Skip to content

Commit 3077036

Browse files
authored
Feat/add m detach (#33)
1 parent ad8023f commit 3077036

File tree

9 files changed

+257
-38
lines changed

9 files changed

+257
-38
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
code: true
3+
type: page
4+
title: mDetach
5+
description: Detach multiple devices from multiple tenants
6+
---
7+
8+
# mDetach
9+
10+
Detach multiple devices from multiple tenants.
11+
12+
---
13+
14+
## Query Syntax
15+
16+
### HTTP
17+
18+
``` http
19+
URL: http://kuzzle:7512/_/device-manager/device-manager/devices/_mDetach[?refresh=wait_for]
20+
Method: PUT
21+
Body:
22+
```
23+
24+
``` js
25+
{
26+
// Using JSON
27+
"sensorIds" ["test-id"],
28+
// Using CSV syntax
29+
"csv": "sensorId\ntest-id"
30+
}
31+
```
32+
33+
### Other protocols
34+
35+
``` js
36+
{
37+
"controller": "device-manager/sensor",
38+
"action": "mAttachTenant",
39+
"body": {
40+
// Using JSON
41+
"sensorIds" ["test-id"],
42+
// Using CSV syntax
43+
"csv": "sensorId\ntest-id"
44+
}
45+
}
46+
```
47+
48+
---
49+
50+
## Body properties
51+
52+
Body properties, must contain at least one of
53+
54+
* `sensorIds`: an array of string containing identifiers of a sensor already attached
55+
* `csv`: a csv syntax compatible containing at least one header `sensorId` with his corresponding values
56+
* `strict`: a boolean value that indicate if the process should fail at first error
57+
58+
---
59+
60+
## Arguments
61+
62+
### Optional:
63+
64+
* `refresh`: if set to `wait_for`, Kuzzle will not respond until the documents are indexed
65+
66+
---
67+
68+
## Response
69+
70+
``` js
71+
{
72+
"status": 200,
73+
"error": null,
74+
"index": "<index>",
75+
"controller": "device-manager/sensor",
76+
"action": "mDetach",
77+
"requestId": "<unique request identifier>",
78+
"result": {
79+
"errors": [],
80+
"successes": []
81+
}
82+
}
83+
```

doc/1/guides/devices/index.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,23 @@ The format used can be either __CSV__ in the form of a string in the format `ten
118118

119119
When attached, all devices documents are copied inside the `devices` collections of all different tenant index.
120120

121+
## Detach a sensor from a tenant
122+
123+
Sensors can be detached to tenant by using the [device-manager/sensor:detach](/kuzzle-iot-platform/device-manager/1/controllers/sensor/detach) API action.
124+
125+
When detached, the sensor document is deleted from the `sensors` collection of the tenant index.
126+
127+
the `tenantId` property is set to `null` in the `device-manager` index.
128+
## Detach multiple sensors from multiple tenants
129+
130+
Multiple different Sensors can also be detached to multiple defferents tenant by using the [device-manager/sensor:mDetach](/kuzzle-iot-platform/device-manager/1/controllers/sensor/mDetach) API action.
131+
132+
The format used can be either __CSV__ in the form of a string in the format "tenantId,sensorId,mysensorId" or __JSON__ in the form of an array of objects.
133+
134+
When detached, all sensors documents are deleted from the `sensors` collections of all different tenant index.
135+
136+
The `tenantId` property is set to `null` for all of them in the `device-manager` index
137+
121138
## Link to an asset
122139

123140
Devices can be linked to an asset by using the [device-manager/device:link](/kuzzle-iot-platform/device-manager/1/controllers/device/link) API action.

features/DeviceController.feature

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ Feature: Device Manager device controller
3636

3737
Scenario: Attach multiple device to a tenant while exceeding documentsWriteCount limit
3838
Given an engine on index "tenant-kuzzle"
39-
When I attach multiple devices while exeding documentsWriteCount limit
40-
Then All attached devices have the correct tenantId
41-
Then All tenant devices documents exists
39+
When I succesfully execute "device-manager/device":"mAttach" while exeding documentsWriteCount limit
40+
Then All devices in "device-manager" "devices" have the property "tenantId" to "tenant-kuzzle"
41+
And All documents "tenant-kuzzle":"devices" exists
4242

4343
Scenario: Error when assigning a device to a tenant
4444
Given an engine on index "tenant-kuzzle"
@@ -67,19 +67,55 @@ Feature: Device Manager device controller
6767
| tenantId | null |
6868
And The document "tenant-kuzzle":"devices":"DummyTemp_detached" does not exists
6969

70+
Scenario: Detach multiple devices to a tenant using JSON
71+
Given an engine on index "tenant-kuzzle"
72+
When I successfully execute the action "device-manager/device":"mAttach" with args:
73+
| body.records.0.tenantId | "tenant-kuzzle" |
74+
| body.records.0.deviceId | "DummyTemp_detached" |
75+
| body.records.1.tenantId | "tenant-kuzzle" |
76+
| body.records.1.deviceId | "DummyTemp_attached-ayse-unlinked" |
77+
When I successfully execute the action "device-manager/device":"mDetach" with args:
78+
| body.deviceIds | ["DummyTemp_detached","DummyTemp_attached-ayse-unlinked"] |
79+
Then The document "device-manager":"devices":"DummyTemp_detached" content match:
80+
| tenantId | null |
81+
Then The document "device-manager":"devices":"DummyTemp_attached-ayse-unlinked" content match:
82+
| tenantId | null |
83+
And The document "tenant-kuzzle":"devices":"DummyTemp_detached" does not exists
84+
And The document "tenant-kuzzle":"devices":"DummyTemp_attached-ayse-unlinked" does not exists
85+
86+
Scenario: Detach multiple devices to a tenant using CSV
87+
Given an engine on index "tenant-kuzzle"
88+
When I successfully execute the action "device-manager/device":"mAttach" with args:
89+
| body.csv | "tenantId,deviceId\\ntenant-kuzzle,DummyTemp_detached\\ntenant-kuzzle,DummyTemp_attached-ayse-unlinked," |
90+
When I successfully execute the action "device-manager/device":"mDetach" with args:
91+
| body.csv | "deviceId\\nDummyTemp_detached\\nDummyTemp_attached-ayse-unlinked," |
92+
Then The document "device-manager":"devices":"DummyTemp_detached" content match:
93+
| tenantId | null |
94+
Then The document "device-manager":"devices":"DummyTemp_attached-ayse-unlinked" content match:
95+
| tenantId | null |
96+
And The document "tenant-kuzzle":"devices":"DummyTemp_detached" does not exists
97+
And The document "tenant-kuzzle":"devices":"DummyTemp_attached-ayse-unlinked" does not exists
98+
99+
Scenario: Detach multiple device to a tenant while exceeding documentsWriteCount limit
100+
Given an engine on index "tenant-kuzzle"
101+
When I succesfully execute "device-manager/device":"mAttach" while exeding documentsWriteCount limit
102+
When I succesfully execute "device-manager/device":"mDetach" while exeding documentsWriteCount limit
103+
Then All devices in "device-manager" "devices" have the property "tenantId" to "null"
104+
And All documents "tenant-kuzzle":"devices" does not exists
105+
70106
Scenario: Error when detaching from a tenant
71107
Given an engine on index "tenant-kuzzle"
72108
When I execute the action "device-manager/device":"detach" with args:
73109
| _id | "DummyTemp_detached" |
74110
Then I should receive an error matching:
75-
| message | "Device \"DummyTemp_detached\" is not attached to a tenant" |
111+
| message | "Devices \"DummyTemp_detached\" are not attached to a tenant" |
76112
Given I successfully execute the action "device-manager/device":"linkAsset" with args:
77113
| _id | "DummyTemp_attached-ayse-unlinked" |
78114
| assetId | "PERFO-unlinked" |
79115
When I execute the action "device-manager/device":"detach" with args:
80116
| _id | "DummyTemp_attached-ayse-unlinked" |
81117
Then I should receive an error matching:
82-
| message | "Device \"DummyTemp_attached-ayse-unlinked\" is still linked to an asset" |
118+
| message | "Devices \"DummyTemp_attached-ayse-unlinked\" are still linked to an asset" |
83119

84120
Scenario: Link device to an asset
85121
When I successfully execute the action "device-manager/device":"linkAsset" with args:

features/fixtures/devices.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ for (let i = 0; i < 50; i++) {
1212
});
1313
}
1414

15-
module.exports = devices;
15+
const devicesTests = devices.filter(test => test.model);
16+
17+
module.exports = { devices, devicesTests };

features/fixtures/fixtures.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const devices = require('./devices');
1+
const { devices } = require('./devices');
22

33
module.exports = {
44
'device-manager': {
Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,71 @@
11
const { When, Then } = require('cucumber');
22

3-
When('I attach multiple devices while exeding documentsWriteCount limit', async function () {
3+
const { devicesTests } = require('../fixtures/devices');
4+
5+
When('I succesfully execute {string}:{string} while exeding documentsWriteCount limit', async function (controller, action) {
46
const records = [];
5-
for (let i = 0; i < 50; i++) {
7+
for (let i = 0; i < devicesTests.length; i++) {
68
records.push({ deviceId: `DummyTemp_detached-${i}`, tenantId: 'tenant-kuzzle' });
79
}
810

911

1012
await this.sdk.query({
11-
controller: "device-manager/device",
12-
action: "mAttach",
13+
controller,
14+
action,
1315
body: {
1416
records
1517
}
1618
});
1719
});
1820

19-
Then('All attached devices have the correct tenantId', async function () {
21+
Then('All devices in {string} {string} have the property {string} to {string}', async function (index, collection, key, value) {
2022
const deviceIds = [];
21-
for (let i = 0; i < 50; i++) {
23+
for (let i = 0; i < devicesTests.length; i++) {
2224
deviceIds.push(`DummyTemp_detached-${i}`);
2325
}
2426

25-
const { successes, errors } = await this.sdk.document.mGet('device-manager', 'devices', deviceIds);
27+
const { successes, errors } = await this.sdk.document.mGet(index, collection, deviceIds);
2628

2729
if (errors.length > 0) {
2830
throw new Error(errors);
2931
}
3032

3133
for (let i = 0; i < successes.length; i++) {
3234
const { _source } = successes[i];
33-
if (_source.tenantId !== 'tenant-kuzzle') {
34-
throw new Error('tenantId should be tenant-kuzzle but current value is: ', _source.tenantId);
35+
const theValue = value === "null" ? null : value;
36+
37+
if (_source[key] !== theValue) {
38+
throw new Error(`tenantId should be ${value} but current value is: ${_source.tenantId}`);
3539
}
3640
}
3741
});
3842

39-
40-
Then('All tenant devices documents exists', async function () {
43+
Then('All {string} devices documents exists', async function (tenant) {
4144
const deviceIds = [];
42-
for (let i = 0; i < 50; i++) {
45+
for (let i = 0; i < devicesTests.length; i++) {
4346
deviceIds.push(`DummyTemp_detached-${i}`);
4447
}
4548

46-
const { errors } = await this.sdk.document.mGet('tenant-kuzzle', 'devices', deviceIds);
49+
const { errors } = await this.sdk.document.mGet(tenant, 'devices', deviceIds);
4750

4851
if (errors.length > 0) {
4952
throw new Error(errors);
5053
}
5154
});
55+
56+
Then(/All documents "(.*?)":"(.*?)" (does not)? exists/, async function (index, collection, not) {
57+
const deviceIds = [];
58+
for (let i = 0; i < devicesTests.length; i++) {
59+
deviceIds.push(`DummyTemp_detached-${i}`);
60+
}
61+
62+
const { successes, errors } = await this.sdk.document.mGet(index, collection, deviceIds);
63+
64+
if (not && successes.length > 0) {
65+
throw new Error(`Documents exists, but it shoudn't`);
66+
}
67+
68+
if (!not && errors.length) {
69+
throw new Error(`Expected documents to exist`);
70+
}
71+
});

lib/controllers/DeviceController.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ export class DeviceController extends CRUDController {
5252
handler: this.detach.bind(this),
5353
http: [{ verb: 'delete', path: 'device-manager/devices/:_id/_detach' }]
5454
},
55+
mDetach: {
56+
handler: this.mDetach.bind(this),
57+
http: [{ verb: 'put', path: 'device-manager/devices/_mDetach' }]
58+
},
5559
linkAsset: {
5660
handler: this.linkAsset.bind(this),
5761
http: [{ verb: 'put', path: 'device-manager/:index/devices/:_id/_link/:assetId' }]
@@ -94,9 +98,21 @@ export class DeviceController extends CRUDController {
9498
async detach (request: KuzzleRequest) {
9599
const deviceId = this.getId(request);
96100

97-
const device = await this.getDevice(deviceId);
101+
const document: DeviceBulkContent = { deviceId };
102+
const devices = await this.mGetDevice([document]);
98103

99-
await this.deviceService.detach(device);
104+
await this.deviceService.mDetach(devices, [document], { strict: true });
105+
}
106+
107+
/**
108+
* Unattach multiple devices from multiple tenants
109+
*/
110+
async mDetach (request: KuzzleRequest) {
111+
const { bulkData, strict } = await this.mParseRequest(request);
112+
113+
const devices = await this.mGetDevice(bulkData);
114+
115+
return this.deviceService.mDetach(devices, bulkData, { strict });
100116
}
101117

102118
/**
@@ -155,8 +171,11 @@ export class DeviceController extends CRUDController {
155171
else if (body.records) {
156172
bulkData = body.records;
157173
}
174+
else if (body.deviceIds) {
175+
bulkData = body.deviceIds.map((deviceId: string) => ({ deviceId }));
176+
}
158177
else {
159-
throw new BadRequestError(`Malformed request missing property csv or records`);
178+
throw new BadRequestError(`Malformed request missing property csv, records, deviceIds`);
160179
}
161180

162181
const strict = body.strict || false;

0 commit comments

Comments
 (0)