From d5a0bd1f5cf4c5bca06e4059ec7d5ffb06315d3f Mon Sep 17 00:00:00 2001 From: Adam Benjamin Date: Thu, 13 Mar 2025 12:55:50 -0500 Subject: [PATCH] chore(gcp-resource-detector): unit test to prevent a regression and ensure previously set attributes are not overwritten with blank values. When attributes have already been set by other detectors, such as the EnvDetector, when the GcpDetector is run, it should not overwrite an existing attribute with a blank value if the source environment variable doesn't exist. Prior to commit 143a1f4f9d876e9d503937c1cd53391d3f771c05, the behavior was as follows: - OTEL_RESOURCE_ATTRIBUTES = 'k8s.namespace.name=my-namespace' - NAMESPACE is undefined - EnvDetector runs and adds 'k8s.namespace.name=my-namespace' to attributes list - GcpDetector runs and sets 'k8s.namespace.name=' (blank) The GcpDetector should only set 'k8s.namespace.name' if the source environment variable is defined. --- .../test/detectors/GcpDetector.test.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/detectors/node/opentelemetry-resource-detector-gcp/test/detectors/GcpDetector.test.ts b/detectors/node/opentelemetry-resource-detector-gcp/test/detectors/GcpDetector.test.ts index 7af4b8b374..49d2ad8c0f 100644 --- a/detectors/node/opentelemetry-resource-detector-gcp/test/detectors/GcpDetector.test.ts +++ b/detectors/node/opentelemetry-resource-detector-gcp/test/detectors/GcpDetector.test.ts @@ -176,6 +176,46 @@ describe('gcpDetector', () => { }); }); + it('should return resource and undefined for non-available kubernetes attributes', async () => { + process.env.KUBERNETES_SERVICE_HOST = 'my-host'; + process.env.HOSTNAME = 'my-hostname'; + process.env.CONTAINER_NAME = 'my-container-name'; + const scope = nock(HOST_ADDRESS) + .get(INSTANCE_PATH) + .reply(200, {}, HEADERS) + .get(INSTANCE_ID_PATH) + .reply(200, () => '4520031799277581759', HEADERS) + .get(CLUSTER_NAME_PATH) + .reply(200, () => 'my-cluster', HEADERS) + .get(PROJECT_ID_PATH) + .reply(200, () => 'my-project-id', HEADERS) + .get(ZONE_PATH) + .reply(200, () => 'project/zone/my-zone', HEADERS) + .get(HOSTNAME_PATH) + .reply(200, () => 'dev.my-project.local', HEADERS); + const secondaryScope = nock(SECONDARY_HOST_ADDRESS) + .get(INSTANCE_PATH) + .reply(200, {}, HEADERS); + + const resource = detectResources({ detectors: [gcpDetector] }); + await resource.waitForAsyncAttributes?.(); + + secondaryScope.done(); + scope.done(); + + assertCloudResource(resource, { + provider: 'gcp', + accountId: 'my-project-id', + zone: 'my-zone', + }); + assertK8sResource(resource, { + clusterName: 'my-cluster', + podName: 'my-hostname', + namespaceName: undefined, + }); + assertContainerResource(resource, { name: 'my-container-name' }); + }); + it('returns empty resource if not detected', async () => { const resource = detectResources({ detectors: [gcpDetector] }); await resource.waitForAsyncAttributes?.();