|
@@ -33,6 +33,7 @@ import static org.hamcrest.Matchers.hasItem;
|
|
|
import static org.hamcrest.Matchers.hasSize;
|
|
|
import static org.hamcrest.Matchers.instanceOf;
|
|
|
import static org.hamcrest.Matchers.not;
|
|
|
+import static org.hamcrest.Matchers.nullValue;
|
|
|
import static org.hamcrest.Matchers.sameInstance;
|
|
|
|
|
|
public class ThreadContextTests extends ESTestCase {
|
|
@@ -73,7 +74,8 @@ public class ThreadContextTests extends ESTestCase {
|
|
|
// foo is the only existing transient header that is cleared
|
|
|
try (
|
|
|
ThreadContext.StoredContext stashed = threadContext.newStoredContext(
|
|
|
- randomFrom(List.of("foo", "foo"), List.of("foo"), List.of("foo", "acme"))
|
|
|
+ randomFrom(List.of("foo", "foo"), List.of("foo"), List.of("foo", "acme")),
|
|
|
+ List.of()
|
|
|
)
|
|
|
) {
|
|
|
// only the requested transient header is cleared
|
|
@@ -113,7 +115,8 @@ public class ThreadContextTests extends ESTestCase {
|
|
|
// test stashed missing header stays missing
|
|
|
try (
|
|
|
ThreadContext.StoredContext stashed = threadContext.newStoredContext(
|
|
|
- randomFrom(Arrays.asList("acme", "acme"), Arrays.asList("acme"))
|
|
|
+ randomFrom(Arrays.asList("acme", "acme"), Arrays.asList("acme")),
|
|
|
+ List.of()
|
|
|
)
|
|
|
) {
|
|
|
assertNull(threadContext.getTransient("acme"));
|
|
@@ -122,6 +125,284 @@ public class ThreadContextTests extends ESTestCase {
|
|
|
assertNull(threadContext.getTransient("acme"));
|
|
|
}
|
|
|
|
|
|
+ public void testNewContextWithClearedRequestHeaders() {
|
|
|
+ ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
|
|
+
|
|
|
+ final Map<String, String> requestHeaders = Map.ofEntries(
|
|
|
+ Map.entry(randomAlphaOfLengthBetween(3, 8), randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry(Task.X_OPAQUE_ID_HTTP_HEADER, randomAlphaOfLength(10)),
|
|
|
+ Map.entry(Task.TRACE_ID, randomAlphaOfLength(20)),
|
|
|
+ Map.entry("_username", "elastic-admin")
|
|
|
+ );
|
|
|
+ threadContext.putHeader(requestHeaders);
|
|
|
+
|
|
|
+ final Map<String, Object> transientHeaders = Map.ofEntries(
|
|
|
+ Map.entry(randomAlphaOfLengthBetween(3, 8), randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry("_random", randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry("_map", Map.of("key", new Object())),
|
|
|
+ Map.entry("_address", "125.124.123.122"),
|
|
|
+ Map.entry("_object", new Object()),
|
|
|
+ Map.entry("_number", 42)
|
|
|
+ );
|
|
|
+ transientHeaders.forEach((k, v) -> threadContext.putTransient(k, v));
|
|
|
+
|
|
|
+ final Map<String, String> responseHeaders = Map.ofEntries(
|
|
|
+ Map.entry(randomAlphaOfLengthBetween(3, 6), randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry("_response_message", "All good."),
|
|
|
+ Map.entry("Warning", "Some warning!")
|
|
|
+ );
|
|
|
+ responseHeaders.forEach((k, v) -> threadContext.addResponseHeader(k, v));
|
|
|
+
|
|
|
+ // this is missing or null
|
|
|
+ if (randomBoolean()) {
|
|
|
+ threadContext.putHeader("_missing_or_null", null);
|
|
|
+ }
|
|
|
+
|
|
|
+ // mark as system context
|
|
|
+ boolean setSystemContext = randomBoolean();
|
|
|
+ if (setSystemContext) {
|
|
|
+ threadContext.markAsSystemContext();
|
|
|
+ }
|
|
|
+
|
|
|
+ // adding password header here to simplify assertions
|
|
|
+ threadContext.putHeader("_password", "elastic-password");
|
|
|
+
|
|
|
+ // password is the only request header that should be cleared
|
|
|
+ try (
|
|
|
+ ThreadContext.StoredContext stashed = threadContext.newStoredContext(
|
|
|
+ List.of(),
|
|
|
+ randomFrom(List.of("_password", "_password"), List.of("_password"), List.of("_password", "_missing_or_null"))
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ // only the requested header is cleared
|
|
|
+ assertThat(threadContext.getHeader("_password"), nullValue());
|
|
|
+ // system context boolean is preserved
|
|
|
+ assertThat(threadContext.isSystemContext(), equalTo(setSystemContext));
|
|
|
+ // missing header is still missing
|
|
|
+ assertThat(threadContext.getHeader("_missing_or_null"), nullValue());
|
|
|
+ // other headers are preserved
|
|
|
+ requestHeaders.forEach((k, v) -> assertThat(threadContext.getHeader(k), equalTo(v)));
|
|
|
+ transientHeaders.forEach((k, v) -> assertThat(threadContext.getTransient(k), equalTo(v)));
|
|
|
+ responseHeaders.forEach((k, v) -> assertThat(threadContext.getResponseHeaders().get(k).get(0), equalTo(v)));
|
|
|
+ // warning header count is still equal to 1
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").size(), equalTo(1));
|
|
|
+
|
|
|
+ // try override stashed header
|
|
|
+ threadContext.putHeader("_password", "new-password");
|
|
|
+ assertThat(threadContext.getHeader("_password"), equalTo("new-password"));
|
|
|
+ // add new headers
|
|
|
+ threadContext.addResponseHeader("_new_response_header", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ threadContext.putTransient("_new_transient_header", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ threadContext.putHeader("_new_request_header", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ threadContext.addResponseHeader("Warning", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ // warning header is now equal to 2
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").size(), equalTo(2));
|
|
|
+ }
|
|
|
+
|
|
|
+ // original "password" header is restored (it is not overridden)
|
|
|
+ assertThat(threadContext.getHeader("_password"), equalTo("elastic-password"));
|
|
|
+ // headers added inside the stash are NOT preserved
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("_new_response_header"), nullValue());
|
|
|
+ assertThat(threadContext.getTransient("_new_transient_header"), nullValue());
|
|
|
+ assertThat(threadContext.getHeader("_new_request_header"), nullValue());
|
|
|
+ // warning header is restored to 1
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").size(), equalTo(1));
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").get(0), equalTo("Some warning!"));
|
|
|
+ // original headers are restored
|
|
|
+ requestHeaders.forEach((k, v) -> assertThat(threadContext.getHeader(k), equalTo(v)));
|
|
|
+ transientHeaders.forEach((k, v) -> assertThat(threadContext.getTransient(k), equalTo(v)));
|
|
|
+ responseHeaders.forEach((k, v) -> assertThat(threadContext.getResponseHeaders().get(k).get(0), equalTo(v)));
|
|
|
+ // system context boolean is unchanged
|
|
|
+ assertThat(threadContext.isSystemContext(), equalTo(setSystemContext));
|
|
|
+
|
|
|
+ // test stashed missing header stays missing
|
|
|
+ try (
|
|
|
+ ThreadContext.StoredContext stashed = threadContext.newStoredContext(
|
|
|
+ randomFrom(Arrays.asList("_missing_or_null", "_missing_or_null"), Arrays.asList("_missing_or_null")),
|
|
|
+ List.of()
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ assertThat(threadContext.getHeader("_missing_or_null"), nullValue());
|
|
|
+ threadContext.putHeader("_missing_or_null", "not_null");
|
|
|
+ }
|
|
|
+ assertThat(threadContext.getHeader("_missing_or_null"), nullValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testNewContextWithoutClearingTransientAndRequestHeaders() {
|
|
|
+ ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
|
|
+
|
|
|
+ final Map<String, String> requestHeaders = Map.ofEntries(
|
|
|
+ Map.entry(randomAlphaOfLengthBetween(3, 8), randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry(Task.X_OPAQUE_ID_HTTP_HEADER, randomAlphaOfLength(10)),
|
|
|
+ Map.entry(Task.TRACE_ID, randomAlphaOfLength(20)),
|
|
|
+ Map.entry("_username", "elastic-admin")
|
|
|
+ );
|
|
|
+ threadContext.putHeader(requestHeaders);
|
|
|
+
|
|
|
+ final Map<String, Object> transientHeaders = Map.ofEntries(
|
|
|
+ Map.entry(randomAlphaOfLengthBetween(3, 8), randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry("_random", randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry("_map", Map.of("key", new Object())),
|
|
|
+ Map.entry("_address", "125.124.123.122"),
|
|
|
+ Map.entry("_object", new Object()),
|
|
|
+ Map.entry("_number", 42)
|
|
|
+ );
|
|
|
+ transientHeaders.forEach((k, v) -> threadContext.putTransient(k, v));
|
|
|
+
|
|
|
+ final Map<String, String> responseHeaders = Map.ofEntries(
|
|
|
+ Map.entry(randomAlphaOfLengthBetween(3, 6), randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry("_response_message", "All good."),
|
|
|
+ Map.entry("Warning", "Some warning!")
|
|
|
+ );
|
|
|
+ responseHeaders.forEach((k, v) -> threadContext.addResponseHeader(k, v));
|
|
|
+
|
|
|
+ // mark as system context
|
|
|
+ boolean setSystemContext = randomBoolean();
|
|
|
+ if (setSystemContext) {
|
|
|
+ threadContext.markAsSystemContext();
|
|
|
+ }
|
|
|
+
|
|
|
+ // test nothing is cleared when empty collections are passed
|
|
|
+ try (ThreadContext.StoredContext stashed = threadContext.newStoredContext(List.of(), List.of())) {
|
|
|
+ // system context boolean is preserved
|
|
|
+ assertThat(threadContext.isSystemContext(), equalTo(setSystemContext));
|
|
|
+ // other headers are preserved
|
|
|
+ assertThat(threadContext.getHeaders().size(), equalTo(requestHeaders.size()));
|
|
|
+ assertThat(threadContext.getResponseHeaders().size(), equalTo(responseHeaders.size()));
|
|
|
+ assertThat(threadContext.getTransientHeaders().size(), equalTo(transientHeaders.size()));
|
|
|
+ requestHeaders.forEach((k, v) -> assertThat(threadContext.getHeader(k), equalTo(v)));
|
|
|
+ transientHeaders.forEach((k, v) -> assertThat(threadContext.getTransient(k), equalTo(v)));
|
|
|
+ responseHeaders.forEach((k, v) -> assertThat(threadContext.getResponseHeaders().get(k).get(0), equalTo(v)));
|
|
|
+ // warning header count is still equal to 1
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").size(), equalTo(1));
|
|
|
+ // add new headers
|
|
|
+ threadContext.addResponseHeader("_new_response_header", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ threadContext.putTransient("_new_transient_header", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ threadContext.putHeader("_new_request_header", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ threadContext.addResponseHeader("Warning", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ // warning header is now equal to 2
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").size(), equalTo(2));
|
|
|
+ }
|
|
|
+
|
|
|
+ // headers added inside the stash are NOT preserved
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("_new_response_header"), nullValue());
|
|
|
+ assertThat(threadContext.getTransient("_new_transient_header"), nullValue());
|
|
|
+ assertThat(threadContext.getHeader("_new_request_header"), nullValue());
|
|
|
+ // original headers are unchanged
|
|
|
+ assertThat(threadContext.getHeaders().size(), equalTo(requestHeaders.size()));
|
|
|
+ assertThat(threadContext.getResponseHeaders().size(), equalTo(responseHeaders.size()));
|
|
|
+ assertThat(threadContext.getTransientHeaders().size(), equalTo(transientHeaders.size()));
|
|
|
+ requestHeaders.forEach((k, v) -> assertThat(threadContext.getHeader(k), equalTo(v)));
|
|
|
+ transientHeaders.forEach((k, v) -> assertThat(threadContext.getTransient(k), equalTo(v)));
|
|
|
+ responseHeaders.forEach((k, v) -> assertThat(threadContext.getResponseHeaders().get(k).get(0), equalTo(v)));
|
|
|
+ // system context boolean is unchanged
|
|
|
+ assertThat(threadContext.isSystemContext(), equalTo(setSystemContext));
|
|
|
+ // warning header is unchanged
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").size(), equalTo(1));
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").get(0), equalTo("Some warning!"));
|
|
|
+ }
|
|
|
+
|
|
|
+ public void testNewContextPreservingResponseHeadersWithClearedTransientAndRequestHeaders() {
|
|
|
+ ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
|
|
+
|
|
|
+ final Map<String, String> requestHeaders = Map.ofEntries(
|
|
|
+ Map.entry(randomAlphaOfLengthBetween(3, 8), randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry(Task.X_OPAQUE_ID_HTTP_HEADER, randomAlphaOfLength(10)),
|
|
|
+ Map.entry(Task.TRACE_ID, randomAlphaOfLength(20)),
|
|
|
+ Map.entry("_username", "elastic-admin")
|
|
|
+ );
|
|
|
+ threadContext.putHeader(requestHeaders);
|
|
|
+
|
|
|
+ final Map<String, Object> transientHeaders = Map.ofEntries(
|
|
|
+ Map.entry(randomAlphaOfLengthBetween(3, 8), randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry("_random", randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry("_map", Map.of("key", new Object())),
|
|
|
+ Map.entry("_address", "125.124.123.122"),
|
|
|
+ Map.entry("_object", new Object()),
|
|
|
+ Map.entry("_number", 42)
|
|
|
+ );
|
|
|
+ transientHeaders.forEach((k, v) -> threadContext.putTransient(k, v));
|
|
|
+
|
|
|
+ final Map<String, String> responseHeaders = Map.ofEntries(
|
|
|
+ Map.entry(randomAlphaOfLengthBetween(3, 6), randomAlphaOfLengthBetween(3, 8)),
|
|
|
+ Map.entry("_response_message", "All good."),
|
|
|
+ Map.entry("Warning", "Some warning!")
|
|
|
+ );
|
|
|
+ responseHeaders.forEach((k, v) -> threadContext.addResponseHeader(k, v));
|
|
|
+
|
|
|
+ // this is missing or null
|
|
|
+ if (randomBoolean()) {
|
|
|
+ threadContext.putHeader("_missing_or_null", null);
|
|
|
+ threadContext.putTransient("_missing_or_null", null);
|
|
|
+ }
|
|
|
+
|
|
|
+ // mark as system context
|
|
|
+ boolean setSystemContext = randomBoolean();
|
|
|
+ if (setSystemContext) {
|
|
|
+ threadContext.markAsSystemContext();
|
|
|
+ }
|
|
|
+
|
|
|
+ // adding request and transient headers to be cleared later
|
|
|
+ threadContext.putHeader("_password", "elastic-password");
|
|
|
+ threadContext.putTransient("_transient_to_be_cleared", "original-transient-value");
|
|
|
+
|
|
|
+ // password is the only request header that should be cleared
|
|
|
+ try (
|
|
|
+ ThreadContext.StoredContext stashed = threadContext.newStoredContextPreservingResponseHeaders(
|
|
|
+ randomFrom(
|
|
|
+ List.of("_transient_to_be_cleared"),
|
|
|
+ List.of("_transient_to_be_cleared", "_transient_to_be_cleared"),
|
|
|
+ List.of("_transient_to_be_cleared", "_missing_or_null")
|
|
|
+ ),
|
|
|
+ randomFrom(List.of("_password", "_password"), List.of("_password"), List.of("_password", "_missing_or_null"))
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ // only the requested headers are cleared
|
|
|
+ assertThat(threadContext.getHeader("_password"), nullValue());
|
|
|
+ assertThat(threadContext.getTransient("_transient_to_be_cleared"), nullValue());
|
|
|
+ // system context boolean is preserved
|
|
|
+ assertThat(threadContext.isSystemContext(), equalTo(setSystemContext));
|
|
|
+ // missing header is still missing
|
|
|
+ assertThat(threadContext.getHeader("_missing_or_null"), nullValue());
|
|
|
+ assertThat(threadContext.getTransient("_missing_or_null"), nullValue());
|
|
|
+ // other headers are preserved
|
|
|
+ requestHeaders.forEach((k, v) -> assertThat(threadContext.getHeader(k), equalTo(v)));
|
|
|
+ transientHeaders.forEach((k, v) -> assertThat(threadContext.getTransient(k), equalTo(v)));
|
|
|
+ responseHeaders.forEach((k, v) -> assertThat(threadContext.getResponseHeaders().get(k).get(0), equalTo(v)));
|
|
|
+ // warning header count is still equal to 1
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").size(), equalTo(1));
|
|
|
+
|
|
|
+ // try override stashed headers
|
|
|
+ threadContext.putHeader("_password", "new-password");
|
|
|
+ threadContext.putTransient("_transient_to_be_cleared", "new-transient-value");
|
|
|
+ assertThat(threadContext.getHeader("_password"), equalTo("new-password"));
|
|
|
+ assertThat(threadContext.getTransient("_transient_to_be_cleared"), equalTo("new-transient-value"));
|
|
|
+ // add new headers
|
|
|
+ threadContext.addResponseHeader("_new_response_header", "value-which-should-be-preserved");
|
|
|
+ threadContext.putTransient("_new_transient_header", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ threadContext.putHeader("_new_request_header", randomAlphaOfLengthBetween(3, 8));
|
|
|
+ threadContext.addResponseHeader("Warning", "Another warning!");
|
|
|
+ // warning header is now equal to 2
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").size(), equalTo(2));
|
|
|
+ }
|
|
|
+
|
|
|
+ // originally cleared headers should be restored (and not overridden)
|
|
|
+ assertThat(threadContext.getHeader("_password"), equalTo("elastic-password"));
|
|
|
+ assertThat(threadContext.getTransient("_transient_to_be_cleared"), equalTo("original-transient-value"));
|
|
|
+ requestHeaders.forEach((k, v) -> assertThat(threadContext.getHeader(k), equalTo(v)));
|
|
|
+ transientHeaders.forEach((k, v) -> assertThat(threadContext.getTransient(k), equalTo(v)));
|
|
|
+ // headers added inside the stash are NOT preserved
|
|
|
+ assertThat(threadContext.getTransient("_new_transient_header"), nullValue());
|
|
|
+ assertThat(threadContext.getHeader("_new_request_header"), nullValue());
|
|
|
+ // except for response headers which should be preserved
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("_new_response_header").get(0), equalTo("value-which-should-be-preserved"));
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").size(), equalTo(2));
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").get(0), equalTo("Some warning!"));
|
|
|
+ assertThat(threadContext.getResponseHeaders().get("Warning").get(1), equalTo("Another warning!"));
|
|
|
+ // system context boolean is unchanged
|
|
|
+ assertThat(threadContext.isSystemContext(), equalTo(setSystemContext));
|
|
|
+ }
|
|
|
+
|
|
|
public void testStashWithOrigin() {
|
|
|
final String origin = randomAlphaOfLengthBetween(4, 16);
|
|
|
final ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|