From ef2b775ce003c144676f0d9838f9e972b070b7d8 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Thu, 14 May 2026 22:45:39 +0200 Subject: [PATCH] test(integration): add http-client test for stereo-pair Marge POST Add an end-to-end IntelliJ HTTP Client test that replays the exact request shape a SoundTouch 10 master sends to its configured Marge server during stereo-pair formation (captured live in issue #252): POST /streaming/account/{accountId}/group/ Authorization: Bearer Content-Type: application/vnd.bose.streaming-v1.2+xml ... TEST ...LEFT ...RIGHT Assertions cover the wire contract that fails loudly if regressed: trailing-slash URL is matched, response is 201 Created with the vendor media type, Location header references the new group under the account, and the body echoes masterDeviceId, name, and both groupRole entries. Wired into the make test-http-client target, sequenced before get_group.http so the GET runs against the post-create state. get_group.http's assertion only checks for the presence of a element, so adding a populated group beforehand is compatible. Refs #252 Co-Authored-By: Claude Opus 4.7 (1M context) --- Makefile | 1 + .../integration/http-client/create_group.http | 66 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/integration/http-client/create_group.http diff --git a/Makefile b/Makefile index 9c4c038..ddbd2b4 100644 --- a/Makefile +++ b/Makefile @@ -169,6 +169,7 @@ test-http-client: /workdir/get_api_versions.http \ /workdir/post_musicprovider_is_eligible.http \ /workdir/get_full_account.http \ + /workdir/create_group.http \ /workdir/get_group.http \ /workdir/unregister_device.http \ --report; \ diff --git a/tests/integration/http-client/create_group.http b/tests/integration/http-client/create_group.http new file mode 100644 index 0000000..c69972e --- /dev/null +++ b/tests/integration/http-client/create_group.http @@ -0,0 +1,66 @@ +### POST /streaming/account/{{accountId}}/group/ (Create Stereo Pair via Marge) +### +### Replays the exact shape a SoundTouch 10 master sends when it forwards the +### addGroup payload to its configured Marge server while forming a stereo pair +### (issue #252). Notable properties of the wire contract this exercises: +### +### * URL has a trailing slash ("/group/", not "/group"). +### * elements have no . +### * No (this is the master-bound payload). +### * No numeric group attribute and no on the request. +### * Content-Type is the vendor-specific media type. +### +### The speaker retries this POST every 15 s while in AddingMaster state; if +### AfterTouch doesn't accept it, the group never completes and reverts to +### NoGroup after a timeout. +POST {{host}}/streaming/account/{{accountId}}/group/ +Content-Type: application/vnd.bose.streaming-v1.2+xml +Authorization: Bearer {{token}} +User-Agent: Bose_Lisa/27.0.6 +Accept: application/vnd.bose.streaming-v1.2+xml + + + + {{deviceId}} + TEST + + + {{deviceId}} + LEFT + + + {{macAddress2}} + RIGHT + + + + +> {% + client.test("Group created successfully", function() { + client.assert(response.status === 201, "Response status should be 201 Created, got " + response.status); + client.assert(response.contentType.mimeType === "application/vnd.bose.streaming-v1.2+xml", + "Response Content-Type should be application/vnd.bose.streaming-v1.2+xml, got '" + response.contentType.mimeType + "'"); + client.assert(response.headers.valueOf("Location") !== null, + "Response should include a Location header pointing to the new group"); + client.assert(response.headers.valueOf("Location").includes("/account/" + client.variables.environment.get("accountId") + "/group/"), + "Location header should reference the new group under the account, got '" + response.headers.valueOf("Location") + "'"); + }); + + client.test("Response body echoes the requested group", function() { + const doc = response.body; + const group = doc.getElementsByTagName("group")[0]; + client.assert(group !== undefined, "Response body should contain "); + + const master = group.getElementsByTagName("masterDeviceId")[0]; + client.assert(master !== undefined, "Response body should contain "); + client.assert(master.textContent === client.variables.environment.get("deviceId"), + "masterDeviceId should match the request, got '" + master.textContent + "'"); + + const name = group.getElementsByTagName("name")[0]; + client.assert(name !== undefined, "Response body should contain "); + client.assert(name.textContent === "TEST", "name should match the requested 'TEST', got '" + name.textContent + "'"); + + const roles = group.getElementsByTagName("groupRole"); + client.assert(roles.length === 2, "Response should contain exactly 2 entries, got " + roles.length); + }); +%} \ No newline at end of file