mirror of
https://github.com/gesellix/Bose-SoundTouch.git
synced 2026-08-18 08:36:13 +00:00
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 <token> Content-Type: application/vnd.bose.streaming-v1.2+xml <group> <masterDeviceId>...</masterDeviceId> <name>TEST</name> <roles> <groupRole><deviceId>...</deviceId><role>LEFT</role></groupRole> <groupRole><deviceId>...</deviceId><role>RIGHT</role></groupRole> </roles> </group> 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 <group> element, so adding a populated group beforehand is compatible. Refs #252 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
c3422ed0d5
commit
ef2b775ce0
@@ -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; \
|
||||
|
||||
@@ -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").
|
||||
### * <groupRole> elements have no <ipAddress>.
|
||||
### * No <senderIPAddress> (this is the master-bound payload).
|
||||
### * No numeric group <id> attribute and no <status> 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
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<group>
|
||||
<masterDeviceId>{{deviceId}}</masterDeviceId>
|
||||
<name>TEST</name>
|
||||
<roles>
|
||||
<groupRole>
|
||||
<deviceId>{{deviceId}}</deviceId>
|
||||
<role>LEFT</role>
|
||||
</groupRole>
|
||||
<groupRole>
|
||||
<deviceId>{{macAddress2}}</deviceId>
|
||||
<role>RIGHT</role>
|
||||
</groupRole>
|
||||
</roles>
|
||||
</group>
|
||||
|
||||
> {%
|
||||
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 <group>");
|
||||
|
||||
const master = group.getElementsByTagName("masterDeviceId")[0];
|
||||
client.assert(master !== undefined, "Response body should contain <masterDeviceId>");
|
||||
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 <name>");
|
||||
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 <groupRole> entries, got " + roles.length);
|
||||
});
|
||||
%}
|
||||
Reference in New Issue
Block a user