Skip to content
This repository was archived by the owner on Nov 7, 2022. It is now read-only.

Commit ac45fd5

Browse files
author
Bogdan Drutu
authored
Add more helper observability test functions, enable oc-trace observability tests. (#462)
* Add more helper observability test functions, enable oc-trace observability tests. * Fix observability_test.go name.
1 parent 68cae62 commit ac45fd5

File tree

3 files changed

+153
-230
lines changed

3 files changed

+153
-230
lines changed

observability/observability_test.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,36 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
// observability_test instead of just observability to avoid dependency cycle between
16+
// observability and observabilitytest
1517
package observability_test
1618

17-
// Will be added in https://github.com/census-instrumentation/opencensus-service/pull/462
19+
// This file contains helpers that are useful to add observability
20+
// with metrics and tracing using OpenCensus to the various pieces
21+
// of the service.
22+
23+
import (
24+
"context"
25+
"testing"
26+
27+
"github.com/census-instrumentation/opencensus-service/observability"
28+
"github.com/census-instrumentation/opencensus-service/observability/observabilitytest"
29+
)
30+
31+
const (
32+
receiverName = "fake_receiver"
33+
exporterName = "fake_exporter"
34+
)
35+
36+
func TestTracePieplineRecordedMetrics(t *testing.T) {
37+
defer observabilitytest.SetupRecordedMetricsTest(t)()
38+
39+
receiverCtx := observability.ContextWithReceiverName(context.Background(), receiverName)
40+
observability.RecordTraceReceiverMetrics(receiverCtx, 17, 13)
41+
exporterCtx := observability.ContextWithExporterName(receiverCtx, exporterName)
42+
observability.RecordTraceExporterMetrics(exporterCtx, 27, 23)
43+
observabilitytest.CheckValueViewReceiverReceivedSpans(t, receiverName, 17)
44+
observabilitytest.CheckValueViewReceiverDroppedSpans(t, receiverName, 13)
45+
observabilitytest.CheckValueViewExporterReceivedSpans(t, receiverName, exporterName, 27)
46+
observabilitytest.CheckValueViewExporterDroppedSpans(t, receiverName, exporterName, 23)
47+
}

observability/observabilitytest/observabilitytest.go

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,29 @@ var _ view.Exporter = (*nopMetricsExporter)(nil)
4141

4242
func (cme *nopMetricsExporter) ExportView(vd *view.Data) {}
4343

44-
// CheckRecordedMetricsForTraceExporter checks that the given TraceExporter records the correct set of metrics with the correct
45-
// set of tags by sending some TraceData to the exporter. The exporter should be able to handle the requests.
46-
func CheckRecordedMetricsForTraceExporter(t *testing.T, te exporter.TraceExporter) {
44+
// SetupRecordedMetricsTest does setup the testing environment to check the metrics recorded by receivers, producers or exporters.
45+
// The returned function should be deferred "defer SetupRecordedMetricsTest(t)()".
46+
func SetupRecordedMetricsTest(t *testing.T) func() {
4747
// Register a nop metrics exporter for the OC library.
4848
nmp := new(nopMetricsExporter)
4949
view.RegisterExporter(nmp)
50-
defer view.UnregisterExporter(nmp)
5150

5251
// Now for the stats exporter
53-
if err := view.Register(observability.ViewExporterReceivedSpans, observability.ViewExporterDroppedSpans); err != nil {
52+
if err := view.Register(observability.AllViews...); err != nil {
5453
t.Fatalf("Failed to register all views: %v", err)
5554
}
56-
defer view.Unregister(observability.ViewExporterReceivedSpans, observability.ViewExporterDroppedSpans)
55+
56+
return func() {
57+
view.UnregisterExporter(nmp)
58+
view.Unregister(observability.AllViews...)
59+
}
60+
}
61+
62+
// CheckRecordedMetricsForTraceExporter checks that the given TraceExporter records the correct set of metrics with the correct
63+
// set of tags by sending few TraceData to the exporter. The exporter should be able to handle the requests correctly without
64+
// dropping.
65+
func CheckRecordedMetricsForTraceExporter(t *testing.T, te exporter.TraceExporter) {
66+
defer SetupRecordedMetricsTest(t)()
5767

5868
now := time.Now().UTC()
5969
spans := []*tracepb.Span{
@@ -98,30 +108,54 @@ func CheckRecordedMetricsForTraceExporter(t *testing.T, te exporter.TraceExporte
98108
}
99109
}
100110

101-
checkValueForExporterView(t, observability.ViewExporterReceivedSpans, te.TraceExportFormat(), int64(numBatches*len(spans)))
102-
checkValueForExporterView(t, observability.ViewExporterDroppedSpans, te.TraceExportFormat(), 0)
111+
CheckValueViewExporterReceivedSpans(t, fakeReceiverName, te.TraceExportFormat(), int64(numBatches*len(spans)))
112+
CheckValueViewExporterDroppedSpans(t, fakeReceiverName, te.TraceExportFormat(), 0)
103113
}
104114

105-
func checkValueForExporterView(t *testing.T, v *view.View, exporterTagName string, value int64) {
106-
rows, err := view.RetrieveData(v.Name)
107-
if err != nil {
108-
t.Fatalf("Error retrieving view data.")
109-
}
115+
// CheckValueViewExporterReceivedSpans checks that for the current exported value in the ViewExporterReceivedSpans
116+
// for {TagKeyReceiver: receiverName, TagKeyExporter: exporterTagName} is equal to "value".
117+
// In tests that this function is called it is required to also call SetupRecordedMetricsTest as first thing.
118+
func CheckValueViewExporterReceivedSpans(t *testing.T, receiverName string, exporterTagName string, value int64) {
119+
checkValueForView(t, observability.ViewExporterReceivedSpans.Name,
120+
wantsTagsForExporterView(receiverName, exporterTagName), value)
121+
}
110122

111-
wantTags := []tag.Tag{
112-
{Key: observability.TagKeyReceiver, Value: fakeReceiverName},
113-
{Key: observability.TagKeyExporter, Value: exporterTagName},
123+
// CheckValueViewExporterDroppedSpans checks that for the current exported value in the ViewExporterDroppedSpans
124+
// for {TagKeyReceiver: receiverName} is equal to "value".
125+
// In tests that this function is called it is required to also call SetupRecordedMetricsTest as first thing.
126+
func CheckValueViewExporterDroppedSpans(t *testing.T, receiverName string, exporterTagName string, value int64) {
127+
checkValueForView(t, observability.ViewExporterDroppedSpans.Name,
128+
wantsTagsForExporterView(receiverName, exporterTagName), value)
129+
}
130+
131+
// CheckValueViewReceiverReceivedSpans checks that for the current exported value in the ViewReceiverReceivedSpans
132+
// for {TagKeyReceiver: receiverName, TagKeyExporter: exporterTagName} is equal to "value".
133+
// In tests that this function is called it is required to also call SetupRecordedMetricsTest as first thing.
134+
func CheckValueViewReceiverReceivedSpans(t *testing.T, receiverName string, value int64) {
135+
checkValueForView(t, observability.ViewReceiverReceivedSpans.Name,
136+
wantsTagsForReceiverView(receiverName), value)
137+
}
138+
139+
// CheckValueViewReceiverDroppedSpans checks that for the current exported value in the ViewReceiverDroppedSpans
140+
// for {TagKeyReceiver: receiverName} is equal to "value".
141+
// In tests that this function is called it is required to also call SetupRecordedMetricsTest as first thing.
142+
func CheckValueViewReceiverDroppedSpans(t *testing.T, receiverName string, value int64) {
143+
checkValueForView(t, observability.ViewReceiverDroppedSpans.Name,
144+
wantsTagsForReceiverView(receiverName), value)
145+
}
146+
147+
func checkValueForView(t *testing.T, vName string, wantTags []tag.Tag, value int64) {
148+
// Make sure the tags slice is sorted by tag keys.
149+
sortTags(wantTags)
150+
151+
rows, err := view.RetrieveData(vName)
152+
if err != nil {
153+
t.Fatalf("Error retrieving view data for view Name %s", vName)
114154
}
115-
// Make sure the vector is sorted by tag keys.
116-
sort.SliceStable(wantTags, func(i, j int) bool {
117-
return wantTags[i].Key.Name() < wantTags[j].Key.Name()
118-
})
119155

120156
for _, row := range rows {
121-
// Make sure the vecotr is sorted by tag keys.
122-
sort.SliceStable(row.Tags, func(i, j int) bool {
123-
return row.Tags[i].Key.Name() < row.Tags[j].Key.Name()
124-
})
157+
// Make sure the tags slice is sorted by tag keys.
158+
sortTags(row.Tags)
125159
if reflect.DeepEqual(wantTags, row.Tags) {
126160
sum := row.Data.(*view.SumData)
127161
if float64(value) != sum.Value {
@@ -133,3 +167,22 @@ func checkValueForExporterView(t *testing.T, v *view.View, exporterTagName strin
133167
}
134168
t.Fatalf("Could not find wantTags: %s in rows %v", wantTags, rows)
135169
}
170+
171+
func wantsTagsForExporterView(receiverName string, exporterTagName string) []tag.Tag {
172+
return []tag.Tag{
173+
{Key: observability.TagKeyReceiver, Value: receiverName},
174+
{Key: observability.TagKeyExporter, Value: exporterTagName},
175+
}
176+
}
177+
178+
func wantsTagsForReceiverView(receiverName string) []tag.Tag {
179+
return []tag.Tag{
180+
{Key: observability.TagKeyReceiver, Value: receiverName},
181+
}
182+
}
183+
184+
func sortTags(tags []tag.Tag) {
185+
sort.SliceStable(tags, func(i, j int) bool {
186+
return tags[i].Key.Name() < tags[j].Key.Name()
187+
})
188+
}

0 commit comments

Comments
 (0)