Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ Stream<DynamicTest> uriNamesTheHttpsScheme() {
assertEquals("hello", get(imp, Optional.empty()).body());
assertEquals("https", rift.imposter(imp.port()).orElseThrow().uri().getScheme(),
"a lookup must report the scheme too");
// rift 0.24.0 prints "ca": null on an https imposter without one (rift#1576, #341).
assertEquals(Optional.empty(), imp.definition().ca(), "definition() reads the engine's https view");
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
* every client). The model validates no combination of them, so it can read whatever an engine or a
* fixture holds; rift refuses the combinations that cannot take effect when the imposter is created.
* {@code ImposterSpec.requireClientCertificate} builds only the two it accepts.
* A {@code ca} of JSON {@code null}, which rift 0.24.0 and Mountebank print on an https imposter
* without one, reads as absent and is not written back. {@code ciphers}, which the engine keeps but
* does not apply, is not modeled and rides {@link #extra()} unchanged.
*
* <p>{@code enabled} is {@code false} for an imposter that holds its port and stubs but answers no
* traffic. The engine writes the key only when it is {@code false}, and so does this codec; absent
Expand Down Expand Up @@ -197,7 +200,8 @@ static ImposterDefinition read(JsonObject obj) {
Optional.ofNullable(obj.get("_rift")).map(v -> RiftConfig.read(JsonSupport.requireObject(v, "_rift"))),
JsonSupport.optBool(obj, "mutualAuth", false),
JsonSupport.optBool(obj, "rejectUnauthorized", false),
Optional.ofNullable(obj.get("ca")).map(CaCertificates::read),
// rift 0.24.0 and Mountebank print "ca": null on an https imposter without one (rift#1576).
Optional.ofNullable(obj.get("ca")).filter(ca -> !(ca instanceof JsonNull)).map(CaCertificates::read),
JsonSupport.optBool(obj, "enabled", true),
JsonSupport.extraFields(obj, MODELED_KEYS));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.achirdlabs.rift.model;

import io.github.achirdlabs.rift.json.JsonNumber;
import io.github.achirdlabs.rift.json.JsonString;
import io.github.achirdlabs.rift.json.JsonValue;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -64,6 +65,48 @@ void anEmptyCaArrayIsKeptRatherThanDropped() {
assertEquals(JsonValue.parse(json), JsonValue.parse(def.toJson()));
}

/** rift 0.24.0's {@code ?replayable=true} export of an https imposter, verbatim (rift#1576). */
private static final String ENGINE_024_HTTPS_EXPORT = """
{"port": 24501, "protocol": "https", "ciphers": "ECDHE-RSA-AES128-GCM-SHA256", "recordRequests": false,
"stubs": [{"responses": [{"is": {"statusCode": 200}}]}],
"mutualAuth": false, "rejectUnauthorized": false, "ca": null}
""";

@Test
void aNullCaReadsAsAbsent() {
ImposterDefinition def = ImposterDefinition.fromJson(ENGINE_024_HTTPS_EXPORT);
assertEquals(Optional.empty(), def.ca());
assertFalse(def.mutualAuth());
assertFalse(def.rejectUnauthorized());
assertEquals(Map.of("ciphers", new JsonString("ECDHE-RSA-AES128-GCM-SHA256")), def.extra(),
"ciphers is not modeled, so it rides extra unchanged");
}

@Test
void aNullCaIsNotWrittenBackAndCiphersIs() {
// null and absent mean the same to every engine and to Mountebank, so the write omits it.
assertEquals(JsonValue.parse("""
{"port": 24501, "protocol": "https",
"stubs": [{"predicates": [], "responses": [{"is": {"statusCode": "200"}}]}],
"ciphers": "ECDHE-RSA-AES128-GCM-SHA256"}
"""), JsonValue.parse(ImposterDefinition.fromJson(ENGINE_024_HTTPS_EXPORT).toJson()));
}

@Test
void aWholeExportWithANullCaParses() {
ImposterDefinitions defs = ImposterDefinitions.fromJson("{\"imposters\": [" + ENGINE_024_HTTPS_EXPORT
+ ", {\"port\": 24502, \"protocol\": \"http\", \"stubs\": []}]}");
assertEquals(List.of(24501, 24502), defs.imposters().stream().map(d -> d.port().orElseThrow()).toList());
assertEquals(Optional.empty(), defs.imposters().get(0).ca());
}

@Test
void aCaOfAnotherTypeIsStillRefused() {
assertThrows(WireFormatException.class, () -> ImposterDefinition.fromJson("""
{"protocol": "https", "ca": 5, "stubs": []}
"""));
}

@Test
void combinationsTheEngineRefusesStillParse() {
// Valid Mountebank, refused by rift 0.18.0 at creation: the model reads it and writes it back.
Expand Down
Loading