From 0d4d1647f55300c50f249616937ecf2ffb112bcd Mon Sep 17 00:00:00 2001 From: Craig Elliott Date: Mon, 18 May 2026 11:48:16 +0100 Subject: [PATCH 1/8] Update existing upgrade tests --- api/grpc/mpi/v1/command_grpc.pb.go | 2 +- api/grpc/mpi/v1/files_grpc.pb.go | 2 +- test/helpers/test_containers_utils.go | 7 +-- .../upgrade/configs/expected-otel-config.yaml | 52 +++++++++++++++++++ test/integration/upgrade/upgrade_test.go | 32 ++++++++---- 5 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 test/integration/upgrade/configs/expected-otel-config.yaml diff --git a/api/grpc/mpi/v1/command_grpc.pb.go b/api/grpc/mpi/v1/command_grpc.pb.go index 2efba7b3c2..fe7c799902 100644 --- a/api/grpc/mpi/v1/command_grpc.pb.go +++ b/api/grpc/mpi/v1/command_grpc.pb.go @@ -8,7 +8,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.6.1 +// - protoc-gen-go-grpc v1.6.2 // - protoc (unknown) // source: mpi/v1/command.proto diff --git a/api/grpc/mpi/v1/files_grpc.pb.go b/api/grpc/mpi/v1/files_grpc.pb.go index fec381a551..d5b8b3b5a7 100644 --- a/api/grpc/mpi/v1/files_grpc.pb.go +++ b/api/grpc/mpi/v1/files_grpc.pb.go @@ -5,7 +5,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.6.1 +// - protoc-gen-go-grpc v1.6.2 // - protoc (unknown) // source: mpi/v1/files.proto diff --git a/test/helpers/test_containers_utils.go b/test/helpers/test_containers_utils.go index 3b9898c9d7..208b365c96 100644 --- a/test/helpers/test_containers_utils.go +++ b/test/helpers/test_containers_utils.go @@ -21,9 +21,10 @@ import ( const configFilePermissions = 0o600 type Parameters struct { - NginxConfigPath string - NginxAgentConfigPath string - LogMessage string + NginxConfigPath string + NginxAgentConfigPath string + NginxAgentOTELConfigPath string + LogMessage string } type MockCollectorContainers struct { diff --git a/test/integration/upgrade/configs/expected-otel-config.yaml b/test/integration/upgrade/configs/expected-otel-config.yaml new file mode 100644 index 0000000000..9a1cb2d661 --- /dev/null +++ b/test/integration/upgrade/configs/expected-otel-config.yaml @@ -0,0 +1,52 @@ +receivers: + containermetrics: + collection_interval: 1m0s + hostmetrics: + collection_interval: 1m0s + initial_delay: 1s + scrapers: + network: + +processors: + batch/default_logs: + send_batch_size: 100 + timeout: 1m0s + send_batch_max_size: 100 + batch/default_metrics: + send_batch_size: 1000 + timeout: 30s + send_batch_max_size: 1000 + securityviolationsfilter/default: {} + +exporters: + otlp_grpc/default: + endpoint: "managementPlane:9092" + timeout: 10s + retry_on_failure: + enabled: true + initial_interval: 10s + max_interval: 60s + max_elapsed_time: 10m + tls: + insecure: true +extensions: + +service: + telemetry: + metrics: + level: none + logs: + level: DEBUG + output_paths: ["/var/log/nginx-agent/opentelemetry-collector-agent.log"] + error_output_paths: ["/var/log/nginx-agent/opentelemetry-collector-agent.log"] + extensions: + + pipelines: + metrics/default: + receivers: + - containermetrics + - hostmetrics + processors: + - batch/default_metrics + exporters: + - otlp_grpc/default \ No newline at end of file diff --git a/test/integration/upgrade/upgrade_test.go b/test/integration/upgrade/upgrade_test.go index 1ab0685029..a7b0bfc1bd 100644 --- a/test/integration/upgrade/upgrade_test.go +++ b/test/integration/upgrade/upgrade_test.go @@ -63,7 +63,7 @@ func Test_UpgradeFromV3(t *testing.T) { // Verify Agent Package Path & get the path verifyAgentPackageSize(t) - // verify agent v3 config has not changed + // verify agent v3 configs has not changed validateAgentConfig(ctx, t, testContainer) // validate agent manifest file @@ -217,18 +217,28 @@ func packagePath(pkgDir, osReleaseContent string) string { func validateAgentConfig(ctx context.Context, tb testing.TB, testContainer testcontainers.Container) { tb.Helper() - agentConfigContent, err := testContainer.CopyFileFromContainer(ctx, "/etc/nginx-agent/nginx-agent.conf") - require.NoError(tb, err) + files := []struct { + containerPath string + expectedPath string + logLabel string + }{ + {"/etc/nginx-agent/nginx-agent.conf", "./configs/nginx-agent-v3-valid-config.conf", "agent config"}, + {"/etc/nginx-agent/opentelemetry-collector-agent.yaml", "./configs/expected-otel-config.yaml", "otel config"}, + } - agentConfig, err := io.ReadAll(agentConfigContent) - require.NoError(tb, err) + for _, file := range files { + configContent, err := testContainer.CopyFileFromContainer(ctx, file.containerPath) + require.NoError(tb, err) - expectedConfig, err := os.ReadFile("./configs/nginx-agent-v3-valid-config.conf") - require.NoError(tb, err) + config, err := io.ReadAll(configContent) + require.NoError(tb, err) + + expectedConfig, err := os.ReadFile(file.expectedPath) + require.NoError(tb, err) - expectedConfig = bytes.TrimSpace(expectedConfig) - agentConfig = bytes.TrimSpace(agentConfig) + expectedConfig = bytes.TrimSpace(expectedConfig) + config = bytes.TrimSpace(config) - assert.Equal(tb, string(expectedConfig), string(agentConfig)) - tb.Log("agent config:", string(agentConfig)) + assert.Equal(tb, string(expectedConfig), string(config)) + } } From a82777d284d40a992057b7c9dd083c1160e1dbcb Mon Sep 17 00:00:00 2001 From: Craig Elliott Date: Mon, 18 May 2026 11:54:59 +0100 Subject: [PATCH 2/8] Update upgrade tests --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index 9a2bd05ad5..43e59c9fdf 100644 --- a/go.sum +++ b/go.sum @@ -221,8 +221,6 @@ github.com/foxboron/go-tpm-keyfiles v0.0.0-20251226215517-609e4778396f/go.mod h1 github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/fxamacker/cbor/v2 v2.9.1 h1:2rWm8B193Ll4VdjsJY28jxs70IdDsHRWgQYAI80+rMQ= @@ -1083,8 +1081,6 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= From e5209e6b230e3b292a2c62136966f60723f88a24 Mon Sep 17 00:00:00 2001 From: Craig Elliott Date: Tue, 19 May 2026 15:35:45 +0100 Subject: [PATCH 3/8] Adding custom otel test --- test/helpers/test_containers_utils.go | 5 + .../upgrade/configs/default/my_config.yaml | 0 .../nginx-agent-v3-valid-config.conf | 0 .../configs/{ => default}/nginx-agent.conf | 0 .../otel-config.yaml} | 0 .../upgrade/configs/otel/my_config.yaml | 15 ++ .../upgrade/configs/otel/nginx-agent.conf | 28 ++++ .../upgrade/configs/otel/otel-config.yaml | 52 ++++++ test/integration/upgrade/upgrade_test.go | 155 ++++++++++++------ 9 files changed, 206 insertions(+), 49 deletions(-) create mode 100644 test/integration/upgrade/configs/default/my_config.yaml rename test/integration/upgrade/configs/{ => default}/nginx-agent-v3-valid-config.conf (100%) rename test/integration/upgrade/configs/{ => default}/nginx-agent.conf (100%) rename test/integration/upgrade/configs/{expected-otel-config.yaml => default/otel-config.yaml} (100%) create mode 100644 test/integration/upgrade/configs/otel/my_config.yaml create mode 100644 test/integration/upgrade/configs/otel/nginx-agent.conf create mode 100644 test/integration/upgrade/configs/otel/otel-config.yaml diff --git a/test/helpers/test_containers_utils.go b/test/helpers/test_containers_utils.go index 208b365c96..f22448c1ae 100644 --- a/test/helpers/test_containers_utils.go +++ b/test/helpers/test_containers_utils.go @@ -107,6 +107,11 @@ func StartContainer( ContainerFilePath: "/etc/nginx/mime.types", FileMode: configFilePermissions, }, + { + HostFilePath: parameters.NginxAgentOTELConfigPath, + ContainerFilePath: "/etc/nginx-agent/my_config.yaml", + FileMode: configFilePermissions, + }, }, Env: env, } diff --git a/test/integration/upgrade/configs/default/my_config.yaml b/test/integration/upgrade/configs/default/my_config.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/integration/upgrade/configs/nginx-agent-v3-valid-config.conf b/test/integration/upgrade/configs/default/nginx-agent-v3-valid-config.conf similarity index 100% rename from test/integration/upgrade/configs/nginx-agent-v3-valid-config.conf rename to test/integration/upgrade/configs/default/nginx-agent-v3-valid-config.conf diff --git a/test/integration/upgrade/configs/nginx-agent.conf b/test/integration/upgrade/configs/default/nginx-agent.conf similarity index 100% rename from test/integration/upgrade/configs/nginx-agent.conf rename to test/integration/upgrade/configs/default/nginx-agent.conf diff --git a/test/integration/upgrade/configs/expected-otel-config.yaml b/test/integration/upgrade/configs/default/otel-config.yaml similarity index 100% rename from test/integration/upgrade/configs/expected-otel-config.yaml rename to test/integration/upgrade/configs/default/otel-config.yaml diff --git a/test/integration/upgrade/configs/otel/my_config.yaml b/test/integration/upgrade/configs/otel/my_config.yaml new file mode 100644 index 0000000000..7827f7c4f1 --- /dev/null +++ b/test/integration/upgrade/configs/otel/my_config.yaml @@ -0,0 +1,15 @@ +receivers: + hostmetrics: + collection_interval: 10s + scrapers: + cpu: + +exporters: + debug: + verbosity: detailed + +service: + pipelines: + metrics: + receivers: [hostmetrics] + exporters: [debug] \ No newline at end of file diff --git a/test/integration/upgrade/configs/otel/nginx-agent.conf b/test/integration/upgrade/configs/otel/nginx-agent.conf new file mode 100644 index 0000000000..061e662054 --- /dev/null +++ b/test/integration/upgrade/configs/otel/nginx-agent.conf @@ -0,0 +1,28 @@ +# +# /etc/nginx-agent/nginx-agent.conf +# +# Configuration file for NGINX Agent. +# + +log: + # set log level (error, warn, info, debug; default "info") + level: debug + # set log path. if empty, don't log to file. + path: /var/log/nginx-agent/ + +allowed_directories: + - /etc/nginx + - /usr/local/etc/nginx + - /usr/share/nginx/modules + - /var/run/nginx + - /var/log/nginx + +command: + server: + host: managementPlane + port: 9092 + type: grpc + +collector: + additional_config_paths: + - "/etc/nginx-agent/my_config.yaml" \ No newline at end of file diff --git a/test/integration/upgrade/configs/otel/otel-config.yaml b/test/integration/upgrade/configs/otel/otel-config.yaml new file mode 100644 index 0000000000..9a1cb2d661 --- /dev/null +++ b/test/integration/upgrade/configs/otel/otel-config.yaml @@ -0,0 +1,52 @@ +receivers: + containermetrics: + collection_interval: 1m0s + hostmetrics: + collection_interval: 1m0s + initial_delay: 1s + scrapers: + network: + +processors: + batch/default_logs: + send_batch_size: 100 + timeout: 1m0s + send_batch_max_size: 100 + batch/default_metrics: + send_batch_size: 1000 + timeout: 30s + send_batch_max_size: 1000 + securityviolationsfilter/default: {} + +exporters: + otlp_grpc/default: + endpoint: "managementPlane:9092" + timeout: 10s + retry_on_failure: + enabled: true + initial_interval: 10s + max_interval: 60s + max_elapsed_time: 10m + tls: + insecure: true +extensions: + +service: + telemetry: + metrics: + level: none + logs: + level: DEBUG + output_paths: ["/var/log/nginx-agent/opentelemetry-collector-agent.log"] + error_output_paths: ["/var/log/nginx-agent/opentelemetry-collector-agent.log"] + extensions: + + pipelines: + metrics/default: + receivers: + - containermetrics + - hostmetrics + processors: + - batch/default_metrics + exporters: + - otlp_grpc/default \ No newline at end of file diff --git a/test/integration/upgrade/upgrade_test.go b/test/integration/upgrade/upgrade_test.go index a7b0bfc1bd..7026d4d547 100644 --- a/test/integration/upgrade/upgrade_test.go +++ b/test/integration/upgrade/upgrade_test.go @@ -11,8 +11,6 @@ import ( "io" "log/slog" "os" - "path" - "path/filepath" "strings" "testing" "time" @@ -29,6 +27,8 @@ const ( maxFileSize int64 = 70000000 maxUpgradeTime = 30 * time.Second agentBuildDir = "../agent/build" + agentConfigDir = "/etc/nginx-agent" + agentLogDir = "/var/log/nginx-agent" ) var ( @@ -46,7 +46,7 @@ func Test_UpgradeFromV3(t *testing.T) { require.NoError(t, err) }(ctx) - testContainer, teardownTest := upgradeSetup(t, true, containerNetwork) + testContainer, teardownTest := upgradeSetup(t, true, "default", containerNetwork) defer teardownTest(t) slog.Info("starting agent v3 upgrade tests") @@ -60,17 +60,24 @@ func Test_UpgradeFromV3(t *testing.T) { // verify version of agent verifyAgentVersion(ctx, t, testContainer, oldVersion) - // Verify Agent Package Path & get the path - verifyAgentPackageSize(t) - + // Expected files to validate after upgrade + files := []struct { + containerPath string + expectedPath string + logLabel string + }{ + {agentConfigDir + "/nginx-agent.conf", "./configs/default/nginx-agent.conf", "agent config"}, + {agentConfigDir + "/opentelemetry-collector-agent.yaml", "./configs/default/otel-config.yaml", "otel config"}, + {agentConfigDir + "/my_config.yaml", "./configs/default/my_config.yaml", "otel config"}, + } // verify agent v3 configs has not changed - validateAgentConfig(ctx, t, testContainer) + validateAgentConfig(ctx, t, testContainer, files) // validate agent manifest file expected := map[string]*model.ManifestFile{ "/etc/nginx/nginx.conf": { ManifestFileMeta: &model.ManifestFileMeta{ - Name: "/etc/nginx/nginx.conf", + Name: "etc/nginx/nginx.conf", Hash: "XEaOA4w+aT5fmNMISPwavBroLVYlkJf9sjKFTnWkTP8=", Size: 1142, Referenced: true, @@ -82,16 +89,76 @@ func Test_UpgradeFromV3(t *testing.T) { slog.Info("finished agent v3 upgrade tests") } -func upgradeSetup(tb testing.TB, expectNoErrorsInLogs bool, +func Test_UpgradeWithCustomOTELConfig(t *testing.T) { + ctx := context.Background() + + containerNetwork := utils.CreateContainerNetwork(ctx, t) + utils.SetupMockManagementPlaneGrpc(ctx, t, containerNetwork) + defer func(ctx context.Context) { + err := utils.MockManagementPlaneGrpcContainer.Terminate(ctx) + require.NoError(t, err) + }(ctx) + + testContainer, teardownTest := upgradeSetup(t, true, "custom_otel", containerNetwork) + defer teardownTest(t) + + slog.Info("starting agent v3 upgrade tests with custom OTEL config") + + // get currently installed agent version + oldVersion := agentVersion(ctx, t, testContainer) + + // verify agent upgrade + verifyAgentUpgrade(ctx, t, testContainer) + + // verify version of agent + verifyAgentVersion(ctx, t, testContainer, oldVersion) + + // Expected files to validate after upgrade + files := []struct { + containerPath string + expectedPath string + logLabel string + }{ + {agentConfigDir + "/nginx-agent.conf", "./configs/otel/nginx-agent.conf", "agent config"}, + {agentConfigDir + "/my_config.yaml", "./configs/otel/my_config.yaml", "otel custom config"}, + {agentConfigDir + "/opentelemetry-collector-agent.yaml", "./configs/otel/otel-config.yaml", "otel config"}, + } + // verify agent v3 configs has not changed + validateAgentConfig(ctx, t, testContainer, files) + + // Validate agent.log contains OTEL startup log + assertStringInContainerFile(ctx, t, testContainer, agentLogDir+"/agent.log", "Starting OTel collector") + assertStringInContainerFile(ctx, t, testContainer, agentLogDir+"/agent.log", "Merging additional OTel config files") + + // Validate agent otel log contains specific logs + assertStringInContainerFile(ctx, t, testContainer, agentLogDir+"/opentelemetry-collector-agent.log", + "Everything is ready. Begin running and processing data.") + + slog.Info("finished agent v3 upgrade tests with custom OTEL config") +} + +func upgradeSetup(tb testing.TB, expectNoErrorsInLogs bool, setupType string, containerNetwork *testcontainers.DockerNetwork, ) (testcontainers.Container, func(tb testing.TB)) { tb.Helper() ctx := context.Background() - - params := &helpers.Parameters{ - NginxConfigPath: "./configs/nginx-oss.conf", - NginxAgentConfigPath: "./configs/nginx-agent.conf", - LogMessage: "nginx_pid", + var params *helpers.Parameters + + switch setupType { + case "custom_otel": + params = &helpers.Parameters{ + NginxConfigPath: "./configs/nginx-oss.conf", + NginxAgentConfigPath: "./configs/otel/nginx-agent.conf", + NginxAgentOTELConfigPath: "./configs/otel/my_config.yaml", + LogMessage: "nginx_pid", + } + default: + params = &helpers.Parameters{ + NginxConfigPath: "./configs/nginx-oss.conf", + NginxAgentConfigPath: "./configs/default/nginx-agent.conf", + NginxAgentOTELConfigPath: "./configs/default/my_config.yaml", + LogMessage: "nginx_pid", + } } testContainer := helpers.StartContainer( @@ -114,20 +181,6 @@ func upgradeSetup(tb testing.TB, expectNoErrorsInLogs bool, } } -func verifyAgentPackageSize(tb testing.TB) string { - tb.Helper() - agentPkgPath, filePathErr := filepath.Abs("../../../build/") - require.NoError(tb, filePathErr, "Error finding local agent package build dir") - - localAgentPkg, packageErr := os.Stat(packagePath(agentPkgPath, osRelease)) - require.NoError(tb, packageErr, "Error accessing package at: "+agentPkgPath) - - // check if file size is less than 70MB - assert.Less(tb, localAgentPkg.Size(), maxFileSize) - - return packagePath(agentBuildDir, osRelease) -} - func verifyAgentUpgrade(ctx context.Context, tb testing.TB, testContainer testcontainers.Container, ) { @@ -202,29 +255,17 @@ func agentVersion(ctx context.Context, tb testing.TB, testContainer testcontaine return output } -func packagePath(pkgDir, osReleaseContent string) string { - pkgPath := path.Join(pkgDir, packageName) - - if strings.Contains(osReleaseContent, "ubuntu") || strings.Contains(osReleaseContent, "Debian") { - return pkgPath + ".deb" - } else if strings.Contains(osReleaseContent, "alpine") { - return pkgPath + ".apk" - } - - return pkgPath + ".rpm" -} - -func validateAgentConfig(ctx context.Context, tb testing.TB, testContainer testcontainers.Container) { - tb.Helper() - - files := []struct { +func validateAgentConfig( + ctx context.Context, + tb testing.TB, + testContainer testcontainers.Container, + files []struct { containerPath string expectedPath string logLabel string - }{ - {"/etc/nginx-agent/nginx-agent.conf", "./configs/nginx-agent-v3-valid-config.conf", "agent config"}, - {"/etc/nginx-agent/opentelemetry-collector-agent.yaml", "./configs/expected-otel-config.yaml", "otel config"}, - } + }, +) { + tb.Helper() for _, file := range files { configContent, err := testContainer.CopyFileFromContainer(ctx, file.containerPath) @@ -238,7 +279,23 @@ func validateAgentConfig(ctx context.Context, tb testing.TB, testContainer testc expectedConfig = bytes.TrimSpace(expectedConfig) config = bytes.TrimSpace(config) - assert.Equal(tb, string(expectedConfig), string(config)) } } + +func assertStringInContainerFile( + ctx context.Context, + tb testing.TB, + testContainer testcontainers.Container, + containerPath string, + searchString string, +) { + tb.Helper() + fileContent, err := testContainer.CopyFileFromContainer(ctx, containerPath) + require.NoError(tb, err) + + content, err := io.ReadAll(fileContent) + require.NoError(tb, err) + + assert.Contains(tb, string(content), searchString, "Expected phrase not found in file: %s", containerPath) +} From 4cdeb984b37fbd23fe889575187ee789f8a70a9c Mon Sep 17 00:00:00 2001 From: Craig Elliott Date: Wed, 20 May 2026 17:11:55 +0100 Subject: [PATCH 4/8] Update tests --- test/helpers/test_containers_utils.go | 56 +++++++++++ test/integration/upgrade/upgrade_test.go | 123 ++++++++++------------- 2 files changed, 109 insertions(+), 70 deletions(-) diff --git a/test/helpers/test_containers_utils.go b/test/helpers/test_containers_utils.go index f22448c1ae..c2dbddb19c 100644 --- a/test/helpers/test_containers_utils.go +++ b/test/helpers/test_containers_utils.go @@ -6,6 +6,7 @@ package helpers import ( + "bytes" "context" "io" "os" @@ -27,6 +28,11 @@ type Parameters struct { LogMessage string } +type ConfigFileDescriptor struct { + ContainerPath string + ExpectedPath string + LogLabel string +} type MockCollectorContainers struct { Agent testcontainers.Container Otel testcontainers.Container @@ -479,3 +485,53 @@ func LogAndTerminateStack(ctx context.Context, tb testing.TB, logAndTerminate("Otel Collector", containers.Otel) logAndTerminate("Prometheus", containers.Prometheus) } + +// ExtractFileFromContainer copies a file from the container at the given path and returns its contents as a string. +func ExtractFileFromContainer( + ctx context.Context, + tb testing.TB, + testContainer testcontainers.Container, + containerPath string, +) string { + tb.Helper() + fileContent, err := testContainer.CopyFileFromContainer(ctx, containerPath) + require.NoError(tb, err) + + content, err := io.ReadAll(fileContent) + require.NoError(tb, err) + content = bytes.TrimSpace(content) + + return string(content) +} + +// ValidateAgentConfig compares files in the container to expected files on disk. +func ValidateAgentConfig( + ctx context.Context, + tb testing.TB, + testContainer testcontainers.Container, + files []ConfigFileDescriptor, +) { + tb.Helper() + + for _, file := range files { + config := ExtractFileFromContainer(ctx, tb, testContainer, file.ContainerPath) + expectedConfig, err := os.ReadFile(file.ExpectedPath) + require.NoError(tb, err) + + expectedConfig = bytes.TrimSpace(expectedConfig) + assert.Equal(tb, string(expectedConfig), config) + } +} + +// AssertStringInContainerFile asserts that a string exists in a file inside the container. +func AssertStringInContainerFile( + ctx context.Context, + tb testing.TB, + testContainer testcontainers.Container, + containerPath string, + searchString string, +) { + tb.Helper() + content := ExtractFileFromContainer(ctx, tb, testContainer, containerPath) + assert.Contains(tb, content, searchString, "Expected phrase not found in file: %s", containerPath) +} diff --git a/test/integration/upgrade/upgrade_test.go b/test/integration/upgrade/upgrade_test.go index 7026d4d547..dcccc070bb 100644 --- a/test/integration/upgrade/upgrade_test.go +++ b/test/integration/upgrade/upgrade_test.go @@ -6,7 +6,6 @@ package upgrade import ( - "bytes" "context" "io" "log/slog" @@ -46,6 +45,7 @@ func Test_UpgradeFromV3(t *testing.T) { require.NoError(t, err) }(ctx) + // Prepare upgrade testContainer, teardownTest := upgradeSetup(t, true, "default", containerNetwork) defer teardownTest(t) @@ -61,31 +61,41 @@ func Test_UpgradeFromV3(t *testing.T) { verifyAgentVersion(ctx, t, testContainer, oldVersion) // Expected files to validate after upgrade - files := []struct { - containerPath string - expectedPath string - logLabel string - }{ - {agentConfigDir + "/nginx-agent.conf", "./configs/default/nginx-agent.conf", "agent config"}, - {agentConfigDir + "/opentelemetry-collector-agent.yaml", "./configs/default/otel-config.yaml", "otel config"}, - {agentConfigDir + "/my_config.yaml", "./configs/default/my_config.yaml", "otel config"}, + files := []helpers.ConfigFileDescriptor{ + { + ContainerPath: agentConfigDir + "/nginx-agent.conf", + ExpectedPath: "./configs/default/nginx-agent.conf", + LogLabel: "agent config", + }, + { + ContainerPath: agentConfigDir + "/my_config.yaml", + ExpectedPath: "./configs/default/my_config.yaml", + LogLabel: "otel config", + }, } - // verify agent v3 configs has not changed - validateAgentConfig(ctx, t, testContainer, files) // validate agent manifest file expected := map[string]*model.ManifestFile{ "/etc/nginx/nginx.conf": { ManifestFileMeta: &model.ManifestFileMeta{ - Name: "etc/nginx/nginx.conf", + Name: "/etc/nginx/nginx.conf", Hash: "XEaOA4w+aT5fmNMISPwavBroLVYlkJf9sjKFTnWkTP8=", Size: 1142, Referenced: true, }, }, } + // Check manifest file contents utils.CheckManifestFile(t, testContainer, expected) + helpers.ValidateAgentConfig(ctx, t, testContainer, files) + + // Validate agent otel conf is present + previousOtelConf := helpers.ExtractFileFromContainer(ctx, t, + testContainer, + agentConfigDir+"/opentelemetry-collector-agent.yaml") + assert.NotEmpty(t, previousOtelConf) + slog.Info("finished agent v3 upgrade tests") } @@ -114,25 +124,43 @@ func Test_UpgradeWithCustomOTELConfig(t *testing.T) { verifyAgentVersion(ctx, t, testContainer, oldVersion) // Expected files to validate after upgrade - files := []struct { - containerPath string - expectedPath string - logLabel string - }{ - {agentConfigDir + "/nginx-agent.conf", "./configs/otel/nginx-agent.conf", "agent config"}, - {agentConfigDir + "/my_config.yaml", "./configs/otel/my_config.yaml", "otel custom config"}, - {agentConfigDir + "/opentelemetry-collector-agent.yaml", "./configs/otel/otel-config.yaml", "otel config"}, + files := []helpers.ConfigFileDescriptor{ + { + ContainerPath: agentConfigDir + "/nginx-agent.conf", + ExpectedPath: "./configs/otel/nginx-agent.conf", + LogLabel: "agent config", + }, + { + ContainerPath: agentConfigDir + "/my_config.yaml", + ExpectedPath: "./configs/otel/my_config.yaml", + LogLabel: "otel custom config", + }, + { + ContainerPath: agentConfigDir + "/opentelemetry-collector-agent.yaml", + ExpectedPath: "./configs/otel/otel-config.yaml", + LogLabel: "otel config", + }, } // verify agent v3 configs has not changed - validateAgentConfig(ctx, t, testContainer, files) + helpers.ValidateAgentConfig(ctx, t, testContainer, files) // Validate agent.log contains OTEL startup log - assertStringInContainerFile(ctx, t, testContainer, agentLogDir+"/agent.log", "Starting OTel collector") - assertStringInContainerFile(ctx, t, testContainer, agentLogDir+"/agent.log", "Merging additional OTel config files") + helpers.AssertStringInContainerFile( + ctx, t, testContainer, agentLogDir+"/agent.log", "Starting OTel collector", + ) + helpers.AssertStringInContainerFile( + ctx, + t, + testContainer, + agentLogDir+"/agent.log", + "Merging additional OTel config files", + ) // Validate agent otel log contains specific logs - assertStringInContainerFile(ctx, t, testContainer, agentLogDir+"/opentelemetry-collector-agent.log", - "Everything is ready. Begin running and processing data.") + helpers.AssertStringInContainerFile( + ctx, t, testContainer, agentLogDir+"/opentelemetry-collector-agent.log", + "Everything is ready. Begin running and processing data.", + ) slog.Info("finished agent v3 upgrade tests with custom OTEL config") } @@ -254,48 +282,3 @@ func agentVersion(ctx context.Context, tb testing.TB, testContainer testcontaine return output } - -func validateAgentConfig( - ctx context.Context, - tb testing.TB, - testContainer testcontainers.Container, - files []struct { - containerPath string - expectedPath string - logLabel string - }, -) { - tb.Helper() - - for _, file := range files { - configContent, err := testContainer.CopyFileFromContainer(ctx, file.containerPath) - require.NoError(tb, err) - - config, err := io.ReadAll(configContent) - require.NoError(tb, err) - - expectedConfig, err := os.ReadFile(file.expectedPath) - require.NoError(tb, err) - - expectedConfig = bytes.TrimSpace(expectedConfig) - config = bytes.TrimSpace(config) - assert.Equal(tb, string(expectedConfig), string(config)) - } -} - -func assertStringInContainerFile( - ctx context.Context, - tb testing.TB, - testContainer testcontainers.Container, - containerPath string, - searchString string, -) { - tb.Helper() - fileContent, err := testContainer.CopyFileFromContainer(ctx, containerPath) - require.NoError(tb, err) - - content, err := io.ReadAll(fileContent) - require.NoError(tb, err) - - assert.Contains(tb, string(content), searchString, "Expected phrase not found in file: %s", containerPath) -} From 251382449c77db0850a44ea0e4037c4ea8aa7c9c Mon Sep 17 00:00:00 2001 From: Craig Elliott Date: Thu, 21 May 2026 13:57:39 +0100 Subject: [PATCH 5/8] Fixing integration tests --- test/helpers/test_containers_utils.go | 50 ++++++++++++++------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/test/helpers/test_containers_utils.go b/test/helpers/test_containers_utils.go index c2dbddb19c..d442b78661 100644 --- a/test/helpers/test_containers_utils.go +++ b/test/helpers/test_containers_utils.go @@ -65,7 +65,30 @@ func StartContainer( "NGINX_LICENSE_JWT": nginxLicenseJwt, } } - + files := []testcontainers.ContainerFile{ + { + HostFilePath: parameters.NginxAgentConfigPath, + ContainerFilePath: "/etc/nginx-agent/nginx-agent.conf", + FileMode: configFilePermissions, + }, + { + HostFilePath: parameters.NginxConfigPath, + ContainerFilePath: "/etc/nginx/nginx.conf", + FileMode: configFilePermissions, + }, + { + HostFilePath: "../../config/nginx/mime.types", + ContainerFilePath: "/etc/nginx/mime.types", + FileMode: configFilePermissions, + }, + } + if parameters.NginxAgentOTELConfigPath != "" { + files = append(files, testcontainers.ContainerFile{ + HostFilePath: parameters.NginxAgentOTELConfigPath, + ContainerFilePath: "/etc/nginx-agent/my_config.yaml", + FileMode: configFilePermissions, + }) + } req := testcontainers.ContainerRequest{ FromDockerfile: testcontainers.FromDockerfile{ Context: "../../../", @@ -97,29 +120,8 @@ func StartContainer( "agent", }, }, - Files: []testcontainers.ContainerFile{ - { - HostFilePath: parameters.NginxAgentConfigPath, - ContainerFilePath: "/etc/nginx-agent/nginx-agent.conf", - FileMode: configFilePermissions, - }, - { - HostFilePath: parameters.NginxConfigPath, - ContainerFilePath: "/etc/nginx/nginx.conf", - FileMode: configFilePermissions, - }, - { - HostFilePath: "../../config/nginx/mime.types", - ContainerFilePath: "/etc/nginx/mime.types", - FileMode: configFilePermissions, - }, - { - HostFilePath: parameters.NginxAgentOTELConfigPath, - ContainerFilePath: "/etc/nginx-agent/my_config.yaml", - FileMode: configFilePermissions, - }, - }, - Env: env, + Files: files, + Env: env, } container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ From 88fbf70c215038d584460961aaeb01d98340b645 Mon Sep 17 00:00:00 2001 From: Craig Elliott Date: Mon, 25 May 2026 09:55:05 +0100 Subject: [PATCH 6/8] Code review feedback --- test/helpers/test_containers_utils.go | 6 +++--- test/integration/upgrade/upgrade_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/helpers/test_containers_utils.go b/test/helpers/test_containers_utils.go index d442b78661..164586ed5e 100644 --- a/test/helpers/test_containers_utils.go +++ b/test/helpers/test_containers_utils.go @@ -506,8 +506,8 @@ func ExtractFileFromContainer( return string(content) } -// ValidateAgentConfig compares files in the container to expected files on disk. -func ValidateAgentConfig( +// ValidateContainerFiles compares files in the container to expected files on disk. +func ValidateContainerFiles( ctx context.Context, tb testing.TB, testContainer testcontainers.Container, @@ -521,7 +521,7 @@ func ValidateAgentConfig( require.NoError(tb, err) expectedConfig = bytes.TrimSpace(expectedConfig) - assert.Equal(tb, string(expectedConfig), config) + assert.Equal(tb, string(expectedConfig), config, "Mismatch in file: %s", file.LogLabel) } } diff --git a/test/integration/upgrade/upgrade_test.go b/test/integration/upgrade/upgrade_test.go index dcccc070bb..aa6fe7eec4 100644 --- a/test/integration/upgrade/upgrade_test.go +++ b/test/integration/upgrade/upgrade_test.go @@ -88,7 +88,7 @@ func Test_UpgradeFromV3(t *testing.T) { // Check manifest file contents utils.CheckManifestFile(t, testContainer, expected) - helpers.ValidateAgentConfig(ctx, t, testContainer, files) + helpers.ValidateContainerFiles(ctx, t, testContainer, files) // Validate agent otel conf is present previousOtelConf := helpers.ExtractFileFromContainer(ctx, t, @@ -142,7 +142,7 @@ func Test_UpgradeWithCustomOTELConfig(t *testing.T) { }, } // verify agent v3 configs has not changed - helpers.ValidateAgentConfig(ctx, t, testContainer, files) + helpers.ValidateContainerFiles(ctx, t, testContainer, files) // Validate agent.log contains OTEL startup log helpers.AssertStringInContainerFile( From eb5ebdffd0788a745e997e7662c1de3f1085f18e Mon Sep 17 00:00:00 2001 From: Aphral Griffin Date: Mon, 25 May 2026 10:13:15 +0100 Subject: [PATCH 7/8] update deps --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 0b4baee7f4..a7afa70b59 100644 --- a/go.mod +++ b/go.mod @@ -393,8 +393,8 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.43.0 golang.org/x/crypto v0.51.0 // indirect - golang.org/x/net v0.54.0 // indirect - golang.org/x/sys v0.44.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect golang.org/x/text v0.37.0 // indirect google.golang.org/grpc v1.80.0 ) diff --git a/go.sum b/go.sum index 43e59c9fdf..6e0ed56d61 100644 --- a/go.sum +++ b/go.sum @@ -1100,8 +1100,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= -golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= @@ -1146,8 +1146,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa h1:efT73AJZfAAUV7SOip6pWGkwJDzIGiKBZGVzHYa+ve4= golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa/go.mod h1:kHjTxDEnAu6/Nl9lDkzjWpR+bmKfxeiRuSDlsMb70gE= From c4ac8ae281f6c5576832be637d489ba12a1adcd1 Mon Sep 17 00:00:00 2001 From: Craig Elliott Date: Mon, 18 May 2026 11:48:16 +0100 Subject: [PATCH 8/8] Update existing upgrade tests --- .../upgrade/configs/expected-otel-config.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 test/integration/upgrade/configs/expected-otel-config.yaml diff --git a/test/integration/upgrade/configs/expected-otel-config.yaml b/test/integration/upgrade/configs/expected-otel-config.yaml new file mode 100644 index 0000000000..9a1cb2d661 --- /dev/null +++ b/test/integration/upgrade/configs/expected-otel-config.yaml @@ -0,0 +1,52 @@ +receivers: + containermetrics: + collection_interval: 1m0s + hostmetrics: + collection_interval: 1m0s + initial_delay: 1s + scrapers: + network: + +processors: + batch/default_logs: + send_batch_size: 100 + timeout: 1m0s + send_batch_max_size: 100 + batch/default_metrics: + send_batch_size: 1000 + timeout: 30s + send_batch_max_size: 1000 + securityviolationsfilter/default: {} + +exporters: + otlp_grpc/default: + endpoint: "managementPlane:9092" + timeout: 10s + retry_on_failure: + enabled: true + initial_interval: 10s + max_interval: 60s + max_elapsed_time: 10m + tls: + insecure: true +extensions: + +service: + telemetry: + metrics: + level: none + logs: + level: DEBUG + output_paths: ["/var/log/nginx-agent/opentelemetry-collector-agent.log"] + error_output_paths: ["/var/log/nginx-agent/opentelemetry-collector-agent.log"] + extensions: + + pipelines: + metrics/default: + receivers: + - containermetrics + - hostmetrics + processors: + - batch/default_metrics + exporters: + - otlp_grpc/default \ No newline at end of file