Skip to content

Commit a71d73c

Browse files
committed
Support removal of environment variables and system properties
1 parent 18ca9f0 commit a71d73c

File tree

12 files changed

+401
-93
lines changed

12 files changed

+401
-93
lines changed

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ See the full guide to [JUnit 5](system-stubs-jupiter/README.md), or use it with
128128

129129
## Using System Stubs Individually
130130

131+
The plugins for JUnit etc will allow the stub objects to be used during a test, where they will
132+
be set up and torn down around the test method. However, they can also be used without the framework.
133+
131134
You can declare a system stub object:
132135

133136
```java
@@ -310,6 +313,22 @@ mutable version of the `and` method used in the first example.
310313
affect the runtime environment. Calling it outside of execution will store the
311314
value for writing into the environment within `execute`.
312315

316+
You can remove an environment variable with `remove`:
317+
318+
```java
319+
// assuming that there's an environment variable "STAGE" set here
320+
new EnvironmentVariables()
321+
.remove("STAGE")
322+
.execute(() -> {
323+
// the variable has been removed
324+
assertThat(System.getenv("STAGE")).isNull();
325+
});
326+
```
327+
328+
The `remove` method deletes environment variables requested in the `EnvironmentVariables` object previously
329+
and also takes those environment variables out of the system environment while the `EnvironmentVariables`
330+
object is active.
331+
313332
### System Properties
314333

315334
#### With `SystemStubs`
@@ -333,6 +352,15 @@ void execute_code_that_manipulates_system_properties() throws Exception {
333352
}
334353
```
335354

355+
This also supports removing properties from the system properties:
356+
357+
```java
358+
// will be restored
359+
restoreSystemProperties(() ->{
360+
System.getProperties().remove("someProp");
361+
});
362+
```
363+
336364
#### With `SystemProperties`
337365

338366
A `SystemProperties` object allows you to set the system properties that will be provided
@@ -358,6 +386,16 @@ someProperties.execute(() -> {
358386
// here the system properties are reverted
359387
```
360388

389+
We can also specify properties to delete from the default system properties:
390+
391+
```java
392+
// when this object is active, some properties will be removed
393+
// from system properties
394+
SystemProperties someProperties = new SystemProperties()
395+
.remove("property1")
396+
.remove("property2");
397+
```
398+
361399
### Sources of `Properties` for `EnvironmentVariables` and `SystemProperties`
362400

363401
Once you have constructed an `EnvironmentVariables` or `SystemProperties` object, you can use the `set` method to apply properties. If these objects are presently _active_

system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/environment/EnvironmentVariableMocker.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,18 +64,25 @@ private static void installInterceptorIntoBootLoader(Instrumentation instrumenta
6464
instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(tempFile));
6565
}
6666

67+
@Deprecated(since = "2.1.5")
68+
public static void connect(Map<String, String> newEnvironmentVariables) {
69+
connect(newEnvironmentVariables, Collections.emptySet());
70+
}
71+
6772
/**
6873
* Attach a map as the mutable replacement environment variables for now. This can be done
6974
* multiple times and each time the replacement will supersede the maps before. Then when {@link #pop()}
7075
* is called, we'll rollback to the previous.
7176
* @param newEnvironmentVariables the mutable map - note: this will be populated by the current
7277
* environment
78+
* @param variablesToRemove a list of variables to take out of the resulting environment variables
7379
*/
74-
public static void connect(Map<String, String> newEnvironmentVariables) {
80+
public static void connect(Map<String, String> newEnvironmentVariables, Set<String> variablesToRemove) {
7581
// add all entries not already present in the new environment variables
7682
System.getenv().entrySet().stream()
7783
.filter(entry -> !newEnvironmentVariables.containsKey(entry.getKey()))
7884
.forEach(entry -> newEnvironmentVariables.put(entry.getKey(), entry.getValue()));
85+
variablesToRemove.forEach(newEnvironmentVariables::remove);
7986
REPLACEMENT_ENV.push(newEnvironmentVariables);
8087
ProcessEnvironmentInterceptor.setEnv(newEnvironmentVariables);
8188
}

system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/environment/EnvironmentVariables.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
import uk.org.webcompere.systemstubs.resource.SingularTestResource;
77

88
import java.nio.file.Path;
9-
import java.util.HashMap;
10-
import java.util.Map;
11-
import java.util.Properties;
9+
import java.util.*;
1210

1311
import static java.util.Collections.emptyMap;
1412
import static uk.org.webcompere.systemstubs.properties.PropertiesUtils.toStringMap;
@@ -35,7 +33,8 @@
3533
* @since 1.0.0
3634
*/
3735
public class EnvironmentVariables extends SingularTestResource implements NameValuePairSetter<EnvironmentVariables> {
38-
protected final Map<String, String> variables;
36+
private final Map<String, String> variables;
37+
private final Set<String> toRemove = new HashSet<>();
3938

4039
/**
4140
* Default constructor with an empty set of environment variables. Use {@link #set(String, String)} to
@@ -113,6 +112,14 @@ public EnvironmentVariables set(String name, String value) {
113112
return this;
114113
}
115114

115+
@Override
116+
public EnvironmentVariables remove(String name) {
117+
toRemove.add(name);
118+
variables.remove(name);
119+
120+
return this;
121+
}
122+
116123
/**
117124
* Return a copy of all the variables set for testing
118125
* @return a copy of the map
@@ -141,7 +148,7 @@ private String format(String text) {
141148

142149
@Override
143150
protected void doSetup() {
144-
EnvironmentVariableMocker.connect(variables);
151+
EnvironmentVariableMocker.connect(variables, toRemove);
145152
}
146153

147154
@Override
Lines changed: 4 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,23 @@
11
package uk.org.webcompere.systemstubs.properties;
22

3-
import uk.org.webcompere.systemstubs.resource.NameValuePairSetter;
4-
import uk.org.webcompere.systemstubs.resource.SingularTestResource;
5-
63
import java.util.Properties;
74

8-
import static java.lang.System.getProperties;
9-
import static java.lang.System.setProperties;
10-
115
/**
126
* Maintain system properties after a test from the ones before the test. Stores the
137
* existing properties when started, and restores them when complete. Allows for a list of properties
148
* that will be applied to the system to be set before the stubbing is triggered.
159
*/
16-
public class SystemProperties extends SingularTestResource implements NameValuePairSetter<SystemProperties> {
17-
private Properties originalProperties;
18-
private Properties properties;
10+
public class SystemProperties extends SystemPropertiesImpl<SystemProperties> {
1911

20-
/**
21-
* Default constructor with no properties. Use {@link #set} to set properties
22-
* either while active or before activation.
23-
* @since 1.0.0
24-
*/
2512
public SystemProperties() {
26-
this.properties = new Properties();
13+
super();
2714
}
2815

29-
/**
30-
* Construct with a specific set of properties.
31-
* @param properties properties to use
32-
* @since 1.0.0
33-
*/
3416
public SystemProperties(Properties properties) {
35-
this.properties = PropertiesUtils.copyOf(properties);
17+
super(properties);
3618
}
3719

38-
/**
39-
* Construct with a set of properties to apply when the object is active
40-
* @param name name of the first property
41-
* @param value value of the first property
42-
* @param nameValues pairs of names and values for further properties
43-
* @since 1.0.0
44-
*/
4520
public SystemProperties(String name, String value, String... nameValues) {
46-
this();
47-
if (nameValues.length % 2 != 0) {
48-
throw new IllegalArgumentException("Must have pairs of values");
49-
}
50-
properties.setProperty(name, value);
51-
for (int i = 0; i < nameValues.length; i += 2) {
52-
properties.setProperty(nameValues[i], nameValues[i + 1]);
53-
}
54-
}
55-
56-
/**
57-
* Set a system property. If active, this will set it with {@link System#setProperty(String, String)}.
58-
* If not active, then this will store the property to apply when this object is part of an execution.
59-
* It is also possible to use {@link System#setProperty(String, String)} while this object is active,
60-
* but when the execution finishes, this object will be unaware of the property set, so will not set
61-
* it next time.
62-
* @param name name of the property
63-
* @param value value to set
64-
* @return this object for fluent use
65-
* @since 1.0.0
66-
*/
67-
@Override
68-
public SystemProperties set(String name, String value) {
69-
properties.setProperty(name, value);
70-
if (isActive()) {
71-
System.setProperty(name, value);
72-
}
73-
return this;
74-
}
75-
76-
@Override
77-
protected void doSetup() throws Exception {
78-
originalProperties = getProperties();
79-
Properties copyProperties = PropertiesUtils.copyOf(originalProperties);
80-
copyProperties.putAll(properties);
81-
setProperties(copyProperties);
82-
}
83-
84-
@Override
85-
protected void doTeardown() throws Exception {
86-
setProperties(originalProperties);
21+
super(name, value, nameValues);
8722
}
8823
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package uk.org.webcompere.systemstubs.properties;
2+
3+
import uk.org.webcompere.systemstubs.resource.NameValuePairSetter;
4+
import uk.org.webcompere.systemstubs.resource.SingularTestResource;
5+
6+
import java.util.HashSet;
7+
import java.util.Properties;
8+
import java.util.Set;
9+
10+
import static java.lang.System.getProperties;
11+
import static java.lang.System.setProperties;
12+
13+
/**
14+
* Maintain system properties after a test from the ones before the test. Stores the
15+
* existing properties when started, and restores them when complete. Allows for a list of properties
16+
* that will be applied to the system to be set before the stubbing is triggered.
17+
*/
18+
public class SystemPropertiesImpl<T extends SystemPropertiesImpl<T>> extends SingularTestResource
19+
implements NameValuePairSetter<SystemPropertiesImpl<T>> {
20+
private Properties originalProperties;
21+
private Properties properties;
22+
23+
private Set<String> propertiesToRemove = new HashSet<>();
24+
25+
/**
26+
* Default constructor with no properties. Use {@link #set} to set properties
27+
* either while active or before activation.
28+
* @since 1.0.0
29+
*/
30+
public SystemPropertiesImpl() {
31+
this.properties = new Properties();
32+
}
33+
34+
/**
35+
* Construct with a specific set of properties.
36+
* @param properties properties to use
37+
* @since 1.0.0
38+
*/
39+
public SystemPropertiesImpl(Properties properties) {
40+
this.properties = PropertiesUtils.copyOf(properties);
41+
}
42+
43+
/**
44+
* Construct with a set of properties to apply when the object is active
45+
* @param name name of the first property
46+
* @param value value of the first property
47+
* @param nameValues pairs of names and values for further properties
48+
* @since 1.0.0
49+
*/
50+
public SystemPropertiesImpl(String name, String value, String... nameValues) {
51+
this();
52+
if (nameValues.length % 2 != 0) {
53+
throw new IllegalArgumentException("Must have pairs of values");
54+
}
55+
properties.setProperty(name, value);
56+
for (int i = 0; i < nameValues.length; i += 2) {
57+
properties.setProperty(nameValues[i], nameValues[i + 1]);
58+
}
59+
}
60+
61+
/**
62+
* Set a system property. If active, this will set it with {@link System#setProperty(String, String)}.
63+
* If not active, then this will store the property to apply when this object is part of an execution.
64+
* It is also possible to use {@link System#setProperty(String, String)} while this object is active,
65+
* but when the execution finishes, this object will be unaware of the property set, so will not set
66+
* it next time.
67+
* @param name name of the property
68+
* @param value value to set
69+
* @return this object for fluent use
70+
* @since 1.0.0
71+
*/
72+
@Override
73+
public SystemPropertiesImpl<T> set(String name, String value) {
74+
properties.setProperty(name, value);
75+
if (isActive()) {
76+
System.setProperty(name, value);
77+
}
78+
return this;
79+
}
80+
81+
/**
82+
* Remove a property - this removes it from system properties if active, and remembers to remove it
83+
* while the object is active
84+
* @param name the name of the property to remove
85+
* @return <code>this</code> for fluent use
86+
* @since 2.1.5
87+
*/
88+
@Override
89+
public SystemPropertiesImpl<T> remove(String name) {
90+
propertiesToRemove.add(name);
91+
if (isActive()) {
92+
System.getProperties().remove(name);
93+
}
94+
return this;
95+
}
96+
97+
@Override
98+
protected void doSetup() throws Exception {
99+
originalProperties = getProperties();
100+
Properties copyProperties = PropertiesUtils.copyOf(originalProperties);
101+
propertiesToRemove.forEach(copyProperties::remove);
102+
copyProperties.putAll(properties);
103+
setProperties(copyProperties);
104+
}
105+
106+
@Override
107+
protected void doTeardown() throws Exception {
108+
setProperties(originalProperties);
109+
}
110+
}

system-stubs-core/src/main/java/uk/org/webcompere/systemstubs/resource/NameValuePairSetter.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
* The general interface of something that can set name value pairs on itself
88
* @param <T> the final type of the class which provides this
99
*/
10-
@FunctionalInterface
11-
public interface NameValuePairSetter<T extends NameValuePairSetter> {
10+
public interface NameValuePairSetter<T extends NameValuePairSetter<T>> {
1211
/**
1312
* Set a name value pair
1413
* @param name the name
@@ -43,4 +42,11 @@ default T set(Map<Object, Object> properties) {
4342
properties.forEach((key, value) -> set(String.valueOf(key), String.valueOf(value)));
4443
return (T)this;
4544
}
45+
46+
/**
47+
* Remove one of the name value pairs
48+
* @param name the name
49+
* @return <code>this</code> for fluent calling
50+
*/
51+
T remove(String name);
4652
}

0 commit comments

Comments
 (0)