From d883d4de538937e0bd09b015523a6e76d13889f3 Mon Sep 17 00:00:00 2001 From: Hoang Pham Date: Wed, 2 Mar 2022 12:46:21 -0600 Subject: [PATCH] FB-1188 - TTL - added more unit tests --- client/orm.go | 2 +- client/orm_test.go | 61 +++++++++++++++++++++++++++++++++-------- field.go | 2 +- http_handler_test.go | 61 +++++++++++++++++++---------------------- internal_client_test.go | 40 +++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 47 deletions(-) diff --git a/client/orm.go b/client/orm.go index 5cd6e682a..5035cc59c 100644 --- a/client/orm.go +++ b/client/orm.go @@ -920,7 +920,7 @@ func OptFieldTypeTime(quantum TimeQuantum, opts ...bool) FieldOption { } } -func OptFieldTtl(dur time.Duration, opts ...bool) FieldOption { +func OptFieldTtl(dur time.Duration) FieldOption { return func(options *FieldOptions) { options.ttl = dur } diff --git a/client/orm_test.go b/client/orm_test.go index 1a37bc18b..29256a23c 100644 --- a/client/orm_test.go +++ b/client/orm_test.go @@ -925,7 +925,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(0, 0), pql.NewDecimal(0, 0), "", - "") + "", + 0) }) t.Run("IntFieldOptions", func(t *testing.T) { @@ -944,7 +945,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(-10, 0), pql.NewDecimal(100, 0), "", - "") + "", + 0) field = sampleIndex.Field("int-field2", OptFieldTypeInt(-10)) jsonString = field.options.String() @@ -962,7 +964,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(-10, 0), pql.NewDecimal(math.MaxInt64, 0), "", - "") + "", + 0) field = sampleIndex.Field("int-field3", OptFieldTypeInt()) jsonString = field.options.String() targetString = fmt.Sprintf(`{"options":{"type":"int","min":%d,"max":%d}}`, math.MinInt64, math.MaxInt64) @@ -978,7 +981,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(math.MinInt64, 0), pql.NewDecimal(math.MaxInt64, 0), "", - "") + "", + 0) field = sampleIndex.Field("int-field4", OptFieldTypeInt(), OptFieldForeignIndex("blerg")) jsonString = field.options.String() @@ -995,7 +999,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(math.MinInt64, 0), pql.NewDecimal(math.MaxInt64, 0), "blerg", - "") + "", + 0) }) t.Run("TimeFieldOptions", func(t *testing.T) { @@ -1017,7 +1022,31 @@ func TestORM(t *testing.T) { pql.NewDecimal(0, 0), pql.NewDecimal(0, 0), "", - "") + "", + 0) + }) + + t.Run("TtlOptions", func(t *testing.T) { + field := sampleIndex.Field("ttl-field", OptFieldTypeTime(TimeQuantumDayHour, true), OptFieldTtl(0)) + if true != field.Opts().NoStandardView() { + t.Fatalf("field noStandardView %v != %v", true, field.Opts().NoStandardView()) + } + jsonString := field.options.String() + targetString := `{"options":{"noStandardView":true,"type":"time","timeQuantum":"DH","ttl":"0s"}}` + if sortedString(targetString) != sortedString(jsonString) { + t.Fatalf("`%s` != `%s`", targetString, jsonString) + } + compareFieldOptions(t, + field.Options(), + FieldTypeTime, + TimeQuantumDayHour, + CacheTypeDefault, + 0, + pql.NewDecimal(0, 0), + pql.NewDecimal(0, 0), + "", + "", + 0) }) t.Run("MutexFieldOptions", func(t *testing.T) { @@ -1036,7 +1065,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(0, 0), pql.NewDecimal(0, 0), "", - "") + "", + 0) }) t.Run("BoolFieldOptions", func(t *testing.T) { @@ -1055,7 +1085,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(0, 0), pql.NewDecimal(0, 0), "", - "") + "", + 0) }) t.Run("DecimalFieldOptions", func(t *testing.T) { @@ -1074,7 +1105,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(7, 3), pql.NewDecimal(999, 3), "", - "") + "", + 0) }) t.Run("DecimalFieldOptions", func(t *testing.T) { @@ -1093,7 +1125,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(7, 3), pql.NewDecimal(999, 3), "", - "") + "", + 0) }) t.Run("TimestampFieldOptions", func(t *testing.T) { @@ -1114,7 +1147,8 @@ func TestORM(t *testing.T) { pql.NewDecimal(MinTimestamp.UnixNano()/TimeUnitNanos(pilosa.TimeUnitSeconds), 0), pql.NewDecimal(MaxTimestamp.UnixNano()/TimeUnitNanos(pilosa.TimeUnitSeconds), 0), "", - pilosa.TimeUnitSeconds) + pilosa.TimeUnitSeconds, + 0) }) @@ -1163,7 +1197,7 @@ func comparePQL(t *testing.T, target string, q PQLQuery) { } } -func compareFieldOptions(t *testing.T, opts *FieldOptions, fieldType FieldType, timeQuantum TimeQuantum, cacheType CacheType, cacheSize int, min pql.Decimal, max pql.Decimal, foreignIndex string, timeUnit string) { +func compareFieldOptions(t *testing.T, opts *FieldOptions, fieldType FieldType, timeQuantum TimeQuantum, cacheType CacheType, cacheSize int, min pql.Decimal, max pql.Decimal, foreignIndex string, timeUnit string, ttl time.Duration) { if fieldType != opts.Type() { t.Fatalf("%s != %s", fieldType, opts.Type()) } @@ -1188,6 +1222,9 @@ func compareFieldOptions(t *testing.T, opts *FieldOptions, fieldType FieldType, if timeUnit != opts.TimeUnit() { t.Fatalf("%s != %s", timeUnit, opts.TimeUnit()) } + if ttl != opts.Ttl() { + t.Fatalf("%s != %s", ttl, opts.Ttl()) + } } func sortedString(s string) string { diff --git a/field.go b/field.go index 33dd6a88c..228f18c8a 100644 --- a/field.go +++ b/field.go @@ -679,7 +679,7 @@ func (f *Field) ForeignIndex() string { return f.options.ForeignIndex } -// Ttl returns the ttl for the field. +// Ttl returns the ttl of the field. func (f *Field) Ttl() time.Duration { return f.options.Ttl } diff --git a/http_handler_test.go b/http_handler_test.go index 35ca4d568..2a213642b 100644 --- a/http_handler_test.go +++ b/http_handler_test.go @@ -6,6 +6,8 @@ import ( "fmt" "net" gohttp "net/http" + "reflect" + "sort" "strings" "testing" @@ -221,7 +223,7 @@ func TestPostFieldWithTtl(t *testing.T) { } } -func TestGetViewHAndDeleteHandler(t *testing.T) { +func TestGetViewAndDelete(t *testing.T) { c := test.MustRunCluster(t, 1) defer c.Close() @@ -258,7 +260,7 @@ func TestGetViewHAndDeleteHandler(t *testing.T) { t.Errorf("posting query, status: %d, body=%s", respQuery.StatusCode, respQuery.Body) } - // The above sample data will create these views: + // The above sample data should create these views: expectedViewNames := []string{ "standard", "standard_2001", @@ -287,54 +289,47 @@ func TestGetViewHAndDeleteHandler(t *testing.T) { } // check if data from view matches with expectedViewNames - allViewsFound := true - for _, expectedViewName := range expectedViewNames { - viewFound := false - for _, view := range parsedViews { - if view.Name == expectedViewName { - viewFound = true - break - } - } - allViewsFound = allViewsFound && viewFound + parseViewNames := []string{} + for _, view := range parsedViews { + parseViewNames = append(parseViewNames, view.Name) } - if !allViewsFound { - t.Errorf("view handler did not return expected data") + sort.Strings(parseViewNames) + + if !reflect.DeepEqual(expectedViewNames, parseViewNames) { + t.Fatalf("expected %v, but got %v", expectedViewNames, parseViewNames) } - // call delete on view standard_20010203 - deleteViewUrl := fmt.Sprintf("%s/index/example/field/test_view/view/standard_20010203", m.URL()) + // call delete on view standard_2001020304 + deleteViewUrl := fmt.Sprintf("%s/index/example/field/test_view/view/standard_2001020304", m.URL()) respDelete := test.Do(t, "DELETE", deleteViewUrl, "") if respDelete.StatusCode != gohttp.StatusOK { - t.Errorf("view handler, status: %d, body=%s", respDelete.StatusCode, respDelete.Body) + t.Errorf("delete handler, status: %d, body=%s", respDelete.StatusCode, respDelete.Body) } - // remove view that was deleted (standard_20010203) from expectedViewNames + // remove view that was deleted (standard_2001020304) from expectedViewNames expectedViewNames = expectedViewNames[:len(expectedViewNames)-1] // call view again viewUrl = fmt.Sprintf("%s/index/example/field/test_view/view", m.URL()) respView = test.Do(t, "GET", viewUrl, "") if respView.StatusCode != gohttp.StatusOK { - t.Errorf("view handler, status: %d, body=%s", respView.StatusCode, respView.Body) + t.Errorf("view handler after delete, status: %d, body=%s", respView.StatusCode, respView.Body) } - // check if expected data matches with data returned from view - allViewsFound = true - for _, expectedViewName := range expectedViewNames { - viewFound := false - for _, view := range parsedViews { - if view.Name == expectedViewName { - viewFound = true - break - } - } - allViewsFound = allViewsFound && viewFound - } - if !allViewsFound { - t.Errorf("after delete, view handler did not return expected data") + if err := json.Unmarshal([]byte(respView.Body), &parsedViews); err != nil { + t.Errorf("parsing view, err: %s", err) } + // check if data from view matches with expectedViewNames + parseViewNames = []string{} + for _, view := range parsedViews { + parseViewNames = append(parseViewNames, view.Name) + } + sort.Strings(parseViewNames) + + if !reflect.DeepEqual(expectedViewNames, parseViewNames) { + t.Fatalf("after delete, expected %v, but got %v", expectedViewNames, parseViewNames) + } } func TestTranslationHandlers(t *testing.T) { diff --git a/internal_client_test.go b/internal_client_test.go index 8d1531137..204a85cae 100644 --- a/internal_client_test.go +++ b/internal_client_test.go @@ -1175,6 +1175,46 @@ func TestClient_FragmentBlocks(t *testing.T) { } } +func TestClient_CreateTimeField(t *testing.T) { + cluster := test.MustRunCluster(t, 1) + defer cluster.Close() + cmd := cluster.GetNode(0) + + c := MustNewClient(cmd.URL(), pilosa.GetHTTPClient(nil)) + + index := "cdf" + err := c.CreateIndex(context.Background(), index, pilosa.IndexOptions{}) + if err != nil { + t.Fatalf("creating index: %v", err) + } + + field := "field" + err = c.CreateFieldWithOptions(context.Background(), index, field, pilosa.FieldOptions{Type: pilosa.FieldTypeTime, TimeQuantum: "YMDH"}) + if err != nil { + t.Fatalf("creating field: %v", err) + } + fld, err := cmd.API.Field(context.Background(), index, field) + if err != nil { + t.Fatalf("getting field: %v", err) + } + if fld.Ttl() != 0 { + t.Fatalf("expected Ttl to be 0, got: %+v", fld.Options().Ttl.String()) + } + + fieldTtl := "field_ttl" + err = c.CreateFieldWithOptions(context.Background(), index, fieldTtl, pilosa.FieldOptions{Type: pilosa.FieldTypeTime, TimeQuantum: "YMDH", Ttl: time.Hour}) + if err != nil { + t.Fatalf("creating field: %v", err) + } + fldTtl, err := cmd.API.Field(context.Background(), index, fieldTtl) + if err != nil { + t.Fatalf("getting field: %v", err) + } + if fldTtl.Ttl() != time.Hour { + t.Fatalf("expected Ttl 1 hour, got: %+v", fldTtl.Ttl().String()) + } +} + func TestClient_CreateDecimalField(t *testing.T) { cluster := test.MustRunCluster(t, 1) defer cluster.Close()