@iobroker/testing 4.1.3 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/build/index.d.ts +1 -1
- package/build/lib/adapterTools.d.ts +7 -2
- package/build/lib/adapterTools.js +47 -31
- package/build/lib/executeCommand.d.ts +3 -3
- package/build/lib/executeCommand.js +32 -32
- package/build/lib/str2regex.js +5 -6
- package/build/lib/testAdapter.d.ts +1 -0
- package/build/lib/testAdapter.js +1 -0
- package/build/tests/index.d.ts +9 -9
- package/build/tests/index.js +0 -1
- package/build/tests/integration/index.d.ts +1 -3
- package/build/tests/integration/index.js +46 -41
- package/build/tests/integration/lib/adapterSetup.d.ts +1 -1
- package/build/tests/integration/lib/adapterSetup.js +55 -42
- package/build/tests/integration/lib/controllerSetup.d.ts +1 -10
- package/build/tests/integration/lib/controllerSetup.js +59 -56
- package/build/tests/integration/lib/dbConnection.d.ts +12 -16
- package/build/tests/integration/lib/dbConnection.js +71 -69
- package/build/tests/integration/lib/harness.d.ts +9 -12
- package/build/tests/integration/lib/harness.js +70 -50
- package/build/tests/integration/lib/logger.d.ts +0 -1
- package/build/tests/integration/lib/logger.js +2 -4
- package/build/tests/integration/lib/tools.d.ts +6 -1
- package/build/tests/integration/lib/tools.js +32 -18
- package/build/tests/packageFiles/index.js +93 -77
- package/build/tests/unit/harness/createMocks.d.ts +3 -3
- package/build/tests/unit/harness/createMocks.js +1 -3
- package/build/tests/unit/index.js +6 -6
- package/build/tests/unit/mocks/mockAdapter.d.ts +3 -4
- package/build/tests/unit/mocks/mockAdapter.js +198 -164
- package/build/tests/unit/mocks/mockAdapterCore.d.ts +4 -10
- package/build/tests/unit/mocks/mockAdapterCore.js +24 -16
- package/build/tests/unit/mocks/mockDatabase.d.ts +13 -14
- package/build/tests/unit/mocks/mockDatabase.js +41 -45
- package/build/tests/unit/mocks/mockLogger.d.ts +1 -2
- package/build/tests/unit/mocks/mockLogger.js +2 -3
- package/build/tests/unit/mocks/tools.d.ts +2 -3
- package/build/tests/unit/mocks/tools.js +17 -15
- package/package.json +28 -32
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
|
@@ -32,7 +42,7 @@ const events_1 = __importDefault(require("events"));
|
|
|
32
42
|
const fs_extra_1 = require("fs-extra");
|
|
33
43
|
const path = __importStar(require("path"));
|
|
34
44
|
const tools_1 = require("./tools");
|
|
35
|
-
const debug = (0, debug_1.default)(
|
|
45
|
+
const debug = (0, debug_1.default)('testing:integration:DBConnection');
|
|
36
46
|
/** The DB connection capsules access to the states and objects DB */
|
|
37
47
|
class DBConnection extends events_1.default {
|
|
38
48
|
/**
|
|
@@ -45,45 +55,45 @@ class DBConnection extends events_1.default {
|
|
|
45
55
|
this.testDir = testDir;
|
|
46
56
|
this.logger = logger;
|
|
47
57
|
this._isRunning = false;
|
|
48
|
-
this.getObject =
|
|
58
|
+
this.getObject = id => {
|
|
49
59
|
if (!this._objectsClient) {
|
|
50
|
-
throw new Error(
|
|
60
|
+
throw new Error('Objects DB is not running');
|
|
51
61
|
}
|
|
52
62
|
return this._objectsClient.getObjectAsync(id);
|
|
53
63
|
};
|
|
54
|
-
this.setObject =
|
|
64
|
+
this.setObject = (...args) => {
|
|
55
65
|
if (!this._objectsClient) {
|
|
56
|
-
throw new Error(
|
|
66
|
+
throw new Error('Objects DB is not running');
|
|
57
67
|
}
|
|
58
68
|
return this._objectsClient.setObjectAsync(...args);
|
|
59
69
|
};
|
|
60
|
-
this.delObject =
|
|
70
|
+
this.delObject = (...args) => {
|
|
61
71
|
if (!this._objectsClient) {
|
|
62
|
-
throw new Error(
|
|
72
|
+
throw new Error('Objects DB is not running');
|
|
63
73
|
}
|
|
64
74
|
return this._objectsClient.delObjectAsync(...args);
|
|
65
75
|
};
|
|
66
|
-
this.getState =
|
|
76
|
+
this.getState = (id) => {
|
|
67
77
|
if (!this._statesClient) {
|
|
68
|
-
throw new Error(
|
|
78
|
+
throw new Error('States DB is not running');
|
|
69
79
|
}
|
|
70
80
|
return this._statesClient.getStateAsync(id);
|
|
71
81
|
};
|
|
72
|
-
this.setState = (
|
|
82
|
+
this.setState = ((...args) => {
|
|
73
83
|
if (!this._statesClient) {
|
|
74
|
-
throw new Error(
|
|
84
|
+
throw new Error('States DB is not running');
|
|
75
85
|
}
|
|
76
86
|
return this._statesClient.setStateAsync(...args);
|
|
77
87
|
});
|
|
78
|
-
this.delState =
|
|
88
|
+
this.delState = (...args) => {
|
|
79
89
|
if (!this._statesClient) {
|
|
80
|
-
throw new Error(
|
|
90
|
+
throw new Error('States DB is not running');
|
|
81
91
|
}
|
|
82
92
|
return this._statesClient.delStateAsync(...args);
|
|
83
93
|
};
|
|
84
|
-
this.getObjectViewAsync =
|
|
94
|
+
this.getObjectViewAsync = (...args) => {
|
|
85
95
|
if (!this._objectsClient) {
|
|
86
|
-
throw new Error(
|
|
96
|
+
throw new Error('Objects DB is not running');
|
|
87
97
|
}
|
|
88
98
|
return this._objectsClient.getObjectViewAsync(...args);
|
|
89
99
|
};
|
|
@@ -102,36 +112,38 @@ class DBConnection extends events_1.default {
|
|
|
102
112
|
return this.getSystemConfig().objects.type;
|
|
103
113
|
}
|
|
104
114
|
get objectsPath() {
|
|
105
|
-
return path.join(this.testDataDir, this.objectsType ===
|
|
115
|
+
return path.join(this.testDataDir, this.objectsType === 'file' ? 'objects.json' : 'objects.jsonl');
|
|
106
116
|
}
|
|
107
117
|
get statesType() {
|
|
108
118
|
return this.getSystemConfig().states.type;
|
|
109
119
|
}
|
|
110
120
|
get statesPath() {
|
|
111
|
-
return path.join(this.testDataDir, this.statesType ===
|
|
121
|
+
return path.join(this.testDataDir, this.statesType === 'file' ? 'states.json' : 'states.jsonl');
|
|
112
122
|
}
|
|
113
123
|
getSystemConfig() {
|
|
114
124
|
const systemFilename = path.join(this.testDataDir, `${this.appName}.json`);
|
|
115
125
|
return (0, fs_extra_1.readJSONSync)(systemFilename);
|
|
116
126
|
}
|
|
117
127
|
async backup() {
|
|
118
|
-
debug(
|
|
128
|
+
debug('Creating DB backup...');
|
|
119
129
|
const wasRunning = this._isRunning;
|
|
120
130
|
await this.stop();
|
|
121
131
|
const objects = await (0, fs_extra_1.readFile)(this.objectsPath);
|
|
122
132
|
const states = await (0, fs_extra_1.readFile)(this.statesPath);
|
|
123
|
-
if (wasRunning)
|
|
133
|
+
if (wasRunning) {
|
|
124
134
|
await this.start();
|
|
135
|
+
}
|
|
125
136
|
return { objects, states };
|
|
126
137
|
}
|
|
127
138
|
async restore(objects, states) {
|
|
128
|
-
debug(
|
|
139
|
+
debug('Restoring DB backup...');
|
|
129
140
|
const wasRunning = this._isRunning;
|
|
130
141
|
await this.stop();
|
|
131
142
|
await (0, fs_extra_1.writeFile)(this.objectsPath, objects);
|
|
132
143
|
await (0, fs_extra_1.writeFile)(this.statesPath, states);
|
|
133
|
-
if (wasRunning)
|
|
144
|
+
if (wasRunning) {
|
|
134
145
|
await this.start();
|
|
146
|
+
}
|
|
135
147
|
}
|
|
136
148
|
setSystemConfig(systemConfig) {
|
|
137
149
|
const systemFilename = path.join(this.testDataDir, `${this.appName}.json`);
|
|
@@ -142,21 +154,21 @@ class DBConnection extends events_1.default {
|
|
|
142
154
|
}
|
|
143
155
|
async start() {
|
|
144
156
|
if (this._isRunning) {
|
|
145
|
-
debug(
|
|
157
|
+
debug('At least one DB instance is already running, not starting again...');
|
|
146
158
|
return;
|
|
147
159
|
}
|
|
148
|
-
debug(
|
|
160
|
+
debug('starting DB instances...');
|
|
149
161
|
await this.createObjectsDB();
|
|
150
162
|
await this.createStatesDB();
|
|
151
163
|
this._isRunning = true;
|
|
152
|
-
debug(
|
|
164
|
+
debug('DB instances started');
|
|
153
165
|
}
|
|
154
166
|
async stop() {
|
|
155
167
|
if (!this._isRunning) {
|
|
156
|
-
debug(
|
|
168
|
+
debug('No DB instance is running, nothing to stop...');
|
|
157
169
|
return;
|
|
158
170
|
}
|
|
159
|
-
debug(
|
|
171
|
+
debug('Stopping DB instances...');
|
|
160
172
|
// Stop clients before servers
|
|
161
173
|
await this._objectsClient?.destroy();
|
|
162
174
|
await this._objectsServer?.destroy();
|
|
@@ -167,36 +179,32 @@ class DBConnection extends events_1.default {
|
|
|
167
179
|
this._statesClient = null;
|
|
168
180
|
this._statesServer = null;
|
|
169
181
|
this._isRunning = false;
|
|
170
|
-
debug(
|
|
182
|
+
debug('DB instances stopped');
|
|
171
183
|
}
|
|
172
184
|
/** Creates the objects DB and sets up listeners for it */
|
|
173
185
|
async createObjectsDB() {
|
|
174
|
-
debug(
|
|
186
|
+
debug('creating objects DB');
|
|
175
187
|
const objectsType = this.objectsType;
|
|
176
188
|
debug(` => objects DB type: ${objectsType}`);
|
|
177
189
|
const settings = {
|
|
178
190
|
connection: {
|
|
179
191
|
type: objectsType,
|
|
180
|
-
host:
|
|
192
|
+
host: '127.0.0.1',
|
|
181
193
|
port: 19001,
|
|
182
|
-
user:
|
|
183
|
-
pass:
|
|
194
|
+
user: '',
|
|
195
|
+
pass: '',
|
|
184
196
|
noFileCache: false,
|
|
185
197
|
connectTimeout: 2000,
|
|
186
198
|
},
|
|
187
199
|
logger: this.logger,
|
|
188
200
|
};
|
|
189
201
|
const objectsDbPath = require.resolve(`@iobroker/db-objects-${objectsType}`, {
|
|
190
|
-
paths: [
|
|
191
|
-
path.join(this.testDir, "node_modules"),
|
|
192
|
-
path.join(this.testControllerDir, "node_modules"),
|
|
193
|
-
],
|
|
202
|
+
paths: [path.join(this.testDir, 'node_modules'), path.join(this.testControllerDir, 'node_modules')],
|
|
194
203
|
});
|
|
195
204
|
debug(` => objects DB lib found at ${objectsDbPath}`);
|
|
196
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
197
205
|
const { Server, Client } = require(objectsDbPath);
|
|
198
206
|
// First create the server
|
|
199
|
-
await new Promise(
|
|
207
|
+
await new Promise(resolve => {
|
|
200
208
|
this._objectsServer = new Server({
|
|
201
209
|
...settings,
|
|
202
210
|
connected: () => {
|
|
@@ -205,17 +213,17 @@ class DBConnection extends events_1.default {
|
|
|
205
213
|
});
|
|
206
214
|
});
|
|
207
215
|
// Then the client
|
|
208
|
-
await new Promise(
|
|
216
|
+
await new Promise(resolve => {
|
|
209
217
|
this._objectsClient = new Client({
|
|
210
218
|
...settings,
|
|
211
219
|
connected: () => {
|
|
212
|
-
this._objectsClient.subscribe(
|
|
220
|
+
this._objectsClient.subscribe('*');
|
|
213
221
|
resolve();
|
|
214
222
|
},
|
|
215
|
-
change: this.emit.bind(this,
|
|
223
|
+
change: this.emit.bind(this, 'objectChange'),
|
|
216
224
|
});
|
|
217
225
|
});
|
|
218
|
-
debug(
|
|
226
|
+
debug(' => done!');
|
|
219
227
|
}
|
|
220
228
|
/** Creates the states DB and sets up listeners for it */
|
|
221
229
|
async createStatesDB() {
|
|
@@ -225,7 +233,7 @@ class DBConnection extends events_1.default {
|
|
|
225
233
|
const settings = {
|
|
226
234
|
connection: {
|
|
227
235
|
type: statesType,
|
|
228
|
-
host:
|
|
236
|
+
host: '127.0.0.1',
|
|
229
237
|
port: 19000,
|
|
230
238
|
options: {
|
|
231
239
|
auth_pass: null,
|
|
@@ -235,16 +243,12 @@ class DBConnection extends events_1.default {
|
|
|
235
243
|
logger: this.logger,
|
|
236
244
|
};
|
|
237
245
|
const statesDbPath = require.resolve(`@iobroker/db-states-${statesType}`, {
|
|
238
|
-
paths: [
|
|
239
|
-
path.join(this.testDir, "node_modules"),
|
|
240
|
-
path.join(this.testControllerDir, "node_modules"),
|
|
241
|
-
],
|
|
246
|
+
paths: [path.join(this.testDir, 'node_modules'), path.join(this.testControllerDir, 'node_modules')],
|
|
242
247
|
});
|
|
243
248
|
debug(` => states DB lib found at ${statesDbPath}`);
|
|
244
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
245
249
|
const { Server, Client } = require(statesDbPath);
|
|
246
250
|
// First create the server
|
|
247
|
-
await new Promise(
|
|
251
|
+
await new Promise(resolve => {
|
|
248
252
|
this._statesServer = new Server({
|
|
249
253
|
...settings,
|
|
250
254
|
connected: () => {
|
|
@@ -253,43 +257,41 @@ class DBConnection extends events_1.default {
|
|
|
253
257
|
});
|
|
254
258
|
});
|
|
255
259
|
// Then the client
|
|
256
|
-
await new Promise(
|
|
260
|
+
await new Promise(resolve => {
|
|
257
261
|
this._statesClient = new Client({
|
|
258
262
|
...settings,
|
|
259
263
|
connected: () => {
|
|
260
|
-
this._statesClient.subscribe(
|
|
264
|
+
this._statesClient.subscribe('*');
|
|
261
265
|
resolve();
|
|
262
266
|
},
|
|
263
|
-
change: this.emit.bind(this,
|
|
267
|
+
change: this.emit.bind(this, 'stateChange'),
|
|
264
268
|
});
|
|
265
269
|
});
|
|
266
|
-
debug(
|
|
270
|
+
debug(' => done!');
|
|
267
271
|
}
|
|
268
272
|
subscribeMessage(id) {
|
|
269
273
|
if (!this._statesClient) {
|
|
270
|
-
throw new Error(
|
|
274
|
+
throw new Error('States DB is not running');
|
|
271
275
|
}
|
|
272
276
|
return this._statesClient.subscribeMessage(id);
|
|
273
277
|
}
|
|
274
278
|
pushMessage(instanceId, msg, callback) {
|
|
275
279
|
if (!this._statesClient) {
|
|
276
|
-
throw new Error(
|
|
280
|
+
throw new Error('States DB is not running');
|
|
277
281
|
}
|
|
278
282
|
this._statesClient.pushMessage(instanceId, msg, callback);
|
|
279
283
|
}
|
|
280
|
-
|
|
284
|
+
getStateIDs(pattern = '*') {
|
|
281
285
|
if (!this._statesClient) {
|
|
282
|
-
throw new Error(
|
|
286
|
+
throw new Error('States DB is not running');
|
|
283
287
|
}
|
|
284
|
-
return
|
|
285
|
-
this._statesClient.getKeys?.(pattern));
|
|
288
|
+
return this._statesClient.getKeysAsync?.(pattern) || this._statesClient.getKeys?.(pattern);
|
|
286
289
|
}
|
|
287
|
-
|
|
290
|
+
getObjectIDs(pattern = '*') {
|
|
288
291
|
if (!this._objectsClient) {
|
|
289
|
-
throw new Error(
|
|
292
|
+
throw new Error('Objects DB is not running');
|
|
290
293
|
}
|
|
291
|
-
return
|
|
292
|
-
this._objectsClient.getKeys?.(pattern));
|
|
294
|
+
return this._objectsClient.getKeysAsync?.(pattern) || this._objectsClient.getKeys?.(pattern);
|
|
293
295
|
}
|
|
294
296
|
}
|
|
295
297
|
exports.DBConnection = DBConnection;
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/// <reference types="iobroker" />
|
|
5
|
-
/// <reference types="node" />
|
|
6
|
-
import { ChildProcess } from "child_process";
|
|
7
|
-
import { EventEmitter } from "events";
|
|
8
|
-
import type { DBConnection } from "./dbConnection";
|
|
1
|
+
import { type ChildProcess } from 'child_process';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import type { DBConnection } from './dbConnection';
|
|
9
4
|
export interface TestHarness {
|
|
10
|
-
on(event:
|
|
11
|
-
on(event:
|
|
12
|
-
on(event:
|
|
5
|
+
on(event: 'objectChange', handler: ioBroker.ObjectChangeHandler): this;
|
|
6
|
+
on(event: 'stateChange', handler: ioBroker.StateChangeHandler): this;
|
|
7
|
+
on(event: 'failed', handler: (codeOrSignal: number | string) => void): this;
|
|
13
8
|
}
|
|
14
9
|
/**
|
|
15
10
|
* The test harness capsules the execution of the JS-Controller and the adapter instance and monitors their status.
|
|
@@ -46,11 +41,13 @@ export declare class TestHarness extends EventEmitter {
|
|
|
46
41
|
stopController(): Promise<void>;
|
|
47
42
|
/**
|
|
48
43
|
* Starts the adapter in a separate process and monitors its status
|
|
44
|
+
*
|
|
49
45
|
* @param env Additional environment variables to set
|
|
50
46
|
*/
|
|
51
47
|
startAdapter(env?: NodeJS.ProcessEnv): Promise<void>;
|
|
52
48
|
/**
|
|
53
49
|
* Starts the adapter in a separate process and resolves after it has started
|
|
50
|
+
*
|
|
54
51
|
* @param waitForConnection By default, the test will wait for the adapter's `alive` state to become true. Set this to `true` to wait for the `info.connection` state instead.
|
|
55
52
|
* @param env Additional environment variables to set
|
|
56
53
|
*/
|
|
@@ -65,7 +62,7 @@ export declare class TestHarness extends EventEmitter {
|
|
|
65
62
|
* Updates the adapter config. The changes can be a subset of the target object
|
|
66
63
|
*/
|
|
67
64
|
changeAdapterConfig(adapterName: string, changes: Record<string, any>): Promise<void>;
|
|
68
|
-
getAdapterExecutionMode(): ioBroker.AdapterCommon[
|
|
65
|
+
getAdapterExecutionMode(): ioBroker.AdapterCommon['mode'];
|
|
69
66
|
/** Enables the sendTo method */
|
|
70
67
|
enableSendTo(): Promise<void>;
|
|
71
68
|
private sendToID;
|
|
@@ -15,19 +15,28 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
37
|
};
|
|
28
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
39
|
exports.TestHarness = void 0;
|
|
30
|
-
/* eslint-disable @typescript-eslint/no-inferrable-types */
|
|
31
40
|
const async_1 = require("alcalzone-shared/async");
|
|
32
41
|
const objects_1 = require("alcalzone-shared/objects");
|
|
33
42
|
const child_process_1 = require("child_process");
|
|
@@ -36,9 +45,9 @@ const events_1 = require("events");
|
|
|
36
45
|
const path = __importStar(require("path"));
|
|
37
46
|
const adapterTools_1 = require("../../../lib/adapterTools");
|
|
38
47
|
const tools_1 = require("./tools");
|
|
39
|
-
const debug = (0, debug_1.default)(
|
|
48
|
+
const debug = (0, debug_1.default)('testing:integration:TestHarness');
|
|
40
49
|
const isWindows = /^win/.test(process.platform);
|
|
41
|
-
const fromAdapterID =
|
|
50
|
+
const fromAdapterID = 'system.adapter.test.0';
|
|
42
51
|
/**
|
|
43
52
|
* The test harness capsules the execution of the JS-Controller and the adapter instance and monitors their status.
|
|
44
53
|
* Use it in every test to start a fresh adapter instance
|
|
@@ -54,7 +63,7 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
54
63
|
this.testDir = testDir;
|
|
55
64
|
this.dbConnection = dbConnection;
|
|
56
65
|
this.sendToID = 1;
|
|
57
|
-
debug(
|
|
66
|
+
debug('Creating instance');
|
|
58
67
|
this.adapterName = (0, adapterTools_1.getAdapterName)(this.adapterDir);
|
|
59
68
|
this.appName = (0, adapterTools_1.getAppName)(adapterDir);
|
|
60
69
|
this.testControllerDir = (0, tools_1.getTestControllerDir)(this.appName, testDir);
|
|
@@ -64,24 +73,24 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
64
73
|
debug(` adapter: ${this.testAdapterDir}`);
|
|
65
74
|
debug(` appName: ${this.appName}`);
|
|
66
75
|
debug(` adapterName: ${this.adapterName}`);
|
|
67
|
-
dbConnection.on(
|
|
68
|
-
this.emit(
|
|
76
|
+
dbConnection.on('objectChange', (id, obj) => {
|
|
77
|
+
this.emit('objectChange', id, obj);
|
|
69
78
|
});
|
|
70
|
-
dbConnection.on(
|
|
71
|
-
this.emit(
|
|
79
|
+
dbConnection.on('stateChange', (id, state) => {
|
|
80
|
+
this.emit('stateChange', id, state);
|
|
72
81
|
});
|
|
73
82
|
}
|
|
74
83
|
/** Gives direct access to the Objects DB */
|
|
75
84
|
get objects() {
|
|
76
85
|
if (!this.dbConnection.objectsClient) {
|
|
77
|
-
throw new Error(
|
|
86
|
+
throw new Error('Objects DB is not running');
|
|
78
87
|
}
|
|
79
88
|
return this.dbConnection.objectsClient;
|
|
80
89
|
}
|
|
81
90
|
/** Gives direct access to the States DB */
|
|
82
91
|
get states() {
|
|
83
92
|
if (!this.dbConnection.statesClient) {
|
|
84
|
-
throw new Error(
|
|
93
|
+
throw new Error('States DB is not running');
|
|
85
94
|
}
|
|
86
95
|
return this.dbConnection.statesClient;
|
|
87
96
|
}
|
|
@@ -105,59 +114,67 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
105
114
|
}
|
|
106
115
|
/** Stops the controller instance (and the adapter if it is running) */
|
|
107
116
|
async stopController() {
|
|
108
|
-
if (!this.isControllerRunning())
|
|
117
|
+
if (!this.isControllerRunning()) {
|
|
109
118
|
return;
|
|
119
|
+
}
|
|
110
120
|
if (!this.didAdapterStop()) {
|
|
111
|
-
debug(
|
|
121
|
+
debug('Stopping adapter instance...');
|
|
112
122
|
// Give the adapter time to stop (as long as configured in the io-package.json)
|
|
113
123
|
let stopTimeout;
|
|
114
124
|
try {
|
|
115
|
-
stopTimeout = (await this.dbConnection.getObject(`system.adapter.${this.adapterName}.0`))
|
|
125
|
+
stopTimeout = (await this.dbConnection.getObject(`system.adapter.${this.adapterName}.0`))
|
|
126
|
+
.common.stopTimeout;
|
|
116
127
|
stopTimeout += 1000;
|
|
117
128
|
}
|
|
118
|
-
catch {
|
|
119
|
-
|
|
129
|
+
catch {
|
|
130
|
+
// ignore
|
|
131
|
+
}
|
|
132
|
+
stopTimeout ||= 5000; // default 5s
|
|
120
133
|
debug(` => giving it ${stopTimeout}ms to terminate`);
|
|
121
134
|
await Promise.race([this.stopAdapter(), (0, async_1.wait)(stopTimeout)]);
|
|
122
135
|
if (this.isAdapterRunning()) {
|
|
123
|
-
debug(
|
|
124
|
-
this._adapterProcess.kill(
|
|
136
|
+
debug('Adapter did not terminate, killing it');
|
|
137
|
+
this._adapterProcess.kill('SIGKILL');
|
|
125
138
|
}
|
|
126
139
|
else {
|
|
127
|
-
debug(
|
|
140
|
+
debug('Adapter terminated');
|
|
128
141
|
}
|
|
129
142
|
}
|
|
130
143
|
else {
|
|
131
|
-
debug(
|
|
144
|
+
debug('Adapter failed to start - no need to terminate!');
|
|
132
145
|
}
|
|
133
146
|
await this.dbConnection.stop();
|
|
134
147
|
}
|
|
135
148
|
/**
|
|
136
149
|
* Starts the adapter in a separate process and monitors its status
|
|
150
|
+
*
|
|
137
151
|
* @param env Additional environment variables to set
|
|
138
152
|
*/
|
|
139
153
|
async startAdapter(env = {}) {
|
|
140
|
-
if (this.isAdapterRunning())
|
|
141
|
-
throw new Error(
|
|
142
|
-
|
|
143
|
-
|
|
154
|
+
if (this.isAdapterRunning()) {
|
|
155
|
+
throw new Error('The adapter is already running!');
|
|
156
|
+
}
|
|
157
|
+
else if (this.didAdapterStop()) {
|
|
158
|
+
throw new Error('This test harness has already been used. Please create a new one for each test!');
|
|
159
|
+
}
|
|
144
160
|
const mainFileAbsolute = await (0, adapterTools_1.locateAdapterMainFile)(this.testAdapterDir);
|
|
145
161
|
const mainFileRelative = path.relative(this.testAdapterDir, mainFileAbsolute);
|
|
146
162
|
const onClose = (code, signal) => {
|
|
147
163
|
this._adapterProcess.removeAllListeners();
|
|
148
164
|
this._adapterExit = code != undefined ? code : signal;
|
|
149
|
-
this.emit(
|
|
165
|
+
this.emit('failed', this._adapterExit);
|
|
150
166
|
};
|
|
151
|
-
this._adapterProcess = (0, child_process_1.spawn)(isWindows ?
|
|
167
|
+
this._adapterProcess = (0, child_process_1.spawn)(isWindows ? 'node.exe' : 'node', [mainFileRelative, '--console'], {
|
|
152
168
|
cwd: this.testAdapterDir,
|
|
153
|
-
stdio: [
|
|
169
|
+
stdio: ['inherit', 'inherit', 'inherit'],
|
|
154
170
|
env: { ...process.env, ...env },
|
|
155
171
|
})
|
|
156
|
-
.on(
|
|
157
|
-
.on(
|
|
172
|
+
.on('close', onClose)
|
|
173
|
+
.on('exit', onClose);
|
|
158
174
|
}
|
|
159
175
|
/**
|
|
160
176
|
* Starts the adapter in a separate process and resolves after it has started
|
|
177
|
+
*
|
|
161
178
|
* @param waitForConnection By default, the test will wait for the adapter's `alive` state to become true. Set this to `true` to wait for the `info.connection` state instead.
|
|
162
179
|
* @param env Additional environment variables to set
|
|
163
180
|
*/
|
|
@@ -166,13 +183,13 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
166
183
|
const waitForStateId = waitForConnection
|
|
167
184
|
? `${this.adapterName}.0.info.connection`
|
|
168
185
|
: `system.adapter.${this.adapterName}.0.alive`;
|
|
169
|
-
this.on(
|
|
186
|
+
void this.on('stateChange', (id, state) => {
|
|
170
187
|
if (id === waitForStateId && state && state.val === true) {
|
|
171
188
|
resolve();
|
|
172
189
|
}
|
|
173
190
|
})
|
|
174
|
-
.on(
|
|
175
|
-
reject(new Error(`The adapter startup was interrupted unexpectedly with ${typeof code ===
|
|
191
|
+
.on('failed', code => {
|
|
192
|
+
reject(new Error(`The adapter startup was interrupted unexpectedly with ${typeof code === 'number' ? 'code' : 'signal'} ${code}`));
|
|
176
193
|
})
|
|
177
194
|
.startAdapter(env);
|
|
178
195
|
});
|
|
@@ -187,33 +204,34 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
187
204
|
}
|
|
188
205
|
/** Stops the adapter process */
|
|
189
206
|
stopAdapter() {
|
|
190
|
-
if (!this.isAdapterRunning())
|
|
207
|
+
if (!this.isAdapterRunning()) {
|
|
191
208
|
return;
|
|
209
|
+
}
|
|
210
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
192
211
|
return new Promise(async (resolve) => {
|
|
193
212
|
const onClose = (code, signal) => {
|
|
194
|
-
if (!this._adapterProcess)
|
|
213
|
+
if (!this._adapterProcess) {
|
|
195
214
|
return;
|
|
215
|
+
}
|
|
196
216
|
this._adapterProcess.removeAllListeners();
|
|
197
217
|
this._adapterExit = code != undefined ? code : signal;
|
|
198
218
|
this._adapterProcess = undefined;
|
|
199
|
-
debug(
|
|
219
|
+
debug('Adapter process terminated:');
|
|
200
220
|
debug(` Code: ${code}`);
|
|
201
221
|
debug(` Signal: ${signal}`);
|
|
202
222
|
resolve();
|
|
203
223
|
};
|
|
204
|
-
this._adapterProcess.removeAllListeners()
|
|
205
|
-
.on("close", onClose)
|
|
206
|
-
.on("exit", onClose);
|
|
224
|
+
this._adapterProcess.removeAllListeners().on('close', onClose).on('exit', onClose);
|
|
207
225
|
// Tell adapter to stop
|
|
208
226
|
try {
|
|
209
227
|
await this.dbConnection.setState(`system.adapter.${this.adapterName}.0.sigKill`, {
|
|
210
228
|
val: -1,
|
|
211
|
-
from:
|
|
229
|
+
from: 'system.host.testing',
|
|
212
230
|
});
|
|
213
231
|
}
|
|
214
232
|
catch {
|
|
215
233
|
// DB connection may be closed already, kill the process
|
|
216
|
-
this._adapterProcess?.kill(
|
|
234
|
+
this._adapterProcess?.kill('SIGTERM');
|
|
217
235
|
}
|
|
218
236
|
});
|
|
219
237
|
}
|
|
@@ -234,9 +252,11 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
234
252
|
/** Enables the sendTo method */
|
|
235
253
|
async enableSendTo() {
|
|
236
254
|
await this.dbConnection.setObject(fromAdapterID, {
|
|
237
|
-
type:
|
|
255
|
+
type: 'instance',
|
|
238
256
|
common: {},
|
|
239
257
|
native: {},
|
|
258
|
+
instanceObjects: [],
|
|
259
|
+
objects: [],
|
|
240
260
|
});
|
|
241
261
|
this.dbConnection.subscribeMessage(fromAdapterID);
|
|
242
262
|
}
|
|
@@ -245,10 +265,10 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
245
265
|
const stateChangedHandler = (id, state) => {
|
|
246
266
|
if (id === `messagebox.${fromAdapterID}`) {
|
|
247
267
|
callback(state.message);
|
|
248
|
-
this.removeListener(
|
|
268
|
+
this.removeListener('stateChange', stateChangedHandler);
|
|
249
269
|
}
|
|
250
270
|
};
|
|
251
|
-
this.addListener(
|
|
271
|
+
this.addListener('stateChange', stateChangedHandler);
|
|
252
272
|
this.dbConnection.pushMessage(`system.adapter.${target}`, {
|
|
253
273
|
command: command,
|
|
254
274
|
message: message,
|
|
@@ -259,7 +279,7 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
259
279
|
ack: false,
|
|
260
280
|
time: Date.now(),
|
|
261
281
|
},
|
|
262
|
-
}, (err, id) => console.log(
|
|
282
|
+
}, (err, id) => console.log(`published message ${id}`));
|
|
263
283
|
}
|
|
264
284
|
}
|
|
265
285
|
exports.TestHarness = TestHarness;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createLogger =
|
|
3
|
+
exports.createLogger = createLogger;
|
|
4
4
|
var LoglevelOrder;
|
|
5
5
|
(function (LoglevelOrder) {
|
|
6
6
|
LoglevelOrder[LoglevelOrder["error"] = 0] = "error";
|
|
@@ -10,8 +10,7 @@ var LoglevelOrder;
|
|
|
10
10
|
LoglevelOrder[LoglevelOrder["silly"] = 4] = "silly";
|
|
11
11
|
})(LoglevelOrder || (LoglevelOrder = {}));
|
|
12
12
|
function createLogger(loglevel) {
|
|
13
|
-
const loglevelNumeric = LoglevelOrder[loglevel ??
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
13
|
+
const loglevelNumeric = LoglevelOrder[loglevel ?? 'debug'] ?? LoglevelOrder.debug;
|
|
15
14
|
const ignore = () => { };
|
|
16
15
|
return {
|
|
17
16
|
error: loglevelNumeric >= LoglevelOrder.error ? console.error : ignore,
|
|
@@ -22,4 +21,3 @@ function createLogger(loglevel) {
|
|
|
22
21
|
level: loglevel,
|
|
23
22
|
};
|
|
24
23
|
}
|
|
25
|
-
exports.createLogger = createLogger;
|