Skip to content

Commit a9fd9a4

Browse files
Refactors environment variables handling to make it testable. (#9586)
1 parent 9d0688a commit a9fd9a4

File tree

22 files changed

+168
-214
lines changed

22 files changed

+168
-214
lines changed

components/environment/src/main/java/datadog/environment/EnvironmentVariables.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@
1616
public final class EnvironmentVariables {
1717
private EnvironmentVariables() {}
1818

19+
public static class EnvironmentVariablesProvider {
20+
public String get(String name) {
21+
return System.getenv(name);
22+
}
23+
24+
public Map<String, String> getAll() {
25+
return System.getenv();
26+
}
27+
}
28+
29+
// Make it accessible from tests.
30+
public static EnvironmentVariablesProvider provider = new EnvironmentVariablesProvider();
31+
1932
/**
2033
* Gets an environment variable value.
2134
*
@@ -41,7 +54,7 @@ public static String getOrDefault(String name, String defaultValue) {
4154
return defaultValue;
4255
}
4356
try {
44-
String value = System.getenv(name);
57+
String value = provider.get(name);
4558
return value == null ? defaultValue : value;
4659
} catch (SecurityException e) {
4760
return defaultValue;
@@ -56,7 +69,7 @@ public static String getOrDefault(String name, String defaultValue) {
5669
*/
5770
public static Map<String, String> getAll() {
5871
try {
59-
return unmodifiableMap(new HashMap<>(System.getenv()));
72+
return unmodifiableMap(new HashMap<>(provider.getAll()));
6073
} catch (SecurityException e) {
6174
return emptyMap();
6275
}

dd-java-agent/agent-builder/src/test/groovy/datadog/trace/agent/test/DefaultInstrumenterForkedTest.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package datadog.trace.agent.test
22

3-
3+
import datadog.environment.EnvironmentVariables
44
import datadog.trace.agent.tooling.InstrumenterModule
55
import datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers
66
import datadog.trace.agent.tooling.bytebuddy.outline.TypePoolFacade
@@ -118,7 +118,7 @@ class DefaultInstrumenterForkedTest extends DDSpecification {
118118
def target = new TestDefaultInstrumenter(name, altName)
119119

120120
then:
121-
System.getenv("DD_INTEGRATION_${value}_ENABLED") == "true"
121+
EnvironmentVariables.get("DD_INTEGRATION_${value}_ENABLED") == "true"
122122
target.enabled == enabled
123123

124124
where:

dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/ci/CIProviderInfoFactoryTest.groovy

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ package datadog.trace.civisibility.ci
22

33
import datadog.trace.api.Config
44
import datadog.trace.civisibility.ci.env.CiEnvironmentImpl
5-
import org.junit.Rule
6-
import org.junit.contrib.java.lang.system.EnvironmentVariables
7-
import org.junit.contrib.java.lang.system.RestoreSystemProperties
5+
import datadog.trace.test.util.ControllableEnvironmentVariables
86
import spock.lang.Specification
97

108
import java.nio.file.Paths
@@ -21,25 +19,18 @@ import static datadog.trace.civisibility.ci.JenkinsInfo.JENKINS
2119
import static datadog.trace.civisibility.ci.TravisInfo.TRAVIS
2220

2321
class CIProviderInfoFactoryTest extends Specification {
24-
@Rule
25-
public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
22+
protected ControllableEnvironmentVariables env = ControllableEnvironmentVariables.setup()
2623

27-
@Rule
28-
public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties()
29-
30-
def setup() {
31-
// Clear all environment variables to avoid clashes between
32-
// real CI/Git environment variables and the spec CI/Git
33-
// environment variables.
34-
environmentVariables.clear(System.getenv().keySet() as String[])
24+
void cleanup() {
25+
env.clear()
3526
}
3627

3728
def "test correct info is selected"() {
3829
setup:
39-
environmentVariables.set(ciKeySelector, "true")
30+
env.set(ciKeySelector, "true")
4031

4132
when:
42-
def ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), new CiEnvironmentImpl(System.getenv()))
33+
def ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), new CiEnvironmentImpl(env.getAll()))
4334
def ciProviderInfo = ciProviderInfoFactory.createCIProviderInfo(Paths.get("").toAbsolutePath())
4435

4536
then:

dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/ci/CITagsProviderTest.groovy

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import datadog.trace.civisibility.ci.env.CiEnvironmentImpl
88
import datadog.trace.civisibility.git.CILocalGitInfoBuilder
99
import datadog.trace.civisibility.git.CIProviderGitInfoBuilder
1010
import datadog.trace.civisibility.git.tree.GitClient
11-
import org.junit.Rule
12-
import org.junit.contrib.java.lang.system.EnvironmentVariables
13-
import org.junit.contrib.java.lang.system.RestoreSystemProperties
11+
import datadog.trace.test.util.ControllableEnvironmentVariables
1412
import spock.lang.Specification
1513

1614
import java.nio.file.Path
@@ -19,36 +17,28 @@ import java.nio.file.Paths
1917
import static datadog.trace.util.ConfigStrings.propertyNameToEnvironmentVariableName
2018

2119
abstract class CITagsProviderTest extends Specification {
22-
2320
static final CI_WORKSPACE_PATH_FOR_TESTS = "ci/ci_workspace_for_tests"
2421
static final GIT_FOLDER_FOR_TESTS = "git_folder_for_tests"
2522

26-
@Rule
27-
public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
28-
29-
@Rule
30-
public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties()
23+
protected ControllableEnvironmentVariables env = ControllableEnvironmentVariables.setup()
3124

3225
protected final String localFSGitWorkspace = resolve(CI_WORKSPACE_PATH_FOR_TESTS)
3326

34-
def setup() {
35-
// Clear all environment variables to avoid clashes between
36-
// real CI/Git environment variables and the spec CI/Git
37-
// environment variables.
38-
environmentVariables.clear(System.getenv().keySet() as String[])
27+
void cleanup() {
28+
env.clear()
3929
}
4030

4131
def "test ci provider info is set properly: #ciSpec.providerName #ciSpec.idx #ciSpec.testCaseName"() {
4232
setup:
4333
ciSpec.env.each {
44-
environmentVariables.set(it.key, it.value.toString())
34+
env.set(it.key, it.value.toString())
4535
if (it.key == "HOME") {
4636
System.setProperty("user.home", it.value)
4737
}
4838
}
4939

5040
when:
51-
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(System.getenv()))
41+
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(env.getAll()))
5242
def ciProviderInfo = ciProviderInfoFactory.createCIProviderInfo(getWorkspacePath())
5343
def ciInfo = ciProviderInfo.buildCIInfo()
5444
def prInfo = ciProviderInfo.buildPullRequestInfo()
@@ -68,13 +58,13 @@ abstract class CITagsProviderTest extends Specification {
6858
def "test user supplied commit hash takes precedence over auto-detected git info"() {
6959
setup:
7060
buildRemoteGitInfoEmpty().each {
71-
environmentVariables.set(it.key, it.value)
61+
env.set(it.key, it.value)
7262
}
7363

74-
environmentVariables.set(propertyNameToEnvironmentVariableName(UserSuppliedGitInfoBuilder.DD_GIT_COMMIT_SHA), "1234567890123456789012345678901234567890")
64+
env.set(propertyNameToEnvironmentVariableName(UserSuppliedGitInfoBuilder.DD_GIT_COMMIT_SHA), "1234567890123456789012345678901234567890")
7565

7666
when:
77-
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(System.getenv()))
67+
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(env.getAll()))
7868
def ciProviderInfo = ciProviderInfoFactory.createCIProviderInfo(getWorkspacePath())
7969
def ciInfo = ciProviderInfo.buildCIInfo()
8070
def ciTagsProvider = ciTagsProvider()
@@ -87,13 +77,13 @@ abstract class CITagsProviderTest extends Specification {
8777
def "test user supplied repo url takes precedence over auto-detected git info"() {
8878
setup:
8979
buildRemoteGitInfoEmpty().each {
90-
environmentVariables.set(it.key, it.value)
80+
env.set(it.key, it.value)
9181
}
9282

93-
environmentVariables.set(propertyNameToEnvironmentVariableName(UserSuppliedGitInfoBuilder.DD_GIT_REPOSITORY_URL), "local supplied repo url")
83+
env.set(propertyNameToEnvironmentVariableName(UserSuppliedGitInfoBuilder.DD_GIT_REPOSITORY_URL), "local supplied repo url")
9484

9585
when:
96-
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(System.getenv()))
86+
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(env.getAll()))
9787
def ciProviderInfo = ciProviderInfoFactory.createCIProviderInfo(getWorkspacePath())
9888
def ciInfo = ciProviderInfo.buildCIInfo()
9989
def ciTagsProvider = ciTagsProvider()
@@ -106,11 +96,11 @@ abstract class CITagsProviderTest extends Specification {
10696
def "test set local git info if remote git info is not present"() {
10797
setup:
10898
buildRemoteGitInfoEmpty().each {
109-
environmentVariables.set(it.key, it.value)
99+
env.set(it.key, it.value)
110100
}
111101

112102
when:
113-
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(System.getenv()))
103+
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(env.getAll()))
114104
def ciProviderInfo = ciProviderInfoFactory.createCIProviderInfo(getWorkspacePath())
115105
def ciInfo = ciProviderInfo.buildCIInfo()
116106
def ciTagsProvider = ciTagsProvider()
@@ -134,15 +124,15 @@ abstract class CITagsProviderTest extends Specification {
134124
def "test avoid setting local git info if remote commit does not match"() {
135125
setup:
136126
buildRemoteGitInfoMismatchLocalGit().each {
137-
environmentVariables.set(it.key, it.value)
127+
env.set(it.key, it.value)
138128
}
139129

140130
when:
141131
def ciTagsProvider = ciTagsProvider()
142132

143133
then:
144134
if (isCi()) {
145-
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(System.getenv()))
135+
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(env.getAll()))
146136
def ciProviderInfo = ciProviderInfoFactory.createCIProviderInfo(getWorkspacePath())
147137
def ciInfo = ciProviderInfo.buildCIInfo()
148138
def tags = ciTagsProvider.getCiTags(ciInfo, PullRequestInfo.EMPTY)
@@ -176,7 +166,7 @@ abstract class CITagsProviderTest extends Specification {
176166

177167
GitInfoProvider gitInfoProvider = new GitInfoProvider()
178168
gitInfoProvider.registerGitInfoBuilder(new UserSuppliedGitInfoBuilder())
179-
gitInfoProvider.registerGitInfoBuilder(new CIProviderGitInfoBuilder(Config.get(), new CiEnvironmentImpl(System.getenv())))
169+
gitInfoProvider.registerGitInfoBuilder(new CIProviderGitInfoBuilder(Config.get(), new CiEnvironmentImpl(env.getAll())))
180170
gitInfoProvider.registerGitInfoBuilder(new CILocalGitInfoBuilder(gitClientFactory, GIT_FOLDER_FOR_TESTS))
181171
return new CITagsProvider(gitInfoProvider)
182172
}

dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/ci/GithubActionsInfoTest.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ class GithubActionsInfoTest extends CITagsProviderTest {
3333
def githubEvent = GithubActionsInfoTest.getResource("/ci/github-event.json")
3434
def githubEventPath = Paths.get(githubEvent.toURI())
3535

36-
environmentVariables.set(GithubActionsInfo.GITHUB_BASE_REF, "base-ref")
37-
environmentVariables.set(GithubActionsInfo.GITHUB_EVENT_PATH, githubEventPath.toString())
36+
env.set(GithubActionsInfo.GITHUB_BASE_REF, "base-ref")
37+
env.set(GithubActionsInfo.GITHUB_EVENT_PATH, githubEventPath.toString())
3838

3939
when:
40-
def pullRequestInfo = new GithubActionsInfo(new CiEnvironmentImpl(System.getenv())).buildPullRequestInfo()
40+
def pullRequestInfo = new GithubActionsInfo(new CiEnvironmentImpl(env.getAll())).buildPullRequestInfo()
4141

4242
then:
4343
pullRequestInfo.getBaseBranch() == "base-ref"

dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/ci/UnknownCIInfoTest.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class UnknownCIInfoTest extends CITagsProviderTest {
4545
]
4646

4747
when:
48-
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(System.getenv()))
48+
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), GIT_FOLDER_FOR_TESTS, new CiEnvironmentImpl(env.getAll()))
4949
def ciProviderInfo = ciProviderInfoFactory.createCIProviderInfo(workspaceForTests)
5050
def ciInfo = ciProviderInfo.buildCIInfo()
5151
def ciTagsProvider = ciTagsProvider()
@@ -62,9 +62,9 @@ class UnknownCIInfoTest extends CITagsProviderTest {
6262

6363
GitInfoProvider gitInfoProvider = new GitInfoProvider()
6464
gitInfoProvider.registerGitInfoBuilder(new UserSuppliedGitInfoBuilder())
65-
gitInfoProvider.registerGitInfoBuilder(new CIProviderGitInfoBuilder(Config.get(), new CiEnvironmentImpl(System.getenv())))
65+
gitInfoProvider.registerGitInfoBuilder(new CIProviderGitInfoBuilder(Config.get(), new CiEnvironmentImpl(env.getAll())))
6666
gitInfoProvider.registerGitInfoBuilder(new CILocalGitInfoBuilder(gitClientFactory, "this-target-folder-does-not-exist"))
67-
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), "this-target-folder-does-not-exist", new CiEnvironmentImpl(System.getenv()))
67+
CIProviderInfoFactory ciProviderInfoFactory = new CIProviderInfoFactory(Config.get(), "this-target-folder-does-not-exist", new CiEnvironmentImpl(env.getAll()))
6868

6969
def ciProviderInfo = ciProviderInfoFactory.createCIProviderInfo(workspaceForTests)
7070
def ciInfo = ciProviderInfo.buildCIInfo()

dd-java-agent/agent-ci-visibility/src/test/groovy/datadog/trace/civisibility/git/CIProviderGitInfoBuilderTest.groovy

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,19 @@ package datadog.trace.civisibility.git
22

33
import datadog.trace.api.Config
44
import datadog.trace.civisibility.ci.env.CiEnvironmentImpl
5-
import org.junit.Rule
6-
import org.junit.contrib.java.lang.system.EnvironmentVariables
5+
import datadog.trace.test.util.ControllableEnvironmentVariables
76
import spock.lang.Specification
87

98
class CIProviderGitInfoBuilderTest extends Specification {
9+
protected ControllableEnvironmentVariables env = ControllableEnvironmentVariables.setup()
1010

11-
@Rule
12-
public final EnvironmentVariables environmentVariables = new EnvironmentVariables()
13-
14-
def setup() {
15-
// Clear all environment variables to avoid clashes between
16-
// real CI/Git environment variables and the spec CI/Git
17-
// environment variables.
18-
environmentVariables.clear(System.getenv().keySet() as String[])
11+
void cleanup() {
12+
env.clear()
1913
}
2014

2115
def "test builds empty git info in an unknown repository"() {
2216
setup:
23-
def builder = new CIProviderGitInfoBuilder(Config.get(), new CiEnvironmentImpl(System.getenv()))
17+
def builder = new CIProviderGitInfoBuilder(Config.get(), new CiEnvironmentImpl(env.getAll()))
2418

2519
when:
2620
def gitInfo = builder.build(null)

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerAgentTest.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import static org.mockito.Mockito.never;
1313
import static org.mockito.Mockito.verify;
1414
import static org.mockito.Mockito.when;
15-
import static utils.TestHelper.setEnvVar;
1615
import static utils.TestHelper.setFieldInConfig;
1716

1817
import com.datadog.debugger.util.RemoteConfigHelper;
@@ -22,6 +21,7 @@
2221
import datadog.trace.api.Config;
2322
import datadog.trace.api.git.GitInfoProvider;
2423
import datadog.trace.bootstrap.instrumentation.api.Tags;
24+
import datadog.trace.test.util.ControllableEnvironmentVariables;
2525
import java.io.BufferedReader;
2626
import java.io.IOException;
2727
import java.io.InputStreamReader;
@@ -54,6 +54,8 @@ public class DebuggerAgentTest {
5454
final MockWebServer server = new MockWebServer();
5555
HttpUrl url;
5656

57+
private ControllableEnvironmentVariables env = ControllableEnvironmentVariables.setup();
58+
5759
private static void setFieldInContainerInfo(
5860
ContainerInfo containerInfo, String fieldName, Object value) {
5961
try {
@@ -67,6 +69,7 @@ private static void setFieldInContainerInfo(
6769

6870
@BeforeEach
6971
public void setUp() {
72+
env.clear();
7073
url = server.url(URL_PATH);
7174
}
7275

@@ -175,14 +178,14 @@ public void tags() {
175178
when(config.getGlobalTags()).thenReturn(globalTags);
176179
// set env vars now to be cached by GitInfoProvider
177180
GitInfoProvider.INSTANCE.invalidateCache();
178-
setEnvVar("DD_GIT_COMMIT_SHA", "sha1");
179-
setEnvVar("DD_GIT_REPOSITORY_URL", "http://github.com");
181+
env.set("DD_GIT_COMMIT_SHA", "sha1");
182+
env.set("DD_GIT_REPOSITORY_URL", "http://github.com");
180183
String tags;
181184
try {
182185
tags = DebuggerAgent.getDefaultTagsMergedWithGlobalTags(config);
183186
} finally {
184-
setEnvVar("DD_GIT_COMMIT_SHA", null);
185-
setEnvVar("DD_GIT_REPOSITORY_URL", null);
187+
env.set("DD_GIT_COMMIT_SHA", null);
188+
env.set("DD_GIT_REPOSITORY_URL", null);
186189
GitInfoProvider.INSTANCE.invalidateCache();
187190
}
188191
Map<String, String> resultTags = new HashMap<>();

dd-java-agent/agent-debugger/src/test/java/utils/TestHelper.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import java.nio.file.Paths;
1010
import java.time.Duration;
1111
import java.util.List;
12-
import java.util.Map;
1312
import java.util.function.BooleanSupplier;
1413

1514
public class TestHelper {
@@ -47,19 +46,4 @@ public static void assertWithTimeout(BooleanSupplier predicate, Duration timeout
4746
}
4847
assertTrue(predicate.getAsBoolean());
4948
}
50-
51-
public static void setEnvVar(String envName, String envValue) {
52-
try {
53-
Class<?> classOfMap = System.getenv().getClass();
54-
Field field = classOfMap.getDeclaredField("m");
55-
field.setAccessible(true);
56-
if (envValue == null) {
57-
((Map<String, String>) field.get(System.getenv())).remove(envName);
58-
} else {
59-
((Map<String, String>) field.get(System.getenv())).put(envName, envValue);
60-
}
61-
} catch (Exception ex) {
62-
ex.printStackTrace();
63-
}
64-
}
6549
}

0 commit comments

Comments
 (0)