如何为插件编写测试代码
一旦你按照 how-to-add-a-new-rule.md 添加了新的插桩规则,你需要添加测试来验证你的规则。
添加插件测试用例
将目录更改为 /test
,并为要测试的插件(例如redis)新建一个目录。在 redis
目录中,有一些子目录,每个子目录的名称代表该插件的最低支持版本。如果要为 redis
添加测试,应执行以下操作:
为你的插桩规则添加最低版本的依赖
例如,如果添加一条支持从 <font style="color:rgb(31, 35, 40);">v9.0.5</font>
到最新版本的 <font style="color:rgb(31, 35, 40);">redis</font>
的规则,则应首先验证最低的 <font style="color:rgb(31, 35, 40);">redis</font>
版本,即 <font style="color:rgb(31, 35, 40);">v9.0.5</font>
。您可以创建一个名为 <font style="color:rgb(31, 35, 40);">v9.0.5</font>
的子目录,并添加以下 <font style="color:rgb(31, 35, 40);">go.mod</font>
:
replace github.com/alibaba/opentelemetry-go-auto-instrumentation = > ../../../../opentelemetry-go-auto-instrumentation
replace github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier = > ../../../../opentelemetry-go-auto-instrumentation/test/verifier
// import this dependency to use verifier
github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier v0.0.0-00010101000000-000000000000
github.com/redis/go-redis/v9 v9.0.5
go.opentelemetry.io/otel v1.30.0
go.opentelemetry.io/otel/sdk v1.30.0
编写该插件相关的业务逻辑
然后,你需要编写一些基于 redis
插件的业务逻辑,例如 test_executing_commands.go
在 redis
中执行基本的 get
和 set
操作。你的测试应尽可能涵盖该插件的所有使用场景。
编写验证代码
如果您编写的业务代码与规则相匹配,就会产生一些观测数据(如 span
)。例如,test_executing_commands.go
会产生两个 span
,一个代表 set redis 操作,另一个代表 get redis 操作。你应该使用校验器来验证其正确性:
import "github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier"
verifier.WaitAndAssertTraces(func (stubs []tracetest.SpanStubs) {
verifier.VerifyDbAttributes(stubs[0][0], "set", "", "redis", "", "localhost", "set a b ex 5 ", "set" )
verifier.VerifyDbAttributes(stubs[1][0], "get", "", "redis", "", "localhost", "get a ", "get" )
验证器的 WaitAndAssertTraces
会接受一个回调函数,该函数会提供生成的所有跟踪信息。您应在所有跟踪中验证每个跨度的属性、父上下文和所有其他关键信息。
如果要验证观测数据,也可以像下面的代码一样使用验证器:
verifier.WaitAndAssertMetrics(map[string]func(metricdata.ResourceMetrics ) {
"http.server.request.duration" : func ( mrs metricdata.ResourceMetrics ) {
if len(mrs.ScopeMetrics ) < = 0 {
panic( "No http.server.request.duration metrics received!" )
point := mrs.ScopeMetrics[0].Metrics[0].Data. ( metricdata.Histogram[float64] )
if point.DataPoints[0].Count != 1 {
panic( "http.server.request.duration metrics count is not 1" )
verifier.VerifyHttpServerMetricsAttributes(point.DataPoints[0].Attributes.ToSlice( ), "GET", "/a", "", "http", "1.1", "http", 200)
"http.client.request.duration" : func ( mrs metricdata.ResourceMetrics ) {
if len(mrs.ScopeMetrics ) < = 0 {
panic( "No http.client.request.duration metrics received!" )
point := mrs.ScopeMetrics[0].Metrics[0].Data. ( metricdata.Histogram[float64] )
if point.DataPoints[0].Count != 1 {
panic( "http.client.request.duration metrics count is not 1" )
verifier.VerifyHttpClientMetricsAttributes(point.DataPoints[0].Attributes.ToSlice( ), "GET", "127.0.0.1:"+strconv.Itoa(port), "", "http", "1.1", port, 200)
用户需要使用验证器中的 WaitAndAssertMetrics
方法来验证度量数据的正确性。WaitAndAssertMetrics
接收一个映射,映射的键是指标的名称,值是该指标数据的验证函数。用户可以在回调函数中编写自己的验证逻辑。
注册测试
最后,你应该注册测试。您应该在测试目录下编写一个_tests.go
文件来完成注册:
const redis_dependency_name = "github.com/redis/go-redis/v9"
const redis_module_name = "redis"
TestCases = append ( TestCases, NewGeneralTestCase ( "redis-9.0.5-executing-commands-test" , redis_module_name, "v9.0.5", "v9.5.1", "1.18", "", TestExecutingCommands )
func TestExecutingCommands ( t * testing.T, env ...string ) {
redisC, redisPort := initRedisContainer ()
defer clearRedisContainer ( redisC )
RunGoBuild(t, "go", "build", "test_executing_commands.go" )
env = append ( env, "REDIS_PORT="+redisPort.Port ())
RunApp(t, "test_executing_commands", env... )
在 init 函数中,您需要用 NewGeneralTestCase 封装您的测试用例,它将接收以下参数:
testName, moduleName, minVersion, maxVersion, minGoVersion, maxGoVersion string, testFunc func(t *testing.T, env …string)
testName:测试用例名称。
moduleName:测试目录中的子目录名。
minVersion:插件的最低支持版本。
maxVersion:插件支持的最高版本
minGoVersion:插件支持的最低 Go 版本。
maxGoVersion:插件支持的最高 Go 版本。
testFunc:要执行的测试函数。
您应使用 opentelemetry-go-auto-instrumentation
构建测试用例,使您的测试用例能够生成观测数据。首先,应调用 UseApp
方法将目录更改为测试用例目录,然后调用 RunGoBuild
进行混合编译。最后,使用 RunApp
运行仪器化的测试用例二进制文件,以验证观测数据。
为插件添加muzzle测试用例
muzzle检查的灵感来自 safety-mechanisms.md 。我们不可能对每个版本都进行通用插件测试,因为这会耗费大量时间。因此,opentelemetry-go-auto-instrumentation
会随机挑选一些版本进行混合编译,以验证不同版本之间的 API 兼容性。如果muzzle check发现某些 API 在某个版本中发生了变化,社区就会创建新的规则对其进行调整。
用户可以通过调用 NewMuzzleTestCase
来添加muzzle检查案例,NewMuzzleTestCase
使用的参数与 NewGeneralTestCase
几乎相同。此外,您还需要指定插件的依赖名称和需要进行muzzle检查的类列表。
添加插件最新测试用例
测试通常是针对我们支持的最低版本的库运行的,以确保针对使用旧版本依赖库的用户的基线,但是Agent可能会在新发布的库版本上失败。、我们会针对从远端获取的最新版本库额外运行仪器测试。如果新版本的库无法与Agent一起运行,我们会通过这次构建发现问题,并在下一次发布Agent时加以解决。
用户可以通过调用 NewLatestDepthTestCase
来添加最新测试案例,NewLatestDepthTestCase
使用的参数与 NewGeneralTestCase 几乎相同。您还需要指定插件的依赖名称和需要进行最新深度检查的类列表。