refactor: add cache tests and remove cache merge task (#14)

This commit is contained in:
l3uddz
2021-02-19 19:15:38 +00:00
committed by GitHub
parent 54cfd68810
commit e1945cf714
18 changed files with 537 additions and 61 deletions

48
cache/cache.go vendored
View File

@@ -1,19 +1,15 @@
package cache
import (
"context"
"fmt"
"github.com/l3uddz/nabarr/logger"
"github.com/lefelys/state"
"github.com/rs/zerolog"
"github.com/xujiajun/nutsdb"
"time"
)
type Client struct {
log zerolog.Logger
st state.State
db *nutsdb.DB
}
@@ -33,54 +29,14 @@ func New(path string) (*Client, error) {
log := logger.New("trace").With().Logger()
// start cleaner
st, tail := state.WithShutdown()
ticker := time.NewTicker(24 * time.Hour)
go func() {
for {
select {
case <-tail.End():
ticker.Stop()
tail.Done()
return
case <-ticker.C:
// clean cache
err := db.Update(func(tx *nutsdb.Tx) error {
return db.Merge()
})
switch {
case err == nil:
log.Info().Msg("Cleaned cache")
case err.Error() == "the number of files waiting to be merged is at least 2":
// there were no data files to be merged
default:
// unexpected error
log.Error().
Err(err).
Msg("Failed cleaning cache")
}
}
}
}()
return &Client{
log: log,
st: st,
db: db,
db: db,
}, nil
}
func (c *Client) Close() error {
// shutdown cleaner
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
if err := c.st.Shutdown(ctx); err != nil {
c.log.Error().
Err(err).
Msg("Failed shutting down cache cleaner gracefully")
}
// close cache
return c.db.Close()
}

45
cache/delete_test.go vendored Normal file
View File

@@ -0,0 +1,45 @@
package cache
import (
"github.com/rs/zerolog"
"testing"
)
func TestClient_Delete(t *testing.T) {
type fields struct {
log zerolog.Logger
}
type args struct {
bucket string
key string
}
tests := []struct {
name string
fields fields
args args
wantErr bool
}{
{
name: "key not present",
fields: fields{
log: zerolog.Logger{},
},
args: args{
bucket: "delete",
key: "test",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Client{
log: tt.fields.log,
db: newDb(t, "delete"),
}
if err := c.Delete(tt.args.bucket, tt.args.key); (err != nil) != tt.wantErr {
t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

98
cache/get_test.go vendored Normal file
View File

@@ -0,0 +1,98 @@
package cache
import (
"github.com/rs/zerolog"
"reflect"
"testing"
"time"
)
func TestClient_Get(t *testing.T) {
type fields struct {
log zerolog.Logger
}
type args struct {
bucket string
key string
}
tests := []struct {
name string
fields fields
args args
sleep time.Duration
put bool
ttl time.Duration
want []byte
wantErr bool
}{
{
name: "no value",
fields: fields{
log: zerolog.Logger{},
},
args: args{
bucket: "get",
key: "test",
},
want: nil,
wantErr: true,
},
{
name: "with value",
fields: fields{
log: zerolog.Logger{},
},
args: args{
bucket: "get",
key: "test",
},
sleep: 1 * time.Second,
put: true,
ttl: 2 * time.Second,
want: []byte("test"),
wantErr: false,
},
{
name: "no value post ttl",
fields: fields{
log: zerolog.Logger{},
},
args: args{
bucket: "get",
key: "test",
},
sleep: 1 * time.Second,
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Client{
log: tt.fields.log,
db: newDb(t, "get"),
}
if tt.put {
if err := c.Put(tt.args.bucket, tt.args.key, tt.want, tt.ttl); (err != nil) != tt.wantErr && tt.sleep == 0 {
t.Errorf("Put() error = %v, wantErr %v", err, tt.wantErr)
}
}
time.Sleep(tt.sleep)
got, err := c.Get(tt.args.bucket, tt.args.key)
if (err != nil) != tt.wantErr {
t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Get() got = %v, want %v", got, tt.want)
}
if err := c.Close(); err != nil {
t.Errorf("Close() error = %v, wantErr %v", err, nil)
}
})
}
}

98
cache/put_test.go vendored Normal file
View File

@@ -0,0 +1,98 @@
package cache
import (
"github.com/rs/zerolog"
"reflect"
"testing"
"time"
)
func TestClient_Put(t *testing.T) {
type fields struct {
log zerolog.Logger
}
type args struct {
bucket string
key string
val []byte
ttl time.Duration
}
tests := []struct {
name string
fields fields
args args
sleep time.Duration
want []byte
wantErr bool
}{
{
name: "with ttl",
fields: fields{
log: zerolog.Logger{},
},
args: args{
bucket: "put",
key: "test",
val: []byte("testing"),
ttl: 50 * time.Millisecond,
},
want: []byte("testing"),
wantErr: false,
},
{
name: "ttl timed out",
fields: fields{
log: zerolog.Logger{},
},
args: args{
bucket: "put",
key: "test",
val: []byte("testing"),
ttl: 1 * time.Second,
},
sleep: 2 * time.Second,
want: nil,
wantErr: true,
},
{
name: "no ttl",
fields: fields{
log: zerolog.Logger{},
},
args: args{
bucket: "put",
key: "test",
val: []byte("testing"),
ttl: 0,
},
want: []byte("testing"),
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Client{
log: tt.fields.log,
db: newDb(t, "nabarr_put"),
}
if err := c.Put(tt.args.bucket, tt.args.key, tt.args.val, tt.args.ttl); (err != nil) != tt.wantErr && tt.sleep == 0 {
t.Errorf("Put() error = %v, wantErr %v", err, tt.wantErr)
}
time.Sleep(tt.sleep)
got, err := c.Get(tt.args.bucket, tt.args.key)
if (err != nil) != tt.wantErr {
t.Errorf("Put() get error = %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Put() got = %v, want %v", got, tt.want)
}
if err := c.Close(); err != nil {
t.Errorf("Close() error = %v, wantErr %v", err, nil)
}
})
}
}

24
cache/test.go vendored Normal file
View File

@@ -0,0 +1,24 @@
package cache
import (
"github.com/xujiajun/nutsdb"
"os"
"path/filepath"
"testing"
)
func newDb(t *testing.T, dir string) *nutsdb.DB {
db, err := nutsdb.Open(nutsdb.Options{
Dir: filepath.Join(os.TempDir(), dir),
EntryIdxMode: nutsdb.HintKeyValAndRAMIdxMode,
SegmentSize: 8 * 1024 * 1024,
NodeNum: 1,
RWMode: nutsdb.FileIO,
SyncEnable: true,
StartFileLoadingMode: nutsdb.MMap,
})
if err != nil {
t.Fatalf("newDb(dir: %v) open error: %v", dir, err)
}
return db
}