package fstore import ( "net/http" "net/http/httptest" "reflect" "strings" "testing" "time" ) func TestStoreHarness(t *testing.T) { StoreTestHarness{}.Run(t) } type StoreTestHarness struct{} func (h StoreTestHarness) Run(t *testing.T) { val := reflect.ValueOf(h) typ := val.Type() for i := 0; i < typ.NumMethod(); i++ { method := typ.Method(i) if !strings.HasPrefix(method.Name, "Test") { continue } t.Run(method.Name, func(t *testing.T) { t.Parallel() rootDir := t.TempDir() primary, err := Open(Config{ RootDir: rootDir, Primary: true, WALSegMinCount: 1, WALSegMaxAgeSec: 1, WALSegGCAgeSec: 2, }) if err != nil { t.Fatal(err) } defer primary.Close() mux := http.NewServeMux() mux.HandleFunc("/rep/", primary.Handle) testServer := httptest.NewServer(mux) defer testServer.Close() rootDir2 := t.TempDir() secondary, err := Open(Config{ RootDir: rootDir2, Primary: false, PrimaryEndpoint: testServer.URL + "/rep/", }) if err != nil { t.Fatal(err) } defer secondary.Close() val.MethodByName(method.Name).Call([]reflect.Value{ reflect.ValueOf(t), reflect.ValueOf(primary), reflect.ValueOf(secondary), }) }) } } func (StoreTestHarness) TestBasic(t *testing.T, primary, secondary *Store) { stateChan := make(chan map[string]string, 1) go func() { stateChan <- primary.WriteRandomFor(4 * time.Second) }() state := <-stateChan secondary.WaitForParity(primary) primary.AssertState(t, state) secondary.AssertState(t, state) } func (StoreTestHarness) TestWriteThenFollow(t *testing.T, primary, secondary *Store) { secondary.Close() stateChan := make(chan map[string]string, 1) go func() { stateChan <- primary.WriteRandomFor(4 * time.Second) }() state := <-stateChan var err error secondary, err = Open(secondary.conf) if err != nil { t.Fatal(err) } secondary.WaitForParity(primary) primary.AssertState(t, state) secondary.AssertState(t, state) } func (StoreTestHarness) TestCloseAndOpenFollowerConcurrently(t *testing.T, primary, secondary *Store) { secondary.Close() stateChan := make(chan map[string]string, 1) go func() { stateChan <- primary.WriteRandomFor(8 * time.Second) }() var err error for i := 0; i < 4; i++ { time.Sleep(time.Second) secondary, err = Open(secondary.conf) if err != nil { t.Fatal(err) } time.Sleep(time.Second) secondary.Close() } secondary, err = Open(secondary.conf) if err != nil { t.Fatal(err) } state := <-stateChan secondary.WaitForParity(primary) primary.AssertState(t, state) secondary.AssertState(t, state) }