Skip to content

Commit f246cd3

Browse files
authored
[3.x] Proxy now properly selects proxy settings from system properties (helidon-io#6526)
Proxy now properly selects proxy settings from system properties Signed-off-by: David Kral <david.k.kral@oracle.com>
1 parent c0ccd9e commit f246cd3

17 files changed

Lines changed: 761 additions & 5 deletions

File tree

bom/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,11 @@
631631
<artifactId>helidon-common-crypto</artifactId>
632632
<version>${helidon.version}</version>
633633
</dependency>
634+
<dependency>
635+
<groupId>io.helidon.common.testing</groupId>
636+
<artifactId>helidon-common-testing-junit5</artifactId>
637+
<version>${helidon.version}</version>
638+
</dependency>
634639

635640
<!-- db client -->
636641
<dependency>

common/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,6 @@
4141
<module>mapper</module>
4242
<module>media-type</module>
4343
<module>crypto</module>
44+
<module>testing</module>
4445
</modules>
4546
</project>

common/testing/junit5/pom.xml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright (c) 2023 Oracle and/or its affiliates.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
18+
-->
19+
20+
<project xmlns="http://maven.apache.org/POM/4.0.0"
21+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
22+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
23+
<modelVersion>4.0.0</modelVersion>
24+
<parent>
25+
<groupId>io.helidon.common.testing</groupId>
26+
<artifactId>helidon-common-testing-project</artifactId>
27+
<version>3.2.1-SNAPSHOT</version>
28+
</parent>
29+
30+
<artifactId>helidon-common-testing-junit5</artifactId>
31+
<name>Helidon Common Testing JUnit5</name>
32+
33+
<dependencies>
34+
<dependency>
35+
<!-- this is to enforce order of compilation, so modules that use this as an annotation processor have it ready -->
36+
<groupId>io.helidon.config</groupId>
37+
<artifactId>helidon-config-metadata-processor</artifactId>
38+
<optional>true</optional>
39+
<scope>provided</scope>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.hamcrest</groupId>
43+
<artifactId>hamcrest-all</artifactId>
44+
<scope>provided</scope>
45+
</dependency>
46+
<dependency>
47+
<groupId>org.junit.jupiter</groupId>
48+
<artifactId>junit-jupiter-api</artifactId>
49+
<scope>provided</scope>
50+
</dependency>
51+
</dependencies>
52+
53+
<build>
54+
<plugins>
55+
<plugin>
56+
<groupId>org.apache.maven.plugins</groupId>
57+
<artifactId>maven-compiler-plugin</artifactId>
58+
<configuration>
59+
<compilerArgs>
60+
<!-- disable the processor we add for reactor -->
61+
<compilerArgument>-proc:none</compilerArgument>
62+
</compilerArgs>
63+
</configuration>
64+
</plugin>
65+
</plugins>
66+
</build>
67+
68+
</project>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright (c) 2023 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.helidon.common.testing.junit5;
17+
18+
import java.util.function.Supplier;
19+
20+
import org.hamcrest.Description;
21+
import org.hamcrest.Matcher;
22+
import org.hamcrest.StringDescription;
23+
24+
import static org.junit.jupiter.api.Assertions.fail;
25+
26+
/**
27+
* Hamcrest matcher capable of configured retries before failing the assertion, plus more generic retry processing.
28+
*/
29+
public class MatcherWithRetry {
30+
31+
private static final int RETRY_COUNT = Integer.getInteger("io.helidon.test.retryCount", 10);
32+
private static final int RETRY_DELAY_MS = Integer.getInteger("io.helidon.test.retryDelayMs", 500);
33+
34+
private MatcherWithRetry() {
35+
}
36+
37+
/**
38+
* Checks the matcher, possibly multiple times after configured delays, invoking the supplier of the matched value each time,
39+
* until either the matcher passes or the maximum retry expires.
40+
* @param reason explanation of the assertion
41+
* @param actualSupplier {@code Supplier} that furnishes the value to submit to the matcher
42+
* @param matcher Hamcrest matcher which evaluates the supplied value
43+
* @return the supplied value
44+
* @param <T> type of the supplied value
45+
*/
46+
public static <T> T assertThatWithRetry(String reason, Supplier<T> actualSupplier, Matcher<? super T> matcher) {
47+
48+
T actual = null;
49+
for (int i = 0; i < RETRY_COUNT; i++) {
50+
actual = actualSupplier.get();
51+
if (matcher.matches(actual)) {
52+
return actual;
53+
}
54+
try {
55+
Thread.sleep(RETRY_DELAY_MS);
56+
} catch (InterruptedException e) {
57+
fail("Error sleeping during assertThatWithRetry", e);
58+
}
59+
}
60+
61+
Description description = new StringDescription();
62+
description.appendText(reason)
63+
.appendText("\nExpected: ")
64+
.appendDescriptionOf(matcher)
65+
.appendText("\n but: ");
66+
matcher.describeMismatch(actual, description);
67+
68+
throw new AssertionError(description.toString());
69+
}
70+
71+
/**
72+
* Checks the matcher, possibly multiple times after configured delays, invoking the supplier of the matched value each time,
73+
* until either the matcher passes or the maximum retry expires.
74+
* @param actualSupplier {@code Supplier} that furnishes the value to submit to the matcher
75+
* @param matcher Hamcrest matcher which evaluates the supplied value
76+
* @return the supplied value
77+
* @param <T> type of the supplied value
78+
*/
79+
public static <T> T assertThatWithRetry(Supplier<T> actualSupplier, Matcher<? super T> matcher) {
80+
return assertThatWithRetry("", actualSupplier, matcher);
81+
}
82+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright (c) 2023 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.helidon.common.testing.junit5;
17+
18+
import java.util.Optional;
19+
20+
import org.hamcrest.Description;
21+
import org.hamcrest.Matcher;
22+
import org.hamcrest.TypeSafeMatcher;
23+
24+
import static org.hamcrest.Matchers.any;
25+
26+
/**
27+
* Hamcrest matchers for {@link Optional}.
28+
*/
29+
public final class OptionalMatcher {
30+
private OptionalMatcher() {
31+
}
32+
33+
/**
34+
* A matcher for an {@link Optional} that checks it is
35+
* present, and that the value matches the provided matcher.
36+
* <p>
37+
* Usage example:
38+
* <pre>
39+
* assertThat(myOptional, optionalValue(is("expected")));
40+
* </pre>
41+
* @param matcher matcher to validate the content of the optional
42+
* @param <T> type of the value
43+
* @return matcher validating the {@link Optional} is present and matches the provided matcher
44+
*/
45+
public static <T> Matcher<Optional<T>> optionalValue(Matcher<? super T> matcher) {
46+
return new WithValue<>(matcher);
47+
}
48+
49+
/**
50+
* A matcher for an {@link Optional} that checks it is empty.
51+
* <p>
52+
* Usage example:
53+
* <pre>
54+
* assertThat(myOptional, optionalEmpty());
55+
* </pre>
56+
* @param <T> type of the optional
57+
* @return matcher validating the {@link Optional} is empty
58+
*/
59+
public static <T> Matcher<Optional<T>> optionalEmpty() {
60+
return new Empty<>();
61+
}
62+
63+
/**
64+
* A matcher for an {@link Optional} that checks it is
65+
* present.
66+
* <p>
67+
* Usage example:
68+
* <pre>
69+
* assertThat(myOptional, optionalPresent());
70+
* </pre>
71+
* @param <T> type of the value
72+
* @return matcher validating the {@link Optional} is present
73+
*/
74+
public static <T> Matcher<Optional<T>> optionalPresent() {
75+
return new WithValue<>(any(Object.class));
76+
}
77+
78+
private static class Empty<T> extends TypeSafeMatcher<Optional<T>> {
79+
@Override
80+
protected boolean matchesSafely(Optional<T> item) {
81+
return item.isEmpty();
82+
}
83+
84+
@Override
85+
public void describeTo(Description description) {
86+
description.appendText("empty Optional");
87+
}
88+
89+
@Override
90+
protected void describeMismatchSafely(Optional<T> item, Description mismatchDescription) {
91+
if (item.isPresent()) {
92+
mismatchDescription.appendText("not empty Optional, and value is ");
93+
mismatchDescription.appendValue(item.get());
94+
}
95+
}
96+
}
97+
98+
private static class WithValue<T> extends TypeSafeMatcher<Optional<T>> {
99+
private final Matcher<? super T> matcher;
100+
101+
WithValue(Matcher<? super T> matcher) {
102+
this.matcher = matcher;
103+
}
104+
105+
@Override
106+
protected boolean matchesSafely(Optional<T> item) {
107+
return item.map(matcher::matches)
108+
.orElse(false);
109+
}
110+
111+
@Override
112+
public void describeTo(Description description) {
113+
description.appendText("not empty Optional, and value ");
114+
description.appendDescriptionOf(matcher);
115+
}
116+
117+
@Override
118+
protected void describeMismatchSafely(Optional<T> item, Description mismatchDescription) {
119+
if (item.isPresent()) {
120+
mismatchDescription.appendText("not empty Optional, and value ");
121+
matcher.describeMismatch(item.get(), mismatchDescription);
122+
} else {
123+
mismatchDescription.appendText("is empty");
124+
}
125+
}
126+
}
127+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2023 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.helidon.common.testing.junit5;
18+
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
import org.junit.jupiter.api.extension.ExtendWith;
25+
26+
/**
27+
* Annotation used to reset system properties to the state before test execution.
28+
*/
29+
@Retention(RetentionPolicy.RUNTIME)
30+
@Target(ElementType.METHOD)
31+
@ExtendWith(RestoreSystemPropertiesExt.class)
32+
public @interface ResetSystemProperties {
33+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2023 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.helidon.common.testing.junit5;
18+
19+
import java.util.Properties;
20+
21+
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
22+
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
23+
import org.junit.jupiter.api.extension.ExtensionContext;
24+
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
25+
import org.junit.jupiter.api.extension.ExtensionContext.Store;
26+
27+
/**
28+
* JUnit 5 extension for preserving and restoring system properties around
29+
* test executions.
30+
* <p>
31+
* Annotate each test method that modifies system properties using
32+
* <code>@ExtendWith(RestoreSystemPropertiesExt.class)</code>
33+
*
34+
*/
35+
public class RestoreSystemPropertiesExt implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
36+
37+
private static final String SYSPROPS_KEY = "systemProps";
38+
39+
@Override
40+
public void beforeTestExecution(ExtensionContext ec) throws Exception {
41+
getStore(ec).put(SYSPROPS_KEY, System.getProperties());
42+
Properties copy = new Properties();
43+
copy.putAll(System.getProperties());
44+
System.setProperties(copy);
45+
}
46+
47+
@Override
48+
public void afterTestExecution(ExtensionContext ec) throws Exception {
49+
System.setProperties(getSavedProps(ec));
50+
}
51+
52+
private Store getStore(ExtensionContext context) {
53+
return context.getStore(Namespace.create(getClass(), context.getRequiredTestMethod()));
54+
}
55+
56+
private Properties getSavedProps(ExtensionContext ec) throws Exception {
57+
Object o = getStore(ec).get(SYSPROPS_KEY);
58+
return Properties.class.cast(o);
59+
}
60+
}

0 commit comments

Comments
 (0)