11package datadog.trace.test.util
22
3+
34import net.bytebuddy.agent.ByteBuddyAgent
45import net.bytebuddy.agent.builder.AgentBuilder
56import net.bytebuddy.dynamic.ClassFileLocator
67import net.bytebuddy.dynamic.Transformer
8+ import org.junit.Rule
9+ import org.junit.contrib.java.lang.system.EnvironmentVariables
10+ import org.junit.contrib.java.lang.system.RestoreSystemProperties
711import spock.lang.Specification
812
13+ import java.lang.reflect.Constructor
14+ import java.lang.reflect.Field
15+ import java.lang.reflect.Modifier
16+
917import static net.bytebuddy.description.modifier.FieldManifestation.VOLATILE
1018import static net.bytebuddy.description.modifier.Ownership.STATIC
1119import static net.bytebuddy.description.modifier.Visibility.PUBLIC
@@ -15,13 +23,22 @@ import static net.bytebuddy.matcher.ElementMatchers.none
1523abstract class DDSpecification extends Specification {
1624 private static final String CONFIG = " datadog.trace.api.Config"
1725
26+ private static Field CONFIG_INSTANCE_FIELD
27+ private static Constructor CONFIG_CONSTRUCTOR
28+
1829 static {
1930 makeConfigInstanceModifiable()
2031 }
2132
2233 // Keep track of config instance already made modifiable
2334 private static isConfigInstanceModifiable = false
2435
36+ @Rule
37+ public final EnvironmentVariables environmentVariables = new EnvironmentVariables ()
38+
39+ @Rule
40+ protected final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties ()
41+
2542 static void makeConfigInstanceModifiable () {
2643 if (isConfigInstanceModifiable) {
2744 return
@@ -43,6 +60,46 @@ abstract class DDSpecification extends Specification {
4360 .transform(Transformer.ForField . withModifiers(PUBLIC , STATIC , VOLATILE ))
4461 }
4562 .installOn(instrumentation)
63+
64+ Class configClass = Class . forName(CONFIG )
65+ CONFIG_INSTANCE_FIELD = configClass. getDeclaredField(" INSTANCE" )
66+ CONFIG_CONSTRUCTOR = configClass. getDeclaredConstructor()
67+ CONFIG_CONSTRUCTOR . setAccessible(true )
68+
4669 isConfigInstanceModifiable = true
4770 }
71+
72+ void cleanupSpec () {
73+ rebuildConfig()
74+ }
75+
76+ void setup () {
77+ rebuildConfig()
78+ }
79+
80+ void injectSysConfig (String name , String value ) {
81+ String prefixedName = name. startsWith(" dd." ) ? name : " dd." + name
82+ System . setProperty(prefixedName, value)
83+ rebuildConfig()
84+ }
85+
86+ void injectEnvConfig (String name , String value ) {
87+ String prefixedName = name. startsWith(" DD_" ) ? name : " DD_" + name
88+ environmentVariables. set(prefixedName, value)
89+ rebuildConfig()
90+ }
91+
92+ /**
93+ * Reset the global configuration. Please note that Runtime ID is preserved to the pre-existing value.
94+ */
95+ synchronized static void rebuildConfig () {
96+ // Ensure the class was re-transformed properly in DDSpecification.makeConfigInstanceModifiable()
97+ assert Modifier . isPublic(CONFIG_INSTANCE_FIELD . getModifiers())
98+ assert Modifier . isStatic(CONFIG_INSTANCE_FIELD . getModifiers())
99+ assert Modifier . isVolatile(CONFIG_INSTANCE_FIELD . getModifiers())
100+ assert ! Modifier . isFinal(CONFIG_INSTANCE_FIELD . getModifiers())
101+
102+ def newConfig = CONFIG_CONSTRUCTOR . newInstance()
103+ CONFIG_INSTANCE_FIELD . set(null , newConfig)
104+ }
48105}
0 commit comments