Files
Bose-SoundTouch/tests/integration/http-client/rename_device.http
T
Tobias GesellchenandClaude Opus 4.7 feadc478d5 test: sweep example data in test files to RFC-5737 + placeholders
Mirrors the .md/.txt sweep across all tracked _test.go, testdata XML,
and .http integration files. Test files are self-contained (producer
+ assertion in the same file), so the matched-pair swap stays green
under `go test ./...`.

Mapping applied:
  192.168.178.[0-9]+   → 192.0.2.[same]
  192.168.1.[0-9]+     → 192.0.2.[same]
  Sound Machinechen    → Living Room SoundTouch
  A Sound Machine      → Kitchen SoundTouch
  A81B6A536A98 + case/separator variants → AABBCCDDEEFF (etc.)
  A81B6A849D99         → AABBCCDDEE01
  A81B6A849D88         → AABBCCDDEE03
  A81B6A536A09         → AABBCCDDEE04
  884AEAEEBD27         → AABBCCDDEE02
  3230304              → 1000001
  9569497              → 1000002

Two semantic fixes alongside the bulk swap:

- pkg/service/zeroconf/zeroconf_test.go: the "private 192" and
  "strips query" cases pin acceptance of RFC-1918 192.168/16. They
  must use a real 192.168 value; doc-range IPs would (correctly) be
  rejected by validateZcBaseURL. Switched to 192.168.10.10 — generic
  enough not to match any home LAN default, real enough for the
  validator. Added a comment explaining why this single test still
  carries a 192.168 literal.

- pkg/service/setup/setup_test.go: TestTestDNSRedirection mocks the
  device's `od -An -tu1` byte output, which is space-separated
  octets ("192 168 1 100"). My sed only matched the dot-separated
  form, so the mock was returning the old IP while the test
  assertions had moved to the doc range. Updated to " 192 0 2 100".

go build ./... clean. go test ./... clean (only TestDocsConsistency
remains failing, which is a pre-existing/untracked-file issue).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 22:05:13 +02:00

100 lines
5.4 KiB
HTTP

### PUT /streaming/account/{accountId}/device/{deviceId} (Rename Device)
###
### Speakers fire this against AfterTouch when the user renames them
### via the Bose App or `soundtouch-cli name set`. Before issue #285's
### route fix the request fell through to the [UNHANDLED] catch-all
### and proxied to streaming.bose.com (401), so the speaker retried
### in a loop and the Bose App showed the rename spinning forever.
### This test runs after register_device.http (which creates the
### initial record) and after power_on.http (which seeds the IP at
### 192.0.2.100). The rename PUT must:
###
### - return 200 OK
### - echo the new name
### - preserve <createdOn> from the initial registration
### - preserve <ipaddress> from the power_on update (request body
### doesn't carry one; the datastore merge keeps the existing)
### - refresh <updatedOn> to "now"
PUT {{host}}/streaming/account/{{accountId}}/device/{{deviceId}}
Content-Type: application/vnd.bose.streaming-v1.2+xml
Authorization: Bearer {{token}}
<?xml version="1.0" encoding="UTF-8" ?>
<device deviceid="{{deviceId}}">
<name>{{deviceName}} (renamed)</name>
<macaddress>{{macAddress1}}</macaddress>
</device>
> {%
client.test("Rename returned 200 OK", function() {
client.assert(response.status === 200, "Response status should be 200, 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");
});
client.test("Response carries the new name and matches the deviceId", function() {
const doc = response.body;
const device = doc.getElementsByTagName("device")[0];
client.assert(device !== undefined, "Response body should contain <device>");
client.assert(device.getAttribute("deviceid") === client.variables.environment.get("deviceId"), "Response deviceid should match");
const name = device.getElementsByTagName("name")[0];
client.assert(name !== undefined, "Response body should contain <name>");
client.assert(name.textContent === client.variables.environment.get("deviceName") + " (renamed)", "Response should carry the renamed value");
});
client.test("createdOn preserved across rename, updatedOn refreshed", function() {
const device = response.body.getElementsByTagName("device")[0];
const createdOn = device.getElementsByTagName("createdOn")[0];
client.assert(createdOn !== undefined, "Response body should contain <createdOn>");
client.assert(createdOn.textContent.length > 0, "createdOn should not be empty (it must survive the rename, not be reset)");
client.assert(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|(\+\d{2}:\d{2}))$/.test(createdOn.textContent), "createdOn should be ISO8601");
// The load-bearing assertion: the value must match what
// register_device.http captured on the initial POST. If it
// doesn't, the rename PUT regressed the "first-paired in
// 2017" semantics — the exact bug behind the parity capture
// at data/parity_mismatches/1771797308__streaming_account_1000001_device_AABBCCDDEEFF.json.
const initial = client.global.get("initialCreatedOn");
client.assert(initial !== undefined && initial.length > 0,
"initialCreatedOn was not captured by register_device.http — test ordering issue");
client.assert(createdOn.textContent === initial,
"createdOn (" + createdOn.textContent + ") differs from the value captured at registration (" + initial + ") — the rename PUT must preserve the original timestamp");
const updatedOn = device.getElementsByTagName("updatedOn")[0];
client.assert(updatedOn !== undefined, "Response body should contain <updatedOn>");
client.assert(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|(\+\d{2}:\d{2}))$/.test(updatedOn.textContent), "updatedOn should be ISO8601");
});
client.test("ipaddress preserved from earlier power_on payload", function() {
const device = response.body.getElementsByTagName("device")[0];
const ipaddress = device.getElementsByTagName("ipaddress")[0];
client.assert(ipaddress !== undefined, "Response body should contain <ipaddress>");
client.assert(ipaddress.textContent === client.variables.environment.get("deviceIp"),
"ipaddress should be preserved from the prior power_on (" + client.variables.environment.get("deviceIp") + "), not overwritten — got " + ipaddress.textContent);
});
%}
### PUT with mismatched deviceid in body (safety check)
###
### If the body's deviceid attribute doesn't match the URL's {device}
### segment the handler refuses with 400 rather than silently re-key
### the persisted record under the wrong account/device. Pins the
### second TestIssue285_* unit-test assertion at the integration
### layer.
PUT {{host}}/streaming/account/{{accountId}}/device/{{deviceId}}
Content-Type: application/vnd.bose.streaming-v1.2+xml
Authorization: Bearer {{token}}
<?xml version="1.0" encoding="UTF-8" ?>
<device deviceid="DEADBEEFCAFE">
<name>Rogue Rename</name>
<macaddress>DEADBEEFCAFE</macaddress>
</device>
> {%
client.test("Mismatched body deviceid returns 400", function() {
client.assert(response.status === 400, "Response status should be 400 for body/url deviceid mismatch, got " + response.status);
});
%}