From 2b3bfdc40be3d976c39f4150cb83a88afd83d6f4 Mon Sep 17 00:00:00 2001 From: Xe Iaso Date: Thu, 3 Jul 2025 04:44:29 +0000 Subject: [PATCH] test(lib/store): make generic storage interface test adaptor Signed-off-by: Xe Iaso --- lib/store/memory/memory_test.go | 11 +++++ lib/store/storetest/storetest.go | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 lib/store/memory/memory_test.go create mode 100644 lib/store/storetest/storetest.go diff --git a/lib/store/memory/memory_test.go b/lib/store/memory/memory_test.go new file mode 100644 index 00000000..40f7eb73 --- /dev/null +++ b/lib/store/memory/memory_test.go @@ -0,0 +1,11 @@ +package memory + +import ( + "testing" + + "github.com/TecharoHQ/anubis/lib/store/storetest" +) + +func TestImpl(t *testing.T) { + storetest.Common(t, New(t.Context())) +} diff --git a/lib/store/storetest/storetest.go b/lib/store/storetest/storetest.go new file mode 100644 index 00000000..b39e75e5 --- /dev/null +++ b/lib/store/storetest/storetest.go @@ -0,0 +1,82 @@ +package storetest + +import ( + "bytes" + "errors" + "testing" + "time" + + "github.com/TecharoHQ/anubis/lib/store" +) + +func Common(t *testing.T, s store.Interface) { + for _, tt := range []struct { + name string + doer func(t *testing.T, s store.Interface) error + err error + }{ + { + name: "basic get set delete", + doer: func(t *testing.T, s store.Interface) error { + if _, err := s.Get(t.Context(), t.Name()); !errors.Is(err, store.ErrNotFound) { + t.Errorf("wanted %s to not exist in store but it exists anyways", t.Name()) + } + + if err := s.Set(t.Context(), t.Name(), []byte(t.Name()), 5*time.Minute); err != nil { + return err + } + + val, err := s.Get(t.Context(), t.Name()) + if errors.Is(err, store.ErrNotFound) { + t.Errorf("wanted %s to exist in store but it does not", t.Name()) + } + + if !bytes.Equal(val, []byte(t.Name())) { + t.Logf("want: %q", t.Name()) + t.Logf("got: %q", string(val)) + t.Error("wrong value returned") + } + + if err := s.Delete(t.Context(), t.Name()); err != nil { + return err + } + + if _, err := s.Get(t.Context(), t.Name()); !errors.Is(err, store.ErrNotFound) { + t.Error("wanted test to not exist in store but it exists anyways") + } + + if err := s.Delete(t.Context(), t.Name()); err == nil { + t.Errorf("key %q does not exist and Delete did not return non-nil", t.Name()) + } + + return nil + }, + }, + { + name: "expires", + doer: func(t *testing.T, s store.Interface) error { + if err := s.Set(t.Context(), t.Name(), []byte(t.Name()), 150*time.Millisecond); err != nil { + return err + } + + //nosleep:bypass XXX(Xe): use Go's time faking thing in Go 1.25 when that is released. + time.Sleep(155 * time.Millisecond) + + if _, err := s.Get(t.Context(), t.Name()); !errors.Is(err, store.ErrNotFound) { + t.Errorf("wanted %s to not exist in store but it exists anyways", t.Name()) + } + + return nil + }, + }, + } { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + if err := tt.doer(t, s); !errors.Is(err, tt.err) { + t.Logf("want: %v", tt.err) + t.Logf("got: %v", err) + t.Error("wrong error") + } + }) + } +}