github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/store/test/store_test.go (about)

     1  // Licensed under the Apache License, Version 2.0 (the "License");
     2  // you may not use this file except in compliance with the License.
     3  // You may obtain a copy of the License at
     4  //
     5  //     https://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS,
     9  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  // See the License for the specific language governing permissions and
    11  // limitations under the License.
    12  //
    13  // Original source: github.com/micro/go-micro/v3/store/test/store_test.go
    14  
    15  // Package test provides a way to run tests against all the various implementations of the Store interface.
    16  // It can't live in the store package itself because of circular import issues
    17  package test
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"strings"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/davecgh/go-spew/spew"
    28  	"github.com/kr/pretty"
    29  	"github.com/tickoalcantara12/micro/v3/service/store"
    30  	"github.com/tickoalcantara12/micro/v3/service/store/cache"
    31  	"github.com/tickoalcantara12/micro/v3/service/store/file"
    32  	"github.com/tickoalcantara12/micro/v3/service/store/memory"
    33  )
    34  
    35  func fileStoreCleanup(db string, s store.Store) {
    36  	s.Close()
    37  	dir := filepath.Join(file.DefaultDir, db+"/")
    38  	os.RemoveAll(dir)
    39  }
    40  
    41  func cockroachStoreCleanup(db string, s store.Store) {
    42  	keys, _ := s.List()
    43  	for _, k := range keys {
    44  		s.Delete(k)
    45  	}
    46  	s.Close()
    47  }
    48  
    49  func memoryCleanup(db string, s store.Store) {
    50  	s.Close()
    51  }
    52  
    53  func cacheCleanup(db string, s store.Store) {
    54  	s.Close()
    55  }
    56  
    57  func TestStoreReInit(t *testing.T) {
    58  	tcs := []struct {
    59  		name    string
    60  		s       store.Store
    61  		cleanup func(db string, s store.Store)
    62  	}{
    63  		{name: "file", s: file.NewStore(store.Table("aaa")), cleanup: fileStoreCleanup},
    64  		{name: "memory", s: memory.NewStore(store.Table("aaa")), cleanup: memoryCleanup},
    65  		{name: "cache", s: cache.NewStore(memory.NewStore(store.Table("aaa"))), cleanup: cacheCleanup},
    66  	}
    67  	for _, tc := range tcs {
    68  		t.Run(tc.name, func(t *testing.T) {
    69  			defer tc.cleanup(file.DefaultDatabase, tc.s)
    70  			tc.s.Init(store.Table("bbb"))
    71  			if tc.s.Options().Table != "bbb" {
    72  				t.Error("Init didn't reinitialise the store")
    73  			}
    74  		})
    75  	}
    76  }
    77  
    78  func TestStoreBasic(t *testing.T) {
    79  	tcs := []struct {
    80  		name    string
    81  		s       store.Store
    82  		cleanup func(db string, s store.Store)
    83  	}{
    84  		{name: "file", s: file.NewStore(), cleanup: fileStoreCleanup},
    85  		{name: "memory", s: memory.NewStore(), cleanup: memoryCleanup},
    86  		{name: "cache", s: cache.NewStore(memory.NewStore()), cleanup: cacheCleanup},
    87  	}
    88  	for _, tc := range tcs {
    89  		t.Run(tc.name, func(t *testing.T) {
    90  			defer tc.cleanup(file.DefaultDatabase, tc.s)
    91  			runStoreTest(tc.s, t)
    92  		})
    93  	}
    94  
    95  }
    96  
    97  func TestStoreTable(t *testing.T) {
    98  	tcs := []struct {
    99  		name    string
   100  		s       store.Store
   101  		cleanup func(db string, s store.Store)
   102  	}{
   103  		{name: "file", s: file.NewStore(store.Table("testTable")), cleanup: fileStoreCleanup},
   104  		{name: "memory", s: memory.NewStore(store.Table("testTable")), cleanup: memoryCleanup},
   105  		{name: "cache", s: cache.NewStore(memory.NewStore(store.Table("testTable"))), cleanup: cacheCleanup},
   106  	}
   107  	for _, tc := range tcs {
   108  		t.Run(tc.name, func(t *testing.T) {
   109  			defer tc.cleanup(file.DefaultDatabase, tc.s)
   110  			runStoreTest(tc.s, t)
   111  		})
   112  	}
   113  }
   114  
   115  func TestStoreDatabase(t *testing.T) {
   116  	tcs := []struct {
   117  		name    string
   118  		s       store.Store
   119  		cleanup func(db string, s store.Store)
   120  	}{
   121  		{name: "file", s: file.NewStore(store.Database("testdb")), cleanup: fileStoreCleanup},
   122  		{name: "memory", s: memory.NewStore(store.Database("testdb")), cleanup: memoryCleanup},
   123  		{name: "cache", s: cache.NewStore(memory.NewStore(store.Database("testdb"))), cleanup: cacheCleanup},
   124  	}
   125  	for _, tc := range tcs {
   126  		t.Run(tc.name, func(t *testing.T) {
   127  			defer tc.cleanup("testdb", tc.s)
   128  			runStoreTest(tc.s, t)
   129  		})
   130  	}
   131  }
   132  
   133  func TestStoreDatabaseTable(t *testing.T) {
   134  	tcs := []struct {
   135  		name    string
   136  		s       store.Store
   137  		cleanup func(db string, s store.Store)
   138  	}{
   139  		{name: "file", s: file.NewStore(store.Database("testdb"), store.Table("testTable")), cleanup: fileStoreCleanup},
   140  		{name: "memory", s: memory.NewStore(store.Database("testdb"), store.Table("testTable")), cleanup: memoryCleanup},
   141  		{name: "cache", s: cache.NewStore(memory.NewStore(store.Database("testdb"), store.Table("testTable"))), cleanup: cacheCleanup},
   142  	}
   143  	for _, tc := range tcs {
   144  		t.Run(tc.name, func(t *testing.T) {
   145  			defer tc.cleanup("testdb", tc.s)
   146  			runStoreTest(tc.s, t)
   147  		})
   148  	}
   149  }
   150  
   151  func runStoreTest(s store.Store, t *testing.T) {
   152  	if len(os.Getenv("IN_TRAVIS_CI")) == 0 {
   153  		t.Logf("Options %s %v\n", s.String(), s.Options())
   154  	}
   155  
   156  	expiryTests(s, t)
   157  	suffixPrefixExpiryTests(s, t)
   158  	readTests(s, t)
   159  	listTests(s, t)
   160  
   161  }
   162  
   163  func readTests(s store.Store, t *testing.T) {
   164  	// Test Table, Suffix and WriteOptions
   165  	if err := s.Write(&store.Record{
   166  		Key:    "foofoobarbar",
   167  		Value:  []byte("something"),
   168  		Expiry: time.Millisecond * 100,
   169  	}); err != nil {
   170  		t.Error(err)
   171  	}
   172  	if err := s.Write(&store.Record{
   173  		Key:    "foofoo",
   174  		Value:  []byte("something"),
   175  		Expiry: time.Millisecond * 100,
   176  	}); err != nil {
   177  		t.Error(err)
   178  	}
   179  	if err := s.Write(&store.Record{
   180  		Key:    "barbar",
   181  		Value:  []byte("something"),
   182  		Expiry: time.Millisecond * 100,
   183  	}); err != nil {
   184  		t.Error(err)
   185  	}
   186  
   187  	if results, err := s.Read("foo", store.ReadPrefix(), store.ReadSuffix()); err != nil {
   188  		t.Error(err)
   189  	} else {
   190  		if len(results) != 1 {
   191  			t.Errorf("Expected 1 results, got %d: %# v", len(results), spew.Sdump(results))
   192  		}
   193  	}
   194  
   195  	time.Sleep(time.Millisecond * 100)
   196  
   197  	if results, err := s.List(); err != nil {
   198  		t.Fatalf("List failed: %s", err)
   199  	} else {
   200  		if len(results) != 0 {
   201  			t.Fatalf("Expiry options were not effective, results :%v", spew.Sdump(results))
   202  		}
   203  	}
   204  
   205  	// write the following records
   206  	for i := 0; i < 10; i++ {
   207  		s.Write(&store.Record{
   208  			Key:   fmt.Sprintf("a%d", i),
   209  			Value: []byte{},
   210  		})
   211  	}
   212  
   213  	// read back a few records
   214  	if results, err := s.Read("a", store.ReadLimit(5), store.ReadPrefix()); err != nil {
   215  		t.Error(err)
   216  	} else {
   217  		if len(results) != 5 {
   218  			t.Fatal("Expected 5 results, got ", len(results))
   219  		}
   220  		if !strings.HasPrefix(results[0].Key, "a") {
   221  			t.Fatalf("Expected a prefix, got %s", results[0].Key)
   222  		}
   223  	}
   224  
   225  	// read the rest back
   226  	if results, err := s.Read("a", store.ReadLimit(30), store.ReadOffset(5), store.ReadPrefix()); err != nil {
   227  		t.Fatal(err)
   228  	} else {
   229  		if len(results) != 5 {
   230  			t.Fatal("Expected 5 results, got ", len(results))
   231  		}
   232  	}
   233  }
   234  
   235  func listTests(s store.Store, t *testing.T) {
   236  	for i := 0; i < 10; i++ {
   237  		s.Write(&store.Record{Key: fmt.Sprintf("List%d", i), Value: []byte("bar")})
   238  	}
   239  
   240  	recs, err := s.List(store.ListPrefix("List"))
   241  	if err != nil {
   242  		t.Fatalf("Error listing records %s", err)
   243  	}
   244  	if len(recs) != 10 {
   245  		t.Fatalf("Expected 10 records, received %d", len(recs))
   246  	}
   247  
   248  	recs, err = s.List(store.ListPrefix("List"), store.ListLimit(5))
   249  	if err != nil {
   250  		t.Fatalf("Error listing records %s", err)
   251  	}
   252  	if len(recs) != 5 {
   253  		t.Fatalf("Expected 5 records, received %d", len(recs))
   254  	}
   255  
   256  	recs, err = s.List(store.ListPrefix("List"), store.ListOffset(6))
   257  	if err != nil {
   258  		t.Fatalf("Error listing records %s", err)
   259  	}
   260  	if len(recs) != 4 {
   261  		t.Fatalf("Expected 4 records, received %d %+v", len(recs), recs)
   262  	}
   263  
   264  	recs, err = s.List(store.ListPrefix("List"), store.ListOffset(6), store.ListLimit(2))
   265  	if err != nil {
   266  		t.Fatalf("Error listing records %s", err)
   267  	}
   268  	if len(recs) != 2 {
   269  		t.Fatalf("Expected 2 records, received %d %+v", len(recs), recs)
   270  	}
   271  
   272  	for i := 0; i < 10; i++ {
   273  		s.Write(&store.Record{Key: fmt.Sprintf("ListOffset%d", i), Value: []byte("bar")})
   274  	}
   275  
   276  	recs, err = s.List(store.ListPrefix("ListOffset"), store.ListOffset(6))
   277  	if err != nil {
   278  		t.Fatalf("Error listing records %s", err)
   279  	}
   280  	if len(recs) != 4 {
   281  		t.Fatalf("Expected 4 records, received %d %+v", len(recs), recs)
   282  	}
   283  
   284  }
   285  
   286  func expiryTests(s store.Store, t *testing.T) {
   287  	// Read and Write an expiring Record
   288  	if err := s.Write(&store.Record{
   289  		Key:    "Hello",
   290  		Value:  []byte("World"),
   291  		Expiry: time.Millisecond * 150,
   292  	}); err != nil {
   293  		t.Error(err)
   294  	}
   295  
   296  	if r, err := s.Read("Hello"); err != nil {
   297  		t.Fatal(err)
   298  	} else {
   299  		if len(r) != 1 {
   300  			t.Error("Read returned multiple records")
   301  		}
   302  		if r[0].Key != "Hello" {
   303  			t.Errorf("Expected %s, got %s", "Hello", r[0].Key)
   304  		}
   305  		if string(r[0].Value) != "World" {
   306  			t.Errorf("Expected %s, got %s", "World", r[0].Value)
   307  		}
   308  	}
   309  
   310  	// wait for expiry
   311  	time.Sleep(time.Millisecond * 200)
   312  
   313  	if _, err := s.Read("Hello"); err != store.ErrNotFound {
   314  		t.Errorf("Expected %# v, got %# v", store.ErrNotFound, err)
   315  	}
   316  
   317  	// exercise the records expiry
   318  	s.Write(&store.Record{Key: "aaa", Value: []byte("bbb"), Expiry: 1 * time.Second})
   319  	s.Write(&store.Record{Key: "aaaa", Value: []byte("bbb"), Expiry: 1 * time.Second})
   320  	s.Write(&store.Record{Key: "aaaaa", Value: []byte("bbb"), Expiry: 1 * time.Second})
   321  	results, err := s.Read("a", store.ReadPrefix())
   322  	if err != nil {
   323  		t.Error(err)
   324  	}
   325  	if len(results) != 3 {
   326  		t.Fatalf("Results should have returned 3 records, returned %d", len(results))
   327  	}
   328  	time.Sleep(1 * time.Second)
   329  	results, err = s.Read("a", store.ReadPrefix())
   330  	if err != nil {
   331  		t.Error(err)
   332  	}
   333  	if len(results) != 0 {
   334  		t.Fatal("Results should have returned 0 records")
   335  	}
   336  }
   337  
   338  func suffixPrefixExpiryTests(s store.Store, t *testing.T) {
   339  	// Write 3 records with various expiry and get with Prefix
   340  	records := []*store.Record{
   341  		&store.Record{
   342  			Key:   "foo",
   343  			Value: []byte("foofoo"),
   344  		},
   345  		&store.Record{
   346  			Key:    "foobar",
   347  			Value:  []byte("foobarfoobar"),
   348  			Expiry: 1 * time.Second,
   349  		},
   350  	}
   351  
   352  	for _, r := range records {
   353  		if err := s.Write(r); err != nil {
   354  			t.Errorf("Couldn't write k: %s, v: %# v (%s)", r.Key, pretty.Formatter(r.Value), err)
   355  		}
   356  	}
   357  
   358  	if results, err := s.Read("foo", store.ReadPrefix()); err != nil {
   359  		t.Errorf("Couldn't read all \"foo\" keys, got %#v (%s)", spew.Sdump(results), err)
   360  	} else {
   361  		if len(results) != 2 {
   362  			t.Errorf("Expected 2 items, got %d", len(results))
   363  		}
   364  	}
   365  
   366  	// wait for the expiry
   367  	time.Sleep(1 * time.Second)
   368  
   369  	if results, err := s.Read("foo", store.ReadPrefix()); err != nil {
   370  		t.Errorf("Couldn't read all \"foo\" keys, got %# v (%s)", spew.Sdump(results), err)
   371  	} else if len(results) != 1 {
   372  		t.Errorf("Expected 1 item, got %d", len(results))
   373  	}
   374  
   375  	if err := s.Delete("foo"); err != nil {
   376  		t.Errorf("Delete failed (%v)", err)
   377  	}
   378  
   379  	if results, err := s.Read("foo"); err != store.ErrNotFound {
   380  		t.Errorf("Expected read failure read all \"foo\" keys, got %# v (%s)", spew.Sdump(results), err)
   381  	} else {
   382  		if len(results) != 0 {
   383  			t.Errorf("Expected 0 items, got %d (%# v)", len(results), spew.Sdump(results))
   384  		}
   385  	}
   386  
   387  	// Write 3 records with various expiry and get with Suffix
   388  	records = []*store.Record{
   389  		&store.Record{
   390  			Key:   "foo",
   391  			Value: []byte("foofoo"),
   392  		},
   393  		&store.Record{
   394  			Key:   "barfoo",
   395  			Value: []byte("barfoobarfoo"),
   396  
   397  			Expiry: time.Second * 1,
   398  		},
   399  		&store.Record{
   400  			Key:    "bazbarfoo",
   401  			Value:  []byte("bazbarfoobazbarfoo"),
   402  			Expiry: 2 * time.Second,
   403  		},
   404  	}
   405  	for _, r := range records {
   406  		if err := s.Write(r); err != nil {
   407  			t.Errorf("Couldn't write k: %s, v: %# v (%s)", r.Key, pretty.Formatter(r.Value), err)
   408  		}
   409  	}
   410  	if results, err := s.Read("foo", store.ReadSuffix()); err != nil {
   411  		t.Errorf("Couldn't read all \"foo\" keys, got %# v (%s)", spew.Sdump(results), err)
   412  	} else {
   413  		if len(results) != 3 {
   414  			t.Errorf("Expected 3 items, got %d", len(results))
   415  			//t.Logf("Table test: %v\n", spew.Sdump(results))
   416  		}
   417  
   418  	}
   419  	time.Sleep(time.Second * 1)
   420  	if results, err := s.Read("foo", store.ReadSuffix()); err != nil {
   421  		t.Errorf("Couldn't read all \"foo\" keys, got %# v (%s)", spew.Sdump(results), err)
   422  	} else {
   423  		if len(results) != 2 {
   424  			t.Errorf("Expected 2 items, got %d", len(results))
   425  			//t.Logf("Table test: %v\n", spew.Sdump(results))
   426  		}
   427  
   428  	}
   429  	time.Sleep(time.Second * 1)
   430  	if results, err := s.Read("foo", store.ReadSuffix()); err != nil {
   431  		t.Errorf("Couldn't read all \"foo\" keys, got %# v (%s)", spew.Sdump(results), err)
   432  	} else {
   433  		if len(results) != 1 {
   434  			t.Errorf("Expected 1 item, got %d", len(results))
   435  			//	t.Logf("Table test: %# v\n", spew.Sdump(results))
   436  		}
   437  	}
   438  	if err := s.Delete("foo"); err != nil {
   439  		t.Errorf("Delete failed (%v)", err)
   440  	}
   441  	if results, err := s.Read("foo", store.ReadSuffix()); err != nil {
   442  		t.Errorf("Couldn't read all \"foo\" keys, got %# v (%s)", spew.Sdump(results), err)
   443  	} else {
   444  		if len(results) != 0 {
   445  			t.Errorf("Expected 0 items, got %d (%# v)", len(results), spew.Sdump(results))
   446  		}
   447  	}
   448  }