### GET /streaming/account/{{accountId}}/full
GET {{host}}/streaming/account/{{accountId}}/full
User-Agent: Bose_Lisa/27.0.6
Accept: application/vnd.bose.streaming-v1.2+xml
Authorization: Bearer {{token}}

> {%
    client.test("Request executed successfully", function() {
        client.assert(response.status === 200, "Response status is not 200");
    });

    client.test("Response content-type is correct", function() {
        var type = response.contentType.mimeType;
        client.assert(type === "application/vnd.bose.streaming-v1.2+xml", "Expected 'application/vnd.bose.streaming-v1.2+xml' but received '" + type + "'");
    });

    client.test("Response body structure", function() {
        var account = response.body.getElementsByTagName("account")[0];
        client.assert(account !== null, "Missing 'account' root element");
        // We use accountId from environment variables
        var expectedAccountId = client.variables.environment.get("accountId");
        client.assert(account.getAttribute("id") === expectedAccountId, "Expected account id '" + expectedAccountId + "' but received '" + account.getAttribute("id") + "'");

        var accountStatus = account.getElementsByTagName("accountStatus")[0];
        client.assert(accountStatus.textContent === "OK", "Account status is not OK");

        var devices = account.getElementsByTagName("devices")[0];
        client.assert(devices !== null, "Missing 'devices' element");

        var deviceList = devices.getElementsByTagName("device");
        client.assert(deviceList.length > 0, "No 'device' elements found");

        var firstDevice = deviceList[0];
        client.assert(firstDevice.getAttribute("deviceid").length > 0, "Missing deviceid attribute");

        var attachedProduct = firstDevice.getElementsByTagName("attachedProduct")[0];
        client.assert(attachedProduct !== null, "Missing 'attachedProduct'");
        client.assert(attachedProduct.getAttribute("product_code").length > 0, "Missing product_code");

        var presets = firstDevice.getElementsByTagName("presets")[0];
        client.assert(presets !== undefined, "Missing 'presets' element");

        var recents = firstDevice.getElementsByTagName("recents")[0];
        client.assert(recents !== undefined, "Missing 'recents' element");

        var sources = account.getElementsByTagName("sources")[0];
        client.assert(sources !== null, "Missing 'sources' element");
        var sourceCount = sources.getElementsByTagName("source").length;
        client.assert(sourceCount > 0, "No 'source' elements found in account sources");
        // AUX (sourceproviderid=9) is intentionally excluded from cloud-side
        // /full responses — real Bose never emitted it; the speaker enumerates
        // AUX from its own hardware via isLocal=true in :8090/sources. See
        // pkg/service/marge/marge.go getAccountSources for the reasoning and
        // commit 2b40481 for the fix that closed #195/#269.
        // INTERNET_RADIO (id=10002) is also excluded — it is a legacy stub
        // that AfterTouch no longer adds to new or existing devices. See
        // GetInitialSources() in pkg/service/datastore/datastore.go.
        client.assert(sourceCount === 4, "Expected 4 cloud sources (LOCAL_INTERNET_RADIO, TUNEIN, RADIO_BROWSER, Spotify; AUX and INTERNET_RADIO are excluded) but got " + sourceCount);

        // Explicit negative assertion: AUX must not appear in /full.
        var sourceList = sources.getElementsByTagName("source");
        for (var i = 0; i < sourceList.length; i++) {
            var pid = sourceList[i].getElementsByTagName("sourceproviderid")[0];
            client.assert(!pid || pid.textContent !== "9", "/full must not include AUX (sourceproviderid=9)");
        }
    });
%}
