Fix AddDeviceToAccount

This commit is contained in:
Tobias Gesellchen
2026-03-29 19:14:48 +02:00
parent 766671f02b
commit a8140ad4fd
4 changed files with 36 additions and 9 deletions
+3 -1
View File
@@ -460,13 +460,15 @@ func (s *Server) HandleMargeAddDevice(w http.ResponseWriter, r *http.Request) {
return
}
data, err := marge.AddDeviceToAccount(s.ds, account, body)
deviceID, data, err := marge.AddDeviceToAccount(s.ds, account, body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/vnd.bose.streaming-v1.2+xml")
w.Header().Set("Location", s.serverURL+"/account/"+account+"/device/"+deviceID)
w.WriteHeader(http.StatusCreated)
_, _ = w.Write(data)
}
+7 -2
View File
@@ -817,8 +817,13 @@ func TestMargeAddRemoveDevice(t *testing.T) {
_ = res.Body.Close()
if res.StatusCode != http.StatusOK {
t.Errorf("AddDevice: Expected status OK, got %v", res.Status)
if res.StatusCode != http.StatusCreated {
t.Errorf("AddDevice: Expected status Created, got %v", res.Status)
}
location := res.Header.Get("Location")
if !strings.Contains(location, "/account/"+account+"/device/NEWDEV") {
t.Errorf("AddDevice: Expected Location header containing /account/%s/device/NEWDEV, got %s", account, location)
}
deviceFile := filepath.Join(accountDir, "devices", "NEWDEV", "DeviceInfo.xml")
+4 -4
View File
@@ -969,14 +969,14 @@ func formatRecentResponse(recentObj *models.ServiceRecent, matchingSrc *models.C
}
// AddDeviceToAccount adds a new device to the specified account.
func AddDeviceToAccount(ds *datastore.DataStore, account string, sourceXML []byte) ([]byte, error) {
func AddDeviceToAccount(ds *datastore.DataStore, account string, sourceXML []byte) (string, []byte, error) {
var newDeviceElem struct {
DeviceID string `xml:"deviceid,attr"`
Name string `xml:"name"`
MACAddress string `xml:"macaddress"`
}
if err := xml.Unmarshal(sourceXML, &newDeviceElem); err != nil {
return nil, err
return "", nil, err
}
info := &models.ServiceDeviceInfo{
@@ -987,7 +987,7 @@ func AddDeviceToAccount(ds *datastore.DataStore, account string, sourceXML []byt
}
if err := ds.SaveDeviceInfo(account, newDeviceElem.DeviceID, info); err != nil {
return nil, err
return "", nil, err
}
createdOn := FormatTime(time.Now())
@@ -1000,7 +1000,7 @@ func AddDeviceToAccount(ds *datastore.DataStore, account string, sourceXML []byt
header := constants.XMLHeader
return append([]byte(header), []byte(res)...), nil
return newDeviceElem.DeviceID, append([]byte(header), []byte(res)...), nil
}
// RemoveDeviceFromAccount removes a device from the specified account.
@@ -12,10 +12,27 @@ Authorization: Bearer {{token}}
> {%
client.test("Device registered successfully", function() {
client.assert(response.status === 200 || response.status === 201, "Response status is not 200 or 201");
client.assert(response.contentType.mimeType === "application/vnd.bose.streaming-v1.2+xml", "Response Content-Type should be application/vnd.bose.streaming-v1.2+xml");
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 body should contain the deviceId");
const name = device.getElementsByTagName("name")[0];
client.assert(name !== undefined, "Response body should contain <name>");
client.assert(name.textContent === client.variables.environment.get("deviceName"), "name should match requested name");
const createdOn = device.getElementsByTagName("createdOn")[0];
client.assert(createdOn !== undefined, "Response body should contain <createdOn>");
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 a valid ISO8601 timestamp");
const updatedOn = device.getElementsByTagName("updatedOn")[0];
client.assert(updatedOn !== undefined, "Response body should contain <updatedOn>");
client.assert(updatedOn.textContent === createdOn.textContent, "updatedOn should match createdOn for a new device");
const ipaddress = device.getElementsByTagName("ipaddress")[0];
client.assert(ipaddress !== undefined, "Response body should contain <ipaddress>");
});
%}
@@ -32,7 +49,10 @@ Authorization: Bearer {{token}}
> {%
client.test("Device registered successfully (variant)", function() {
client.assert(response.status === 200 || response.status === 201, "Response status is not 200 or 201");
client.assert(response.status === 200 || response.status === 201, "Response status should be 200 or 201");
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.assert(response.headers.valueOf("Location").includes("/account/" + client.variables.environment.get("accountId") + "/device/" + client.variables.environment.get("deviceId")), "Location header should point to the created device");
const doc = response.body;
const device = doc.getElementsByTagName("device")[0];
client.assert(device !== undefined, "Response body should contain <device>");
@@ -40,7 +60,7 @@ Authorization: Bearer {{token}}
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");
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 a valid ISO8601 timestamp");
const name = device.getElementsByTagName("name")[0];
client.assert(name !== undefined, "Response body should contain <name>");