From 530731736b4b2f04c18fcd3102f8b352d3c9ec8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Jerman?= Date: Thu, 29 Aug 2019 17:47:32 +0200 Subject: [PATCH] Add tests --- compose/decoder/decoder_test.go | 179 ++++++++++++++++++ compose/decoder/record.go | 6 +- compose/decoder/record_test.go | 135 +++++++++++++ compose/internal/service/import_session.go | 2 +- .../internal/service/import_session_test.go | 111 +++++++++++ 5 files changed, 431 insertions(+), 2 deletions(-) create mode 100644 compose/decoder/decoder_test.go create mode 100644 compose/decoder/record_test.go create mode 100644 compose/internal/service/import_session_test.go diff --git a/compose/decoder/decoder_test.go b/compose/decoder/decoder_test.go new file mode 100644 index 000000000..b9da09e46 --- /dev/null +++ b/compose/decoder/decoder_test.go @@ -0,0 +1,179 @@ +package decoder + +import ( + "bytes" + "encoding/csv" + "encoding/json" + "errors" + "fmt" + "io" + "testing" + + "github.com/cortezaproject/corteza-server/internal/test" +) + +func makeReadSeeker(c string) io.ReadSeeker { + bb := []byte(c) + return bytes.NewReader(bb) +} + +const ( + testCSV string = "f1,f2,ID\nr1v1,r1v2,1\n" + testJSONL string = "{ \"f1\": \"nr1v1\", \"f2\": \"r1v2\", \"ID\": \"1\" }\n" +) + +func TestEntryCount(t *testing.T) { + t.Run("Flat reader", func(t *testing.T) { + rs := makeReadSeeker(testCSV) + fr := NewFlatReader(csv.NewReader(rs), rs) + + c, err := fr.EntryCount() + test.Assert(t, + c == 1, + fmt.Sprintf("Invalid number of entries determines; found %d, expected %d", c, 1), + ) + + test.Assert(t, + err == nil, + "Returned with error", + ) + }) + + t.Run("Structured decoder", func(t *testing.T) { + rs := makeReadSeeker(testJSONL) + sd := NewStructuredDecoder(json.NewDecoder(rs), rs) + + c, err := sd.EntryCount() + test.Assert(t, + c == 1, + fmt.Sprintf("Invalid number of entries determines; found %d, expected %d", c, 1), + ) + + test.Assert(t, + err == nil, + "Returned with error", + ) + }) +} + +func TestGet(t *testing.T) { + t.Run("Flat reader", func(t *testing.T) { + rs := makeReadSeeker(testCSV) + fr := NewFlatReader(csv.NewReader(rs), rs) + + // dump first line + fr.get(func(f []string) error { return nil }) + err := fr.get(func(f []string) error { + return errors.New("called") + }) + test.Assert(t, + err != nil, + "Error should be returned to indicate that get did read", + ) + + err = fr.get(func(f []string) error { + return errors.New("called") + }) + test.Assert(t, + err == nil, + "Error should NOT be returned to indicate that get didn't read", + ) + }) + + t.Run("Structured decoder", func(t *testing.T) { + rs := makeReadSeeker(testJSONL) + sd := NewStructuredDecoder(json.NewDecoder(rs), rs) + + err := sd.get(func(f map[string]interface{}) error { + return errors.New("called") + }) + test.Assert(t, + err != nil, + "Error should be returned to indicate that get did read", + ) + + err = sd.get(func(f map[string]interface{}) error { + return errors.New("called") + }) + test.Assert(t, + err == nil, + "Error should NOT be returned to indicate that get didn't read", + ) + }) +} + +func TestWalk(t *testing.T) { + t.Run("Flat reader", func(t *testing.T) { + rs := makeReadSeeker(testCSV) + fr := NewFlatReader(csv.NewReader(rs), rs) + + i := 0 + err := fr.walk(func(f []string) error { + i++ + return nil + }) + + test.Assert(t, + i == 2, + "Invalid number of reads", + ) + + test.Assert(t, + err == nil, + "Returned with error", + ) + }) + + t.Run("Structured decoder", func(t *testing.T) { + rs := makeReadSeeker(testJSONL) + sd := NewStructuredDecoder(json.NewDecoder(rs), rs) + + i := 0 + err := sd.walk(func(f map[string]interface{}) error { + i++ + return nil + }) + + test.Assert(t, + i == 1, + "Invalid number of reads", + ) + + test.Assert(t, + err == nil, + "Returned with error", + ) + }) +} + +func TestHeader(t *testing.T) { + t.Run("Flat reader", func(t *testing.T) { + rs := makeReadSeeker(testCSV) + fr := NewFlatReader(csv.NewReader(rs), rs) + + h := fr.Header() + test.Assert(t, + len(h) == 3, + "Invalid number of header fields", + ) + + expect := [...]string{"f1", "f2", "ID"} + for i, h := range h { + test.Assert(t, + h == expect[i], + "Invalid header value", + ) + } + }) + + t.Run("Structured decoder", func(t *testing.T) { + rs := makeReadSeeker(testJSONL) + sd := NewStructuredDecoder(json.NewDecoder(rs), rs) + + h := sd.Header() + test.Assert(t, + len(h) == 3, + "Invalid number of header fields", + ) + }) +} diff --git a/compose/decoder/record.go b/compose/decoder/record.go index 5aa1062b5..6b338eaa2 100644 --- a/compose/decoder/record.go +++ b/compose/decoder/record.go @@ -24,7 +24,11 @@ func fmtTimePtr(tp string) (*time.Time, error) { return &t, nil } -func mapify(header []string, values []string) map[string]string { +func mapify(header, values []string) map[string]string { + if len(header) != len(values) { + return nil + } + rtr := make(map[string]string) for i, v := range values { rtr[header[i]] = v diff --git a/compose/decoder/record_test.go b/compose/decoder/record_test.go new file mode 100644 index 000000000..c1a05f900 --- /dev/null +++ b/compose/decoder/record_test.go @@ -0,0 +1,135 @@ +package decoder + +import ( + "encoding/csv" + "encoding/json" + "fmt" + "strings" + "testing" + + "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/internal/test" +) + +func TestMapify(t *testing.T) { + t.Run("Fail if lengths missmatch", func(t *testing.T) { + var h []string + h = append(h, "h1", "h2") + + var v []string + v = append(v, "v1") + + test.Assert(t, + mapify(h, v) == nil, + "Value should be nil", + ) + + test.Assert(t, + mapify(v, h) == nil, + "Value should be nil", + ) + }) + + t.Run("Successfully mapped", func(t *testing.T) { + var h []string + h = append(h, "h1", "h2") + + var v []string + v = append(v, "v1", "v2") + + mpd := mapify(h, v) + test.Assert(t, + len(mpd) == 2, + fmt.Sprintf("Invalid length %d; should be %d", len(mpd), 2), + ) + + test.Assert(t, + mpd["h1"] == "v1" && mpd["h2"] == "v2", + "Invalid values", + ) + }) +} + +func TestSetSystemField(t *testing.T) { + t.Run("Correctly determine & set", func(t *testing.T) { + r := &types.Record{} + name := "recordID" + value := "123" + is, err := setSystemField(r, name, value) + test.Assert(t, + err == nil, + "Returned with error", + ) + + test.Assert(t, + is, + "Couldn't determine it's a system field", + ) + + test.Assert(t, + r.ID == 123, + fmt.Sprintf("Determined value (%d) not valid; should be %s", r.ID, value), + ) + }) + + t.Run("Correctly determine that it's not", func(t *testing.T) { + r := &types.Record{} + name := "customField" + value := "123" + is, err := setSystemField(r, name, value) + test.Assert(t, + err == nil, + "Returned with error", + ) + + test.Assert(t, + !is, + "Couldn't determine it's not a system field", + ) + }) +} + +func TestRecords(t *testing.T) { + testFields := make(map[string]string) + testFields["f1"] = "f1" + testFields["f2"] = "f2" + testFields["ID"] = "ID" + + t.Run("Flat reader", func(t *testing.T) { + fr := NewFlatReader(csv.NewReader(strings.NewReader(testCSV)), nil) + row := 0 + fr.Records(testFields, func(mod *types.Record) error { + row++ + test.Assert(t, + len(mod.Values) == 2, + "Not enough values", + ) + + test.Assert(t, + mod.ID == uint64(row), + "Not enough values", + ) + + return nil + }) + }) + + t.Run("Structured decoder", func(t *testing.T) { + sd := NewStructuredDecoder(json.NewDecoder(strings.NewReader(testJSONL)), nil) + row := 0 + sd.Records(testFields, func(mod *types.Record) error { + row++ + test.Assert(t, + len(mod.Values) == 2, + "Not enough values", + ) + + test.Assert(t, + mod.ID == uint64(row), + "Not enough values", + ) + + return nil + }) + }) +} diff --git a/compose/internal/service/import_session.go b/compose/internal/service/import_session.go index 7717649b6..a27eef4cd 100644 --- a/compose/internal/service/import_session.go +++ b/compose/internal/service/import_session.go @@ -29,7 +29,7 @@ type ( } ) -func ImportSession() ImportSessionService { +func ImportSession() *importSession { return &importSession{ logger: DefaultLogger.Named("importSession"), records: recordSet{}, diff --git a/compose/internal/service/import_session_test.go b/compose/internal/service/import_session_test.go new file mode 100644 index 000000000..02097e3cc --- /dev/null +++ b/compose/internal/service/import_session_test.go @@ -0,0 +1,111 @@ +package service + +import ( + "context" + "testing" + + "go.uber.org/zap" + + "github.com/cortezaproject/corteza-server/internal/test" +) + +var ctx context.Context = context.WithValue(context.Background(), "testing", true) + +func TestFindRecordByID(t *testing.T) { + DefaultLogger = zap.New(nil, nil) + svc := ImportSession() + ss, _ := svc.SetRecordByID(ctx, 1, 0, 0, nil, nil, nil) + sid := ss.SessionID + + t.Run("Found", func(t *testing.T) { + s, err := svc.FindRecordByID(ctx, sid) + test.Assert(t, + s != nil, + "Session should be found", + ) + + test.Assert(t, + err == nil, + "Returned with error", + ) + }) + + t.Run("Not found", func(t *testing.T) { + s, err := svc.FindRecordByID(ctx, sid+1) + test.Assert(t, + s == nil, + "Session should not be found", + ) + + test.Assert(t, + err != nil, + "Error should not be nil", + ) + }) +} + +func TestSetRecordByID(t *testing.T) { + DefaultLogger = zap.New(nil, nil) + svc := ImportSession() + + t.Run("New", func(t *testing.T) { + ss, err := svc.SetRecordByID(ctx, 1, 0, 0, nil, nil, nil) + test.Assert(t, + len(svc.records) == 1 && ss != nil, + "Session should be created", + ) + + test.Assert(t, + err == nil, + "Returned with error", + ) + }) + + t.Run("Existing", func(t *testing.T) { + svc := ImportSession() + ss, err := svc.SetRecordByID(ctx, 1, 0, 0, nil, nil, nil) + ns, err := svc.SetRecordByID(ctx, ss.SessionID, 0, 0, nil, nil, nil) + test.Assert(t, + len(svc.records) == 1 && ns != nil && ss.SessionID == ns.SessionID, + "Existing session should be edited", + ) + + test.Assert(t, + err == nil, + "Returned with error", + ) + }) +} + +func TestDeleteRecordByID(t *testing.T) { + DefaultLogger = zap.New(nil, nil) + svc := ImportSession() + ss, _ := svc.SetRecordByID(ctx, 1, 0, 0, nil, nil, nil) + + t.Run("Delete existing", func(t *testing.T) { + err := svc.DeleteRecordByID(ctx, ss.SessionID) + test.Assert(t, + len(svc.records) == 0, + "Session should be deleted", + ) + + test.Assert(t, + err == nil, + "Returned with error", + ) + }) + + t.Run("Session not found", func(t *testing.T) { + ss, _ := svc.SetRecordByID(ctx, 1, 0, 0, nil, nil, nil) + err := svc.DeleteRecordByID(ctx, ss.SessionID+1) + test.Assert(t, + len(svc.records) == 1, + "Session should not deleted", + ) + + test.Assert(t, + err == nil, + "Returned with error", + ) + }) +}