diff --git a/apis/testing/conditions.go b/apis/testing/conditions.go index 2a90b9cb7..02d1fe8b0 100644 --- a/apis/testing/conditions.go +++ b/apis/testing/conditions.go @@ -17,11 +17,11 @@ package testing import ( "fmt" - "testing" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/apis" duckv1b1 "knative.dev/pkg/apis/duck/v1beta1" + "knative.dev/pkg/test" ) // CheckCondition checks if condition `c` on `cc` has value `cs`. @@ -39,7 +39,7 @@ func CheckCondition(s *duckv1b1.Status, c apis.ConditionType, cs corev1.Conditio // CheckConditionOngoing checks if the condition is in state `Unknown`. // DEPRECATED: Use versioned test helper -func CheckConditionOngoing(s *duckv1b1.Status, c apis.ConditionType, t *testing.T) { +func CheckConditionOngoing(s *duckv1b1.Status, c apis.ConditionType, t test.T) { t.Helper() if err := CheckCondition(s, c, corev1.ConditionUnknown); err != nil { t.Error(err) @@ -48,7 +48,7 @@ func CheckConditionOngoing(s *duckv1b1.Status, c apis.ConditionType, t *testing. // CheckConditionFailed checks if the condition is in state `False`. // DEPRECATED: Use versioned test helper -func CheckConditionFailed(s *duckv1b1.Status, c apis.ConditionType, t *testing.T) { +func CheckConditionFailed(s *duckv1b1.Status, c apis.ConditionType, t test.T) { t.Helper() if err := CheckCondition(s, c, corev1.ConditionFalse); err != nil { t.Error(err) @@ -57,7 +57,7 @@ func CheckConditionFailed(s *duckv1b1.Status, c apis.ConditionType, t *testing.T // CheckConditionSucceeded checks if the condition is in state `True`. // DEPRECATED: Use versioned test helper -func CheckConditionSucceeded(s *duckv1b1.Status, c apis.ConditionType, t *testing.T) { +func CheckConditionSucceeded(s *duckv1b1.Status, c apis.ConditionType, t test.T) { t.Helper() if err := CheckCondition(s, c, corev1.ConditionTrue); err != nil { t.Error(err) diff --git a/apis/testing/v1/conditions.go b/apis/testing/v1/conditions.go index 253d37871..6ace88eb5 100644 --- a/apis/testing/v1/conditions.go +++ b/apis/testing/v1/conditions.go @@ -17,11 +17,11 @@ package v1 import ( "fmt" - "testing" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/test" ) // CheckCondition checks if condition `c` on `cc` has value `cs`. @@ -37,7 +37,7 @@ func CheckCondition(s *duckv1.Status, c apis.ConditionType, cs corev1.ConditionS } // CheckConditionOngoing checks if the condition is in state `Unknown`. -func CheckConditionOngoing(s *duckv1.Status, c apis.ConditionType, t *testing.T) { +func CheckConditionOngoing(s *duckv1.Status, c apis.ConditionType, t test.T) { t.Helper() if err := CheckCondition(s, c, corev1.ConditionUnknown); err != nil { t.Error(err) @@ -45,7 +45,7 @@ func CheckConditionOngoing(s *duckv1.Status, c apis.ConditionType, t *testing.T) } // CheckConditionFailed checks if the condition is in state `False`. -func CheckConditionFailed(s *duckv1.Status, c apis.ConditionType, t *testing.T) { +func CheckConditionFailed(s *duckv1.Status, c apis.ConditionType, t test.T) { t.Helper() if err := CheckCondition(s, c, corev1.ConditionFalse); err != nil { t.Error(err) @@ -53,7 +53,7 @@ func CheckConditionFailed(s *duckv1.Status, c apis.ConditionType, t *testing.T) } // CheckConditionSucceeded checks if the condition is in state `True`. -func CheckConditionSucceeded(s *duckv1.Status, c apis.ConditionType, t *testing.T) { +func CheckConditionSucceeded(s *duckv1.Status, c apis.ConditionType, t test.T) { t.Helper() if err := CheckCondition(s, c, corev1.ConditionTrue); err != nil { t.Error(err) diff --git a/apis/testing/v1beta1/conditions.go b/apis/testing/v1beta1/conditions.go index ada1d8d15..74aa26b2a 100644 --- a/apis/testing/v1beta1/conditions.go +++ b/apis/testing/v1beta1/conditions.go @@ -17,11 +17,11 @@ package testing import ( "fmt" - "testing" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/apis" duckv1b1 "knative.dev/pkg/apis/duck/v1beta1" + "knative.dev/pkg/test" ) // CheckCondition checks if condition `c` on `cc` has value `cs`. @@ -37,7 +37,7 @@ func CheckCondition(s *duckv1b1.Status, c apis.ConditionType, cs corev1.Conditio } // CheckConditionOngoing checks if the condition is in state `Unknown`. -func CheckConditionOngoing(s *duckv1b1.Status, c apis.ConditionType, t *testing.T) { +func CheckConditionOngoing(s *duckv1b1.Status, c apis.ConditionType, t test.T) { t.Helper() if err := CheckCondition(s, c, corev1.ConditionUnknown); err != nil { t.Error(err) @@ -45,7 +45,7 @@ func CheckConditionOngoing(s *duckv1b1.Status, c apis.ConditionType, t *testing. } // CheckConditionFailed checks if the condition is in state `False`. -func CheckConditionFailed(s *duckv1b1.Status, c apis.ConditionType, t *testing.T) { +func CheckConditionFailed(s *duckv1b1.Status, c apis.ConditionType, t test.T) { t.Helper() if err := CheckCondition(s, c, corev1.ConditionFalse); err != nil { t.Error(err) @@ -53,7 +53,7 @@ func CheckConditionFailed(s *duckv1b1.Status, c apis.ConditionType, t *testing.T } // CheckConditionSucceeded checks if the condition is in state `True`. -func CheckConditionSucceeded(s *duckv1b1.Status, c apis.ConditionType, t *testing.T) { +func CheckConditionSucceeded(s *duckv1b1.Status, c apis.ConditionType, t test.T) { t.Helper() if err := CheckCondition(s, c, corev1.ConditionTrue); err != nil { t.Error(err) diff --git a/metrics/metricstest/metricstest.go b/metrics/metricstest/metricstest.go index bc7a92d30..449623435 100644 --- a/metrics/metricstest/metricstest.go +++ b/metrics/metricstest/metricstest.go @@ -16,51 +16,52 @@ limitations under the License. package metricstest import ( - "testing" + "reflect" "go.opencensus.io/stats/view" + "knative.dev/pkg/test" ) // CheckStatsReported checks that there is a view registered with the given name for each string in names, // and that each view has at least one record. -func CheckStatsReported(t *testing.T, names ...string) { +func CheckStatsReported(t test.T, names ...string) { t.Helper() for _, name := range names { d, err := view.RetrieveData(name) if err != nil { - t.Errorf("For metric %s: Reporter.Report() error = %v", name, err) + t.Error("For metric, Reporter.Report() error", "metric", name, "error", err) } if len(d) < 1 { - t.Errorf("For metric %s: No data reported when data was expected, view data is empty.", name) + t.Error("For metric, no data reported when data was expected, view data is empty.", "metric", name) } } } // CheckStatsNotReported checks that there are no records for any views that a name matching a string in names. // Names that do not match registered views are considered not reported. -func CheckStatsNotReported(t *testing.T, names ...string) { +func CheckStatsNotReported(t test.T, names ...string) { t.Helper() for _, name := range names { d, err := view.RetrieveData(name) // err == nil means a valid stat exists matching "name" // len(d) > 0 means a component recorded metrics for that stat if err == nil && len(d) > 0 { - t.Errorf("For metric %s: Unexpected data reported when no data was expected. Reporter len(d) = %d", name, len(d)) + t.Error("For metric, unexpected data reported when no data was expected.", "metric", name, "Reporter len(d)", len(d)) } } } // CheckCountData checks the view with a name matching string name to verify that the CountData stats // reported are tagged with the tags in wantTags and that wantValue matches reported count. -func CheckCountData(t *testing.T, name string, wantTags map[string]string, wantValue int64) { +func CheckCountData(t test.T, name string, wantTags map[string]string, wantValue int64) { t.Helper() if row := checkExactlyOneRow(t, name); row != nil { checkRowTags(t, row, name, wantTags) if s, ok := row.Data.(*view.CountData); !ok { - t.Errorf("%s: got %T, want CountData", name, row.Data) + t.Error("want CountData", "metric", name, "got", reflect.TypeOf(row.Data)) } else if s.Value != wantValue { - t.Errorf("For metric %s: value = %v, want: %d", name, s.Value, wantValue) + t.Error("Wrong value", "metric", name, "value", s.Value, "want", wantValue) } } } @@ -68,22 +69,22 @@ func CheckCountData(t *testing.T, name string, wantTags map[string]string, wantV // CheckDistributionData checks the view with a name matching string name to verify that the DistributionData stats reported // are tagged with the tags in wantTags and that expectedCount number of records were reported. // It also checks that expectedMin and expectedMax match the minimum and maximum reported values, respectively. -func CheckDistributionData(t *testing.T, name string, wantTags map[string]string, expectedCount int64, expectedMin float64, expectedMax float64) { +func CheckDistributionData(t test.T, name string, wantTags map[string]string, expectedCount int64, expectedMin float64, expectedMax float64) { t.Helper() if row := checkExactlyOneRow(t, name); row != nil { checkRowTags(t, row, name, wantTags) if s, ok := row.Data.(*view.DistributionData); !ok { - t.Errorf("%s: got %T, want DistributionData", name, row.Data) + t.Error("want DistributionData", "metric", name, "got", reflect.TypeOf(row.Data)) } else { if s.Count != expectedCount { - t.Errorf("For metric %s: reporter count = %d, want = %d", name, s.Count, expectedCount) + t.Error("reporter count wrong", "metric", name, "got", s.Count, "want", expectedCount) } if s.Min != expectedMin { - t.Errorf("For metric %s: reporter count = %f, want = %f", name, s.Min, expectedMin) + t.Error("reporter count wrong", "metric", name, "got", s.Min, "want", expectedMin) } if s.Max != expectedMax { - t.Errorf("For metric %s: reporter count = %f, want = %f", name, s.Max, expectedMax) + t.Error("reporter count wrong", "metric", name, "got", s.Max, "want", expectedMax) } } } @@ -91,30 +92,30 @@ func CheckDistributionData(t *testing.T, name string, wantTags map[string]string // CheckLastValueData checks the view with a name matching string name to verify that the LastValueData stats // reported are tagged with the tags in wantTags and that wantValue matches reported last value. -func CheckLastValueData(t *testing.T, name string, wantTags map[string]string, wantValue float64) { +func CheckLastValueData(t test.T, name string, wantTags map[string]string, wantValue float64) { t.Helper() if row := checkExactlyOneRow(t, name); row != nil { checkRowTags(t, row, name, wantTags) if s, ok := row.Data.(*view.LastValueData); !ok { - t.Errorf("%s: got %T, want LastValueData", name, row.Data) + t.Error("want LastValueData", "metric", name, "got", reflect.TypeOf(row.Data)) } else if s.Value != wantValue { - t.Errorf("For metric %s: Reporter.Report() expected %v got %v", name, s.Value, wantValue) + t.Error("Reporter.Report() wrong value", "metric", name, "got", s.Value, "want", wantValue) } } } // CheckSumData checks the view with a name matching string name to verify that the SumData stats // reported are tagged with the tags in wantTags and that wantValue matches the reported sum. -func CheckSumData(t *testing.T, name string, wantTags map[string]string, wantValue float64) { +func CheckSumData(t test.T, name string, wantTags map[string]string, wantValue float64) { t.Helper() if row := checkExactlyOneRow(t, name); row != nil { checkRowTags(t, row, name, wantTags) if s, ok := row.Data.(*view.SumData); !ok { - t.Errorf("%s: got %T, want SumData", name, row.Data) + t.Error("Wrong type", "metric", name, "got", reflect.TypeOf(row.Data), "want", "SumData") } else if s.Value != wantValue { - t.Errorf("For metric %s: value = %v, want: %v", name, s.Value, wantValue) + t.Error("Wrong sumdata", "metric", name, "got", s.Value, "want", wantValue) } } } @@ -134,32 +135,32 @@ func Unregister(names ...string) { } } -func checkExactlyOneRow(t *testing.T, name string) *view.Row { +func checkExactlyOneRow(t test.T, name string) *view.Row { t.Helper() d, err := view.RetrieveData(name) if err != nil { - t.Errorf("For metric %s: Reporter.Report() error = %v", name, err) + t.Error("Reporter.Report() error", "metric", name, "error", err) return nil } if len(d) != 1 { - t.Errorf("For metric %s: Reporter.Report() len(d)=%v, want 1", name, len(d)) + t.Error("Reporter.Report() wrong length", "metric", name, "got", len(d), "want", 1) return nil } return d[0] } -func checkRowTags(t *testing.T, row *view.Row, name string, wantTags map[string]string) { +func checkRowTags(t test.T, row *view.Row, name string, wantTags map[string]string) { t.Helper() if wantlen, gotlen := len(wantTags), len(row.Tags); gotlen != wantlen { - t.Errorf("For metric %s: Reporter got %v tags while want %v", name, gotlen, wantlen) + t.Error("Reporter got wrong number of tags", "metric", name, "got", gotlen, "want", wantlen) } for _, got := range row.Tags { n := got.Key.Name() if want, ok := wantTags[n]; !ok { - t.Errorf("For metric %s: Reporter got an extra tag %v: %v", name, n, got.Value) + t.Error("Reporter got an extra tag", "metric", name, "gotName", n, "gotValue", got.Value) } else if got.Value != want { - t.Errorf("For metric %s: Reporter expected a different tag value for key: %s, got: %s, want: %s", name, n, got.Value, want) + t.Error("Reporter expected a different tag value for key", "metric", name, "key", n, "got", got.Value, "want", want) } } } diff --git a/test/helpers/name.go b/test/helpers/name.go index 5014814f6..97f85fb83 100644 --- a/test/helpers/name.go +++ b/test/helpers/name.go @@ -20,9 +20,10 @@ import ( "log" "math/rand" "strings" - "testing" "time" "unicode" + + "knative.dev/pkg/test" ) const ( @@ -42,12 +43,12 @@ func init() { } // ObjectPrefixForTest returns the name prefix for this test's random names. -func ObjectPrefixForTest(t *testing.T) string { +func ObjectPrefixForTest(t test.T) string { return MakeK8sNamePrefix(strings.TrimPrefix(t.Name(), testNamePrefix)) } // ObjectNameForTest generates a random object name based on the test name. -func ObjectNameForTest(t *testing.T) string { +func ObjectNameForTest(t test.T) string { return AppendRandomString(ObjectPrefixForTest(t)) } diff --git a/test/logstream/interface.go b/test/logstream/interface.go index 6aadddc77..7506546ae 100644 --- a/test/logstream/interface.go +++ b/test/logstream/interface.go @@ -18,9 +18,9 @@ package logstream import ( "os" - "testing" "knative.dev/pkg/system" + "knative.dev/pkg/test" ) // Canceler is the type of a function returned when a logstream is started to be @@ -30,12 +30,12 @@ type Canceler func() // Start begins streaming the logs from system components with a `key:` matching // `test.ObjectNameForTest(t)` to `t.Log`. It returns a Canceler, which must // be called before the test completes. -func Start(t *testing.T) Canceler { +func Start(t test.TLegacy) Canceler { return stream.Start(t) } type streamer interface { - Start(t *testing.T) Canceler + Start(t test.TLegacy) Canceler } var stream streamer diff --git a/test/logstream/kubelogs.go b/test/logstream/kubelogs.go index 733e564ea..84e4cf27e 100644 --- a/test/logstream/kubelogs.go +++ b/test/logstream/kubelogs.go @@ -22,7 +22,6 @@ import ( "fmt" "strings" "sync" - "testing" "time" "golang.org/x/sync/errgroup" @@ -50,18 +49,18 @@ var _ streamer = (*kubelogs)(nil) // timeFormat defines a simple timestamp with millisecond granularity const timeFormat = "15:04:05.000" -func (k *kubelogs) init(t *testing.T) { +func (k *kubelogs) init(t test.TLegacy) { k.keys = make(map[string]logger) kc, err := test.NewKubeClient(test.Flags.Kubeconfig, test.Flags.Cluster) if err != nil { - t.Errorf("Error loading client config: %v", err) + t.Error("Error loading client config", "error", err) } // List the pods in the given namespace. pl, err := kc.Kube.CoreV1().Pods(k.namespace).List(metav1.ListOptions{}) if err != nil { - t.Errorf("Error listing pods: %v", err) + t.Error("Error listing pods", "error", err) } eg := errgroup.Group{} @@ -160,7 +159,7 @@ func (k *kubelogs) handleLine(l string) { } // Start implements streamer -func (k *kubelogs) Start(t *testing.T) Canceler { +func (k *kubelogs) Start(t test.TLegacy) Canceler { k.once.Do(func() { k.init(t) }) name := helpers.ObjectPrefixForTest(t) @@ -177,7 +176,7 @@ func (k *kubelogs) Start(t *testing.T) Canceler { delete(k.keys, name) if k.err != nil { - t.Errorf("error during logstream: %v", k.err) + t.Error("error during logstream", "error", k.err) } } } diff --git a/test/logstream/null.go b/test/logstream/null.go index bbc6cfd2c..7a8ad1bc4 100644 --- a/test/logstream/null.go +++ b/test/logstream/null.go @@ -16,15 +16,13 @@ limitations under the License. package logstream -import ( - "testing" -) +import "knative.dev/pkg/test" type null struct{} var _ streamer = (*null)(nil) // Start implements streamer -func (*null) Start(t *testing.T) Canceler { +func (*null) Start(t test.TLegacy) Canceler { return func() {} } diff --git a/test/tinterface.go b/test/tinterface.go new file mode 100644 index 000000000..c4a87dae8 --- /dev/null +++ b/test/tinterface.go @@ -0,0 +1,35 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Defines an interface of commonality between testing.T and logging.TLogger +// Allows most library functions to be shared +// Simplifies coexistance with TLogger + +package test + +type T interface { + Name() string + Helper() + SkipNow() + Log(args ...interface{}) + Error(args ...interface{}) +} + +type TLegacy interface { + T + Logf(fmt string, args ...interface{}) // It gets passed to things in logstream + Fatal(args ...interface{}) +}