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
2 changes: 1 addition & 1 deletion .mex/context/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ mex:

# HTTP transport boundary

The HTTP transport uses pinned TLS and enrollment; certificate binding authenticates peers, while the envelopes are strictly parsed but not independently signed. Proxy-to-backend outgoing messages are durably queued, and both sides have durable inbound replay fences. Backend-to-proxy outgoing messages remain in memory with a bounded shutdown flush. A network response, queue write, and application acknowledgement are different events. A valid nonempty queue directory reports pending work; invalid or inaccessible queue structure throws `IOException`, which callers must handle conservatively. A restart-visible `RUNNING` callback is neither replayed nor acknowledged because its side effects are uncertain. Source: `SimpleAPI/src/main/java/com/bencodez/simpleapi/servercomm/http/`, `SimpleAPI/src/test/java/com/bencodez/simpleapi/servercomm/http/`.
The HTTP transport uses pinned TLS and enrollment; certificate binding authenticates peers, while the envelopes are strictly parsed but not independently signed. Proxy-to-backend outgoing messages are durably queued, and both sides have durable inbound replay fences. Backend-to-proxy outgoing messages remain in memory with a bounded shutdown flush. A network response, queue write, and application acknowledgement are different events. A valid nonempty queue directory reports pending work; invalid or inaccessible queue structure throws `IOException`, which callers must handle conservatively. A restart-visible `RUNNING` callback is neither replayed nor acknowledged because its side effects are uncertain. Source: `SimpleAPI/src/main/java/com/bencodez/simpleapi/servercomm/http/`, `SimpleAPI/src/test/java/com/bencodez/simpleapi/tests/servercomm/http/`.

Transport work must keep size bounds, shutdown behavior, and authentication checks together. Inspect current tests for the exact guarantee instead of inferring exactly-once behavior from a queue name.
2 changes: 1 addition & 1 deletion .mex/patterns/http-transport-change.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ mex:

# HTTP transport change

Map enqueue, persisted state, send, acknowledgement, restart recovery, and unreadable state before changing completion semantics. Keep TLS/enrollment and bounded execution checks in the same review. See `context/http.md` and current tests under `SimpleAPI/src/test/java/com/bencodez/simpleapi/servercomm/http/`.
Map enqueue, persisted state, send, acknowledgement, restart recovery, and unreadable state before changing completion semantics. Keep TLS/enrollment and bounded execution checks in the same review. See `context/http.md` and current tests under `SimpleAPI/src/test/java/com/bencodez/simpleapi/tests/servercomm/http/`.
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ mvn -B -f SimpleAPI/pom.xml test
mvn -B -f SimpleAPI/pom.xml package
```

All test classes and test-only helpers belong under `com.bencodez.simpleapi.tests` (or its subpackages), with matching paths under `SimpleAPI/src/test/java/com/bencodez/simpleapi/tests/`. Keep production package names and visibility unchanged when organizing tests; use narrowly scoped test-only reflection access where an existing test needs implementation internals. Preserve test discovery and both full/shared artifact checks when moving tests.

Confirm current CI and POM settings before relying on these commands. Verify that the package invocation produced both the legacy/full artifact and every configured classifier, especially the `shared` JAR. Run `git diff --check` and confirm tests actually ran.

## Packaging boundaries
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package com.bencodez.simpleapi.build;
package com.bencodez.simpleapi.tests.build;



import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package com.bencodez.simpleapi.core;
package com.bencodez.simpleapi.tests.core;



import static org.junit.jupiter.api.Assertions.*;
import java.net.URLClassLoader;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package com.bencodez.simpleapi.file;
package com.bencodez.simpleapi.tests.file;

import com.bencodez.simpleapi.file.PrivateFilePermissions;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package com.bencodez.simpleapi.file.config.configurate;
package com.bencodez.simpleapi.tests.file.config.configurate;

import com.bencodez.simpleapi.file.config.configurate.ConfigurateConfigView;

import static org.junit.jupiter.api.Assertions.*;
import java.util.ArrayList;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
package com.bencodez.simpleapi.file.config.configurate;
package com.bencodez.simpleapi.tests.file.config.configurate;

import com.bencodez.simpleapi.file.config.configurate.ConfigurateConfigView;
import com.bencodez.simpleapi.file.config.configurate.YamlConfigDocument;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import com.bencodez.simpleapi.servercomm.http.PackagedTlsSmoke;
import com.bencodez.simpleapi.tests.servercomm.http.PackagedTlsSmoke;

/** Package-phase checks: Maven's dependency classpath must not mask missing shaded classes. */
public class FullArtifactTest {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
package com.bencodez.simpleapi.servercomm.http;
package com.bencodez.simpleapi.tests.servercomm.http;

import com.bencodez.simpleapi.servercomm.http.HttpBackendTransportConnector;
import com.bencodez.simpleapi.servercomm.http.HttpClientCredentialStore;
import com.bencodez.simpleapi.servercomm.http.HttpConnectionCode;
import com.bencodez.simpleapi.servercomm.http.HttpTlsIdentity;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
Expand Down Expand Up @@ -33,20 +38,20 @@ void callbackOwnedCloseCompletesItsJournalBeforeAsynchronousSealing() throws Exc
callbackReturned.countDown();
}));
String id = UUID.randomUUID().toString();
connector.get().dispatch(new HttpTransportProtocol.Delivery(id, JsonEnvelope.builder("self-close").build()));
HttpTestAccess.dispatch(connector.get(), new HttpProtocolAccess.Delivery(id, JsonEnvelope.builder("self-close").build()));
assertTrue(callbackReturned.await(2, TimeUnit.SECONDS), "callback-owned close must not drain its own worker");
connector.get().close();
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(2);
HttpInboundDeliveryStore.State state = null;
Object state = null;
while (System.nanoTime() < deadline) {
state = HttpInboundDeliveryStore.inspect(clientDirectory).state(id);
if (state == HttpInboundDeliveryStore.State.COMPLETED) break;
state = HttpInboundStoreAccess.inspect(clientDirectory).state(id);
if (state == HttpInboundStoreAccess.State.COMPLETED) break;
Thread.sleep(5);
}
assertEquals(HttpInboundDeliveryStore.State.COMPLETED, state,
assertEquals(HttpInboundStoreAccess.State.COMPLETED, state,
"the callback wrapper must mark completed before close seals the journal");
connector.get().start();
assertFalse(connector.get().pollerAlive(), "a closed connector must not restart its poller");
assertFalse(HttpTestAccess.pollerAlive(connector.get()), "a closed connector must not restart its poller");
connector.get().close();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
package com.bencodez.simpleapi.servercomm.http;
package com.bencodez.simpleapi.tests.servercomm.http;

import com.bencodez.simpleapi.servercomm.http.HttpBackendTransportConnector;
import com.bencodez.simpleapi.servercomm.http.HttpClientCredentialStore;
import com.bencodez.simpleapi.servercomm.http.HttpConnectionCode;
import com.bencodez.simpleapi.servercomm.http.HttpEnrollmentAuthority;
import com.bencodez.simpleapi.servercomm.http.HttpProxyTransportServer;
import com.bencodez.simpleapi.servercomm.http.HttpTlsIdentity;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertEquals;
Expand All @@ -22,7 +29,7 @@ class HttpBackendSendLifecycleTest {
void pausedSendCannotEnterAfterCloseAndFlushCutsOffNewSends() throws Exception {
HttpTlsIdentity identity = HttpTlsIdentity.loadOrCreate(directory.resolve("proxy"), "localhost");
HttpEnrollmentAuthority authority = new HttpEnrollmentAuthority(identity, directory.resolve("authority"));
try (HttpProxyTransportServer server = new HttpProxyTransportServer(new InetSocketAddress("localhost", 0), identity,
try (HttpProxyTransportServer server = HttpTestAccess.server(new InetSocketAddress("localhost", 0), identity,
authority, ignored -> { })) {
server.start();
HttpConnectionCode code = authority.createConnectionCode("lobby-1", server.endpoint("localhost"), Duration.ofMinutes(5));
Expand All @@ -44,7 +51,7 @@ void pausedSendCannotEnterAfterCloseAndFlushCutsOffNewSends() throws Exception {
assertTrue(second.send(JsonEnvelope.builder("accepted-before-flush").build()));
assertPausedSendIsRejectedByFlush(second);
assertFalse(second.send(JsonEnvelope.builder("rejected-after-flush").build()));
assertEquals(0, second.queuedOutgoing());
assertEquals(0, HttpTestAccess.queuedOutgoing(second));
second.start();
assertTrue(second.send(JsonEnvelope.builder("accepted-after-restart").build()));
}
Expand All @@ -55,7 +62,7 @@ void pausedSendCannotEnterAfterCloseAndFlushCutsOffNewSends() throws Exception {
void restartedConnectorRequiresAResponseFromItsNewRun() throws Exception {
HttpTlsIdentity identity = HttpTlsIdentity.loadOrCreate(directory.resolve("restart-proxy"), "localhost");
HttpEnrollmentAuthority authority = new HttpEnrollmentAuthority(identity, directory.resolve("restart-authority"));
try (HttpProxyTransportServer server = new HttpProxyTransportServer(new InetSocketAddress("localhost", 0), identity,
try (HttpProxyTransportServer server = HttpTestAccess.server(new InetSocketAddress("localhost", 0), identity,
authority, ignored -> { })) {
server.start();
HttpConnectionCode code = authority.createConnectionCode("lobby-1", server.endpoint("localhost"), Duration.ofMinutes(5));
Expand All @@ -78,7 +85,7 @@ void restartedConnectorRequiresAResponseFromItsNewRun() throws Exception {
void startOpensSendAdmissionBeforeThePollerCanRun() throws Exception {
HttpTlsIdentity identity = HttpTlsIdentity.loadOrCreate(directory.resolve("startup-proxy"), "localhost");
HttpEnrollmentAuthority authority = new HttpEnrollmentAuthority(identity, directory.resolve("startup-authority"));
try (HttpProxyTransportServer server = new HttpProxyTransportServer(new InetSocketAddress("localhost", 0), identity,
try (HttpProxyTransportServer server = HttpTestAccess.server(new InetSocketAddress("localhost", 0), identity,
authority, ignored -> { })) {
server.start();
HttpConnectionCode code = authority.createConnectionCode("lobby-1", server.endpoint("localhost"), Duration.ofMinutes(5));
Expand Down Expand Up @@ -108,7 +115,7 @@ void restartWaitsForThePreviousPollerToExit() throws Exception {
HttpTlsIdentity identity = HttpTlsIdentity.loadOrCreate(directory.resolve("restart-proxy"), "localhost");
HttpConnectionCode code = new HttpConnectionCode("lobby-1", java.net.URI.create("https://localhost:8443/"),
identity.serverCertificatePin(), identity.caCertificatePin(), java.time.Instant.now().plusSeconds(60),
HttpTransportSecrets.randomToken());
HttpSecretsAccess.randomToken());
Path credentials = directory.resolve("restart-client");
HttpClientCredentialStore.saveEnrolled(credentials, code, identity.issueClientCertificate("lobby-1"));
try (HttpBackendTransportConnector connector = new HttpBackendTransportConnector(credentials, ignored -> { })) {
Expand Down Expand Up @@ -154,7 +161,7 @@ private static void assertPausedSendIsRejectedByClose(HttpBackendTransportConnec
assertFalse(sender.isAlive());
assertFalse(closer.isAlive());
assertFalse(accepted.get());
assertEquals(0, connector.queuedOutgoing());
assertEquals(0, HttpTestAccess.queuedOutgoing(connector));
}

private static void assertPausedSendIsRejectedByFlush(HttpBackendTransportConnector connector) throws Exception {
Expand Down Expand Up @@ -182,7 +189,7 @@ private static void assertPausedSendIsRejectedByFlush(HttpBackendTransportConnec
assertFalse(flusher.isAlive());
assertFalse(accepted.get());
assertTrue(flushed.get());
assertEquals(0, connector.queuedOutgoing());
assertEquals(0, HttpTestAccess.queuedOutgoing(connector));
}

private static Field field(String name) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
package com.bencodez.simpleapi.servercomm.http;
package com.bencodez.simpleapi.tests.servercomm.http;

import com.bencodez.simpleapi.servercomm.http.HttpBackendTransportConnector;
import com.bencodez.simpleapi.servercomm.http.HttpConnectionCode;
import com.bencodez.simpleapi.servercomm.http.HttpEnrollmentAuthority;
import com.bencodez.simpleapi.servercomm.http.HttpProxyTransportServer;
import com.bencodez.simpleapi.servercomm.http.HttpTlsIdentity;

import static org.junit.jupiter.api.Assertions.assertThrows;

Expand All @@ -15,7 +21,7 @@ class HttpBackendTransportConnectorConstructorTest {
void invalidConnectionCodeDoesNotPreventImmediateValidRetry() throws Exception {
HttpTlsIdentity identity = HttpTlsIdentity.loadOrCreate(directory.resolve("proxy"), "localhost");
HttpEnrollmentAuthority authority = new HttpEnrollmentAuthority(identity, directory.resolve("authority"));
try (HttpProxyTransportServer server = new HttpProxyTransportServer(new InetSocketAddress("localhost", 0),
try (HttpProxyTransportServer server = HttpTestAccess.server(new InetSocketAddress("localhost", 0),
identity, authority, ignored -> { })) {
server.start();
HttpConnectionCode code = authority.createConnectionCode("lobby-1", server.endpoint("localhost"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
package com.bencodez.simpleapi.servercomm.http;
package com.bencodez.simpleapi.tests.servercomm.http;

import com.bencodez.simpleapi.servercomm.http.HttpConnectionCode;
import com.bencodez.simpleapi.servercomm.http.HttpEnrollmentAuthority;
import com.bencodez.simpleapi.servercomm.http.HttpTlsIdentity;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
Expand Down
Loading
Loading