-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
processor/deltatocumulative: telemetry tests #35742
processor/deltatocumulative: telemetry tests #35742
Conversation
684beda
to
2dc5560
Compare
@@ -36,15 +37,15 @@ func New(set component.TelemetrySettings) (Metrics, error) { | |||
type Metrics struct { | |||
metadata.TelemetryBuilder | |||
|
|||
tracked func() int | |||
tracked *func() int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixes a bug discovered during testing where the callback update had no effect, so the metric was always 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure this is correct? tracked func() int
is a function pointer already. tracked *func() int
is a pointer to a pointer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in-fact yes.
Lines 20 to 26 in e57fcf4
m := Metrics{ | |
tracked: &zero, | |
} | |
trackedCb := metadata.WithDeltatocumulativeStreamsTrackedLinearCallback(func() int64 { | |
return int64((*m.tracked)()) | |
}) |
trackedCb
captures m.tracked
by value. if we later re-assign that func()
, this is not reflected here.
by having it capture a pointer instead, we can update the underlying value and the closure correctly sees the new callback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to use separate commits here? One that adds the test, even if it fails, another that fixes a bug.
If the there is a test failing before the fix it would be awesome since it show that it is indeed a bug :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting.... I would have thought that go would have captured m
and dereferenced it. But I guess it makes sense to capture m.tracked
directly
e57fcf4
to
c379bbd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we couldn't use componentTestTelemetry instead? Testing telemetry is something common to all components in the collector, sounds strange that we need to implement our own comparison logic
Lines 45 to 56 in 08a86b4
func (tt *componentTestTelemetry) assertMetrics(t *testing.T, expected []metricdata.Metrics) { | |
var md metricdata.ResourceMetrics | |
require.NoError(t, tt.reader.Collect(context.Background(), &md)) | |
// ensure all required metrics are present | |
for _, want := range expected { | |
got := tt.getMetric(want.Name, md) | |
metricdatatest.AssertEqual(t, want, got, metricdatatest.IgnoreTimestamp()) | |
} | |
// ensure no additional metrics are emitted | |
require.Equal(t, len(expected), tt.len(md)) | |
} |
processor/deltatocumulativeprocessor/internal/testing/sdktest/example_test.go
Show resolved
Hide resolved
diff --git a/processor/deltatocumulativeprocessor/processor_test.go b/processor/deltatocumulativeprocessor/processor_test.go
index 12d4452e62..cfc28dc617 100644
--- a/processor/deltatocumulativeprocessor/processor_test.go
+++ b/processor/deltatocumulativeprocessor/processor_test.go
@@ -14,11 +14,13 @@ import (
"testing"
"github.com/stretchr/testify/require"
+ "go.opentelemetry.io/collector/config/configtelemetry"
"go.opentelemetry.io/collector/confmap/confmaptest"
"go.opentelemetry.io/collector/consumer/consumertest"
"go.opentelemetry.io/collector/pdata/pmetric"
"go.opentelemetry.io/collector/processor"
- "go.opentelemetry.io/collector/processor/processortest"
+ "go.opentelemetry.io/otel/metric"
+ "go.opentelemetry.io/otel/metric/noop"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
"gopkg.in/yaml.v3"
@@ -54,7 +56,7 @@ func TestProcessor(t *testing.T) {
ctx := context.Background()
cfg := config(t, file("config.yaml"))
- proc, sink := setup(t, cfg)
+ proc, sink, tel := setup(t, cfg)
stages, _ := filepath.Glob(file("*.test"))
for _, file := range stages {
@@ -71,6 +73,8 @@ func TestProcessor(t *testing.T) {
t.Fatal(diff)
}
}
+
+ tel.assertMetrics(t, metrics)
})
}
@@ -89,7 +93,7 @@ func config(t *testing.T, file string) *Config {
return cfg
}
-func setup(t *testing.T, cfg *Config) (processor.Metrics, *consumertest.MetricsSink) {
+func setup(t *testing.T, cfg *Config) (processor.Metrics, *consumertest.MetricsSink, componentTestTelemetry) {
t.Helper()
next := &consumertest.MetricsSink{}
@@ -97,15 +101,27 @@ func setup(t *testing.T, cfg *Config) (processor.Metrics, *consumertest.MetricsS
cfg = &Config{MaxStale: 0, MaxStreams: math.MaxInt}
}
+ tel := setupTestTelemetry()
+ set := tel.NewSettings()
+ mp := set.LeveledMeterProvider(configtelemetry.LevelBasic)
+ set.LeveledMeterProvider = func(level configtelemetry.Level) metric.MeterProvider {
+ // detailed level enables otelhttp client instrumentation which we
+ // dont want to test here
+ if level == configtelemetry.LevelDetailed {
+ return noop.MeterProvider{}
+ }
+ return mp
+ }
+
proc, err := NewFactory().CreateMetrics(
context.Background(),
- processortest.NewNopSettings(),
+ set,
cfg,
next,
)
require.NoError(t, err)
- return proc, next
+ return proc, next, tel
} |
@ArthurSens I considered First of all, it requires you to specify all metrics emitted by the reader, which we rarely want. We only want to test the metrics relevant to the specific test case. Second, you need some way to get that For actual comparison, it just calls out to
I can honestly not even spot the difference in the assertMetrics output (without knowing from the sdktest diff below) Taking a closer look, I think I can cut down the amount of work sdktest does by relying more on go-cmp ignorers ... similar to how |
Could we contribute this? I'd rather stick to what everybody is using, and improve things for everybody if we see limitations. I don't see why people would refuse better comparison output :) |
Tests internal telemetry (metadata.TelemetryBuilder) is recorded as expected. Introduces `internal/testing/sdktest` for this. Introduces `-- telemetry --` section to testdata.
bfd99b0
to
d381aa2
Compare
All of the partial diffing we do by manually copying values can be achieved using go-cmp Filters and Transformers. This a lot cleaner and less maintenance
d381aa2
to
97af96b
Compare
due to a bad closure capture, the callback registration never happened
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @RichieSams, I am just summarizing here what @sh0rez and I discussed in Slack:
Although we're writing a lot of code here that concerns our test framework, the PR does test that the telemetry behaves as expected, so let's merge this to unblock other work.
We did agree that we don't appreciate maintaining a full-blown test framework just for us. It's extra work for the maintainers of this component and we don't help the whole collector community evolve what they have.
Task for the future:
- Propose better test output for collector-core's testing framework.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason why this isn't a .yml
or .yaml
file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's technically not a yaml file.
this uses txtar to bundle several yaml files (in, out, telemetry) into one physical file. This is nice because:
- input and output in the same file
- multiple write-requests per testcase as each request is a
.test
file. This allows to test processor state across write requests
the .test
ending is arbitrary but I thought it serves the purpose here
@@ -16,12 +16,13 @@ import ( | |||
) | |||
|
|||
func New(set component.TelemetrySettings) (Metrics, error) { | |||
zero := func() int { return -1 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I the only one who thinks "zero" is a bad name for something that returns -1
? Also because the previous iteration of the code returned zero...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ugh this is an oversight.
I will address this in a later PR
#### Description Tests internal telemetry (metadata.TelemetryBuilder) is recorded as expected. Introduces `internal/testing/sdktest` for this. Introduces `-- telemetry --` section to testdata. <!--Describe what testing was performed and which tests were added.--> #### Testing Existing tests were extended to have a `-- telemetry --` section that specifies expected meter readings in `sdktest.Format` <!--Describe the documentation added.--> #### Documentation not needed <!--Please delete paragraphs that you did not use before submitting.-->
#### Description Tests internal telemetry (metadata.TelemetryBuilder) is recorded as expected. Introduces `internal/testing/sdktest` for this. Introduces `-- telemetry --` section to testdata. <!--Describe what testing was performed and which tests were added.--> #### Testing Existing tests were extended to have a `-- telemetry --` section that specifies expected meter readings in `sdktest.Format` <!--Describe the documentation added.--> #### Documentation not needed <!--Please delete paragraphs that you did not use before submitting.-->
Description
Tests internal telemetry (metadata.TelemetryBuilder) is recorded as
expected.
Introduces
internal/testing/sdktest
for this.Introduces
-- telemetry --
section to testdata.Testing
Existing tests were extended to have a
-- telemetry --
section that specifies expected meter readings insdktest.Format
Documentation
not needed