package files_test import ( "bytes" "io" "strings" "testing" "time" "git.t-juice.club/torjus/gpaste/files" "github.com/google/go-cmp/cmp" "github.com/google/uuid" ) func RunFilestoreTest(s files.FileStore, t *testing.T) { t.Run("Basic", func(t *testing.T) { // Create dataString := "TEST_LOL_OMG" id := uuid.Must(uuid.NewRandom()).String() bodyBuf := &bytes.Buffer{} bodyBuf.Write([]byte(dataString)) body := io.NopCloser(bodyBuf) f := &files.File{ ID: id, MaxViews: 99, Body: body, ExpiresOn: time.Now().Add(99 * time.Second), } err := s.Store(f) if err != nil { t.Fatalf("Unable to store file: %s", err) } // Retrieve retrieved, err := s.Get(id) if err != nil { t.Fatalf("Unable to retrieve file: %s", err) } retrievedBuf := &bytes.Buffer{} _, err = retrievedBuf.ReadFrom(retrieved.Body) if err != nil { t.Fatalf("Unable to read retrieved body: %s", err) } _ = retrieved.Body.Close() if err != nil { t.Fatalf("Error reading from retrieved file: %s", err) } if retrievedBuf.String() != dataString { t.Fatalf("Data from retrieved body mismatch. Got %s want %s", retrievedBuf.String(), dataString) } expected := &files.File{ ID: f.ID, MaxViews: f.MaxViews, ExpiresOn: f.ExpiresOn, FileSize: int64(len(dataString)), } ignoreBody := cmp.FilterPath(func(p cmp.Path) bool { return p.String() == "Body" }, cmp.Ignore()) if diff := cmp.Diff(retrieved, expected, ignoreBody); diff != "" { t.Errorf("File comparison failed: %s", diff) } // List ids, err := s.List() if err != nil { t.Fatalf("Error doing list: %s", err) } if len(ids) != 1 { t.Fatalf("List has wrong length: %d", len(ids)) } if ids[0] != id { t.Fatalf("ID is wrong. Got %s want %s", ids[0], id) } // Delete if err := s.Delete(id); err != nil { t.Fatalf("Error deleting file: %s", err) } ids, err = s.List() if err != nil { t.Fatalf("Error listing after delete: %s", err) } if len(ids) != 0 { t.Fatalf("List after delete has wrong length: %d", len(ids)) } }) } func RunPersistentFilestoreTest(newStoreFunc func() files.FileStore, t *testing.T) { s := newStoreFunc() files := []struct { File *files.File ExpectedData string }{ { File: &files.File{ ID: uuid.NewString(), OriginalFilename: "testfile.txt", MaxViews: 5, ExpiresOn: time.Now().Add(10 * time.Minute), Body: io.NopCloser(strings.NewReader("cocks!")), FileSize: 6, }, ExpectedData: "cocks!", }, { File: &files.File{ ID: uuid.NewString(), OriginalFilename: "testfile2.txt", MaxViews: 5, ExpiresOn: time.Now().Add(10 * time.Minute), Body: io.NopCloser(strings.NewReader("derps!")), FileSize: 6, }, ExpectedData: "derps!", }, } for _, f := range files { err := s.Store(f.File) if err != nil { t.Fatalf("Error storing file: %s", err) } } for _, f := range files { retrieved, err := s.Get(f.File.ID) if err != nil { t.Fatalf("Unable to retrieve file: %s", err) } ignoreBody := cmp.FilterPath(func(p cmp.Path) bool { return p.String() == "Body" }, cmp.Ignore()) if !cmp.Equal(retrieved, f.File, ignoreBody) { t.Errorf("Mismatch: %s", cmp.Diff(retrieved, f.File)) } buf := new(strings.Builder) if _, err := io.Copy(buf, retrieved.Body); err != nil { t.Fatalf("Error reading from body: %s", err) } retrieved.Body.Close() if buf.String() != f.ExpectedData { t.Fatalf("Data does not match. %s", cmp.Diff(buf.String(), f.ExpectedData)) } } // Reopen store, and fetch again s = newStoreFunc() for _, f := range files { retrieved, err := s.Get(f.File.ID) if err != nil { t.Fatalf("Unable to retrieve file: %s", err) } ignoreBody := cmp.FilterPath(func(p cmp.Path) bool { return p.String() == "Body" }, cmp.Ignore()) if !cmp.Equal(retrieved, f.File, ignoreBody) { t.Errorf("Mismatch: %s", cmp.Diff(retrieved, f.File)) } buf := new(strings.Builder) if _, err := io.Copy(buf, retrieved.Body); err != nil { t.Fatalf("Error reading from body: %s", err) } retrieved.Body.Close() if buf.String() != f.ExpectedData { t.Fatalf("Data does not match. %s", cmp.Diff(buf.String(), f.ExpectedData)) } } }