@iobroker/testing 2.5.2 → 2.5.5
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/CHANGELOG.md +10 -1
- package/LICENSE +1 -1
- package/build/index.js +5 -1
- package/build/lib/adapterTools.d.ts +1 -10
- package/build/lib/adapterTools.js +10 -7
- package/build/tests/index.js +1 -0
- package/build/tests/integration/index.js +33 -26
- package/build/tests/integration/lib/adapterSetup.d.ts +3 -4
- package/build/tests/integration/lib/adapterSetup.js +23 -18
- package/build/tests/integration/lib/controllerSetup.d.ts +3 -6
- package/build/tests/integration/lib/controllerSetup.js +29 -21
- package/build/tests/integration/lib/dbConnection.d.ts +46 -22
- package/build/tests/integration/lib/dbConnection.js +263 -47
- package/build/tests/integration/lib/harness.d.ts +7 -11
- package/build/tests/integration/lib/harness.js +48 -104
- package/build/tests/integration/lib/tools.js +5 -1
- package/build/tests/packageFiles/index.js +18 -1
- package/build/tests/unit/mocks/mockAdapterCore.js +5 -1
- package/package.json +26 -26
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -18,72 +22,284 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
18
22
|
__setModuleDefault(result, mod);
|
|
19
23
|
return result;
|
|
20
24
|
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
21
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
29
|
exports.DBConnection = void 0;
|
|
30
|
+
const debug_1 = __importDefault(require("debug"));
|
|
31
|
+
const events_1 = __importDefault(require("events"));
|
|
23
32
|
const fs_extra_1 = require("fs-extra");
|
|
24
33
|
const path = __importStar(require("path"));
|
|
25
34
|
const tools_1 = require("./tools");
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
const debug = (0, debug_1.default)("testing:integration:DBConnection");
|
|
36
|
+
/** The logger instance for the objects and states DB */
|
|
37
|
+
const logger = {
|
|
38
|
+
silly: console.log,
|
|
39
|
+
debug: console.log,
|
|
40
|
+
info: console.log,
|
|
41
|
+
warn: console.warn,
|
|
42
|
+
error: console.error,
|
|
43
|
+
};
|
|
44
|
+
/** The DB connection capsules access to the states and objects DB */
|
|
45
|
+
class DBConnection extends events_1.default {
|
|
28
46
|
/**
|
|
29
47
|
* @param appName The branded name of "iobroker"
|
|
30
48
|
* @param testDir The directory the integration tests are executed in
|
|
31
49
|
*/
|
|
32
50
|
constructor(appName, testDir) {
|
|
51
|
+
super();
|
|
33
52
|
this.appName = appName;
|
|
34
53
|
this.testDir = testDir;
|
|
54
|
+
this._isRunning = false;
|
|
55
|
+
this.getObject = async (id) => {
|
|
56
|
+
if (!this._objectsClient) {
|
|
57
|
+
throw new Error("Objects DB is not running");
|
|
58
|
+
}
|
|
59
|
+
return this._objectsClient.getObjectAsync(id);
|
|
60
|
+
};
|
|
61
|
+
this.setObject = async (...args) => {
|
|
62
|
+
if (!this._objectsClient) {
|
|
63
|
+
throw new Error("Objects DB is not running");
|
|
64
|
+
}
|
|
65
|
+
return this._objectsClient.setObjectAsync(...args);
|
|
66
|
+
};
|
|
67
|
+
this.delObject = async (...args) => {
|
|
68
|
+
if (!this._objectsClient) {
|
|
69
|
+
throw new Error("Objects DB is not running");
|
|
70
|
+
}
|
|
71
|
+
return this._objectsClient.delObjectAsync(...args);
|
|
72
|
+
};
|
|
73
|
+
this.getState = async (id) => {
|
|
74
|
+
if (!this._statesClient) {
|
|
75
|
+
throw new Error("States DB is not running");
|
|
76
|
+
}
|
|
77
|
+
return this._statesClient.getStateAsync(id);
|
|
78
|
+
};
|
|
79
|
+
this.setState = (async (...args) => {
|
|
80
|
+
if (!this._statesClient) {
|
|
81
|
+
throw new Error("States DB is not running");
|
|
82
|
+
}
|
|
83
|
+
return this._statesClient.setStateAsync(...args);
|
|
84
|
+
});
|
|
85
|
+
this.delState = async (...args) => {
|
|
86
|
+
if (!this._statesClient) {
|
|
87
|
+
throw new Error("States DB is not running");
|
|
88
|
+
}
|
|
89
|
+
return this._statesClient.delStateAsync(...args);
|
|
90
|
+
};
|
|
91
|
+
this.getObjectViewAsync = async (...args) => {
|
|
92
|
+
if (!this._objectsClient) {
|
|
93
|
+
throw new Error("Objects DB is not running");
|
|
94
|
+
}
|
|
95
|
+
return this._objectsClient.getObjectViewAsync(...args);
|
|
96
|
+
};
|
|
97
|
+
this.testControllerDir = (0, tools_1.getTestControllerDir)(this.appName, testDir);
|
|
35
98
|
this.testDataDir = (0, tools_1.getTestDataDir)(appName, testDir);
|
|
36
|
-
this.objectsPath = path.join(this.testDataDir, "objects.json");
|
|
37
|
-
this.statesPath = path.join(this.testDataDir, "states.json");
|
|
38
|
-
}
|
|
39
|
-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
40
|
-
async readObjectsDB() {
|
|
41
|
-
// debug(`reading objects db...`);
|
|
42
|
-
// debug(` dataDir: ${dataDir}`);
|
|
43
|
-
// debug(` objectsPath: ${objectsPath}`);
|
|
44
|
-
if (await (0, fs_extra_1.pathExists)(this.objectsPath)) {
|
|
45
|
-
// debug(` exists: true`);
|
|
46
|
-
return (0, fs_extra_1.readJSON)(this.objectsPath, { encoding: "utf8" });
|
|
47
|
-
}
|
|
48
99
|
}
|
|
49
|
-
|
|
50
|
-
|
|
100
|
+
/** The underlying objects client instance that can be used to access the objects DB */
|
|
101
|
+
get objectsClient() {
|
|
102
|
+
return this._objectsClient;
|
|
103
|
+
}
|
|
104
|
+
/** The underlying states client instance that can be used to access the states DB */
|
|
105
|
+
get statesClient() {
|
|
106
|
+
return this._statesClient;
|
|
107
|
+
}
|
|
108
|
+
get objectsType() {
|
|
109
|
+
return this.getSystemConfig().objects.type;
|
|
110
|
+
}
|
|
111
|
+
get objectsPath() {
|
|
112
|
+
return path.join(this.testDataDir, this.objectsType === "file" ? "objects.json" : "objects.jsonl");
|
|
113
|
+
}
|
|
114
|
+
get statesType() {
|
|
115
|
+
return this.getSystemConfig().states.type;
|
|
116
|
+
}
|
|
117
|
+
get statesPath() {
|
|
118
|
+
return path.join(this.testDataDir, this.statesType === "file" ? "states.json" : "states.jsonl");
|
|
119
|
+
}
|
|
120
|
+
getSystemConfig() {
|
|
121
|
+
const systemFilename = path.join(this.testDataDir, `${this.appName}.json`);
|
|
122
|
+
return (0, fs_extra_1.readJSONSync)(systemFilename);
|
|
123
|
+
}
|
|
124
|
+
async backup() {
|
|
125
|
+
debug("Creating DB backup...");
|
|
126
|
+
const wasRunning = this._isRunning;
|
|
127
|
+
await this.stop();
|
|
128
|
+
const objects = await (0, fs_extra_1.readFile)(this.objectsPath);
|
|
129
|
+
const states = await (0, fs_extra_1.readFile)(this.statesPath);
|
|
130
|
+
if (wasRunning)
|
|
131
|
+
await this.start();
|
|
132
|
+
return { objects, states };
|
|
133
|
+
}
|
|
134
|
+
async restore(objects, states) {
|
|
135
|
+
debug("Restoring DB backup...");
|
|
136
|
+
const wasRunning = this._isRunning;
|
|
137
|
+
await this.stop();
|
|
138
|
+
await (0, fs_extra_1.writeFile)(this.objectsPath, objects);
|
|
139
|
+
await (0, fs_extra_1.writeFile)(this.statesPath, states);
|
|
140
|
+
if (wasRunning)
|
|
141
|
+
await this.start();
|
|
142
|
+
}
|
|
143
|
+
setSystemConfig(systemConfig) {
|
|
144
|
+
const systemFilename = path.join(this.testDataDir, `${this.appName}.json`);
|
|
145
|
+
(0, fs_extra_1.writeJSONSync)(systemFilename, systemConfig, { spaces: 2 });
|
|
146
|
+
}
|
|
147
|
+
get isRunning() {
|
|
148
|
+
return this._isRunning;
|
|
149
|
+
}
|
|
150
|
+
async start() {
|
|
151
|
+
if (this._isRunning) {
|
|
152
|
+
debug("At least one DB instance is already running, not starting again...");
|
|
51
153
|
return;
|
|
52
|
-
|
|
154
|
+
}
|
|
155
|
+
debug("starting DB instances...");
|
|
156
|
+
await this.createObjectsDB();
|
|
157
|
+
await this.createStatesDB();
|
|
158
|
+
this._isRunning = true;
|
|
159
|
+
debug("DB instances started");
|
|
53
160
|
}
|
|
54
|
-
async
|
|
55
|
-
|
|
161
|
+
async stop() {
|
|
162
|
+
var _a, _b, _c, _d;
|
|
163
|
+
if (!this._isRunning) {
|
|
164
|
+
debug("No DB instance is running, nothing to stop...");
|
|
56
165
|
return;
|
|
57
|
-
return (0, fs_extra_1.writeJSON)(this.statesPath, states);
|
|
58
|
-
}
|
|
59
|
-
async readStatesDB() {
|
|
60
|
-
// debug(`reading states db...`);
|
|
61
|
-
// debug(` dataDir: ${dataDir}`);
|
|
62
|
-
// debug(` statesPath: ${statesPath}`);
|
|
63
|
-
if (await (0, fs_extra_1.pathExists)(this.statesPath)) {
|
|
64
|
-
// debug(` exists: true`);
|
|
65
|
-
return (0, fs_extra_1.readJSON)(this.statesPath, { encoding: "utf8" });
|
|
66
166
|
}
|
|
167
|
+
debug("Stopping DB instances...");
|
|
168
|
+
// Stop clients before servers
|
|
169
|
+
await ((_a = this._objectsClient) === null || _a === void 0 ? void 0 : _a.destroy());
|
|
170
|
+
await ((_b = this._objectsServer) === null || _b === void 0 ? void 0 : _b.destroy());
|
|
171
|
+
await ((_c = this._statesClient) === null || _c === void 0 ? void 0 : _c.destroy());
|
|
172
|
+
await ((_d = this._statesServer) === null || _d === void 0 ? void 0 : _d.destroy());
|
|
173
|
+
this._objectsClient = null;
|
|
174
|
+
this._objectsServer = null;
|
|
175
|
+
this._statesClient = null;
|
|
176
|
+
this._statesServer = null;
|
|
177
|
+
this._isRunning = false;
|
|
178
|
+
debug("DB instances stopped");
|
|
67
179
|
}
|
|
68
|
-
/**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
180
|
+
/** Creates the objects DB and sets up listeners for it */
|
|
181
|
+
async createObjectsDB() {
|
|
182
|
+
debug("creating objects DB");
|
|
183
|
+
const objectsType = this.objectsType;
|
|
184
|
+
debug(` => objects DB type: ${objectsType}`);
|
|
185
|
+
const settings = {
|
|
186
|
+
connection: {
|
|
187
|
+
type: objectsType,
|
|
188
|
+
host: "127.0.0.1",
|
|
189
|
+
port: 19001,
|
|
190
|
+
user: "",
|
|
191
|
+
pass: "",
|
|
192
|
+
noFileCache: false,
|
|
193
|
+
connectTimeout: 2000,
|
|
194
|
+
},
|
|
195
|
+
logger,
|
|
196
|
+
};
|
|
197
|
+
const objectsDbPath = require.resolve(`@iobroker/db-objects-${objectsType}`, {
|
|
198
|
+
paths: [
|
|
199
|
+
path.join(this.testDir, "node_modules"),
|
|
200
|
+
path.join(this.testControllerDir, "node_modules"),
|
|
201
|
+
],
|
|
202
|
+
});
|
|
203
|
+
debug(` => objects DB lib found at ${objectsDbPath}`);
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
205
|
+
const { Server, Client } = require(objectsDbPath);
|
|
206
|
+
// First create the server
|
|
207
|
+
await new Promise((resolve) => {
|
|
208
|
+
this._objectsServer = new Server({
|
|
209
|
+
...settings,
|
|
210
|
+
connected: () => {
|
|
211
|
+
resolve();
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
// Then the client
|
|
216
|
+
await new Promise((resolve) => {
|
|
217
|
+
this._objectsClient = new Client({
|
|
218
|
+
...settings,
|
|
219
|
+
connected: () => {
|
|
220
|
+
this._objectsClient.subscribe("*");
|
|
221
|
+
resolve();
|
|
222
|
+
},
|
|
223
|
+
change: this.emit.bind(this, "objectChange"),
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
debug(" => done!");
|
|
78
227
|
}
|
|
79
|
-
/**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
228
|
+
/** Creates the states DB and sets up listeners for it */
|
|
229
|
+
async createStatesDB() {
|
|
230
|
+
debug(`creating states DB`);
|
|
231
|
+
const statesType = this.statesType;
|
|
232
|
+
debug(` => states DB type: ${statesType}`);
|
|
233
|
+
const settings = {
|
|
234
|
+
connection: {
|
|
235
|
+
type: statesType,
|
|
236
|
+
host: "127.0.0.1",
|
|
237
|
+
port: 19000,
|
|
238
|
+
options: {
|
|
239
|
+
auth_pass: null,
|
|
240
|
+
retry_max_delay: 15000,
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
logger,
|
|
244
|
+
};
|
|
245
|
+
const statesDbPath = require.resolve(`@iobroker/db-states-${statesType}`, {
|
|
246
|
+
paths: [
|
|
247
|
+
path.join(this.testDir, "node_modules"),
|
|
248
|
+
path.join(this.testControllerDir, "node_modules"),
|
|
249
|
+
],
|
|
250
|
+
});
|
|
251
|
+
debug(` => states DB lib found at ${statesDbPath}`);
|
|
252
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
253
|
+
const { Server, Client } = require(statesDbPath);
|
|
254
|
+
// First create the server
|
|
255
|
+
await new Promise((resolve) => {
|
|
256
|
+
this._statesServer = new Server({
|
|
257
|
+
...settings,
|
|
258
|
+
connected: () => {
|
|
259
|
+
resolve();
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
// Then the client
|
|
264
|
+
await new Promise((resolve) => {
|
|
265
|
+
this._statesClient = new Client({
|
|
266
|
+
...settings,
|
|
267
|
+
connected: () => {
|
|
268
|
+
this._statesClient.subscribe("*");
|
|
269
|
+
resolve();
|
|
270
|
+
},
|
|
271
|
+
change: this.emit.bind(this, "stateChange"),
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
debug(" => done!");
|
|
275
|
+
}
|
|
276
|
+
subscribeMessage(id) {
|
|
277
|
+
if (!this._statesClient) {
|
|
278
|
+
throw new Error("States DB is not running");
|
|
279
|
+
}
|
|
280
|
+
return this._statesClient.subscribeMessage(id);
|
|
281
|
+
}
|
|
282
|
+
pushMessage(instanceId, msg, callback) {
|
|
283
|
+
if (!this._statesClient) {
|
|
284
|
+
throw new Error("States DB is not running");
|
|
285
|
+
}
|
|
286
|
+
this._statesClient.pushMessage(instanceId, msg, callback);
|
|
287
|
+
}
|
|
288
|
+
async getStateIDs(pattern = "*") {
|
|
289
|
+
var _a, _b, _c, _d;
|
|
290
|
+
if (!this._statesClient) {
|
|
291
|
+
throw new Error("States DB is not running");
|
|
292
|
+
}
|
|
293
|
+
return (((_b = (_a = this._statesClient).getKeysAsync) === null || _b === void 0 ? void 0 : _b.call(_a, pattern)) ||
|
|
294
|
+
((_d = (_c = this._statesClient).getKeys) === null || _d === void 0 ? void 0 : _d.call(_c, pattern)));
|
|
295
|
+
}
|
|
296
|
+
async getObjectIDs(pattern = "*") {
|
|
297
|
+
var _a, _b, _c, _d;
|
|
298
|
+
if (!this._objectsClient) {
|
|
299
|
+
throw new Error("Objects DB is not running");
|
|
300
|
+
}
|
|
301
|
+
return (((_b = (_a = this._objectsClient).getKeysAsync) === null || _b === void 0 ? void 0 : _b.call(_a, pattern)) ||
|
|
302
|
+
((_d = (_c = this._objectsClient).getKeys) === null || _d === void 0 ? void 0 : _d.call(_c, pattern)));
|
|
87
303
|
}
|
|
88
304
|
}
|
|
89
305
|
exports.DBConnection = DBConnection;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { ChildProcess } from "child_process";
|
|
4
4
|
import { EventEmitter } from "events";
|
|
5
|
+
import type { DBConnection } from "./dbConnection";
|
|
5
6
|
export interface TestHarness {
|
|
6
7
|
on(event: "objectChange", handler: ioBroker.ObjectChangeHandler): this;
|
|
7
8
|
on(event: "stateChange", handler: ioBroker.StateChangeHandler): this;
|
|
@@ -14,21 +15,19 @@ export interface TestHarness {
|
|
|
14
15
|
export declare class TestHarness extends EventEmitter {
|
|
15
16
|
private adapterDir;
|
|
16
17
|
private testDir;
|
|
18
|
+
private dbConnection;
|
|
17
19
|
/**
|
|
18
20
|
* @param adapterDir The root directory of the adapter
|
|
19
21
|
* @param testDir The directory the integration tests are executed in
|
|
20
22
|
*/
|
|
21
|
-
constructor(adapterDir: string, testDir: string);
|
|
23
|
+
constructor(adapterDir: string, testDir: string, dbConnection: DBConnection);
|
|
22
24
|
private adapterName;
|
|
23
25
|
private appName;
|
|
24
26
|
private testControllerDir;
|
|
25
27
|
private testAdapterDir;
|
|
26
|
-
|
|
27
|
-
private _objects;
|
|
28
|
-
/** The actual objects DB */
|
|
28
|
+
/** Gives direct access to the Objects DB */
|
|
29
29
|
get objects(): any;
|
|
30
|
-
|
|
31
|
-
/** The actual states DB */
|
|
30
|
+
/** Gives direct access to the States DB */
|
|
32
31
|
get states(): any;
|
|
33
32
|
private _adapterProcess;
|
|
34
33
|
/** The process the adapter is running in */
|
|
@@ -36,10 +35,6 @@ export declare class TestHarness extends EventEmitter {
|
|
|
36
35
|
private _adapterExit;
|
|
37
36
|
/** Contains the adapter exit code or signal if it was terminated unexpectedly */
|
|
38
37
|
get adapterExit(): number | string | undefined;
|
|
39
|
-
/** Creates the objects DB and sets up listeners for it */
|
|
40
|
-
private createObjectsDB;
|
|
41
|
-
/** Creates the states DB and sets up listeners for it */
|
|
42
|
-
private createStatesDB;
|
|
43
38
|
/** Checks if the controller instance is running */
|
|
44
39
|
isControllerRunning(): boolean;
|
|
45
40
|
/** Starts the controller instance by creating the databases */
|
|
@@ -65,7 +60,8 @@ export declare class TestHarness extends EventEmitter {
|
|
|
65
60
|
/**
|
|
66
61
|
* Updates the adapter config. The changes can be a subset of the target object
|
|
67
62
|
*/
|
|
68
|
-
changeAdapterConfig(
|
|
63
|
+
changeAdapterConfig(adapterName: string, changes: Record<string, any>): Promise<void>;
|
|
64
|
+
getAdapterExecutionMode(): ioBroker.AdapterCommon["mode"];
|
|
69
65
|
/** Enables the sendTo method */
|
|
70
66
|
enableSendTo(): Promise<void>;
|
|
71
67
|
private sendToID;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -23,7 +27,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
23
27
|
};
|
|
24
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
29
|
exports.TestHarness = void 0;
|
|
26
|
-
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
27
30
|
const async_1 = require("alcalzone-shared/async");
|
|
28
31
|
const objects_1 = require("alcalzone-shared/objects");
|
|
29
32
|
const child_process_1 = require("child_process");
|
|
@@ -31,18 +34,9 @@ const debug_1 = __importDefault(require("debug"));
|
|
|
31
34
|
const events_1 = require("events");
|
|
32
35
|
const path = __importStar(require("path"));
|
|
33
36
|
const adapterTools_1 = require("../../../lib/adapterTools");
|
|
34
|
-
const dbConnection_1 = require("./dbConnection");
|
|
35
37
|
const tools_1 = require("./tools");
|
|
36
38
|
const debug = (0, debug_1.default)("testing:integration:TestHarness");
|
|
37
39
|
const isWindows = /^win/.test(process.platform);
|
|
38
|
-
/** The logger instance for the objects and states DB */
|
|
39
|
-
const logger = {
|
|
40
|
-
silly: console.log,
|
|
41
|
-
debug: console.log,
|
|
42
|
-
info: console.log,
|
|
43
|
-
warn: console.warn,
|
|
44
|
-
error: console.error,
|
|
45
|
-
};
|
|
46
40
|
const fromAdapterID = "system.adapter.test.0";
|
|
47
41
|
/**
|
|
48
42
|
* The test harness capsules the execution of the JS-Controller and the adapter instance and monitors their status.
|
|
@@ -53,10 +47,11 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
53
47
|
* @param adapterDir The root directory of the adapter
|
|
54
48
|
* @param testDir The directory the integration tests are executed in
|
|
55
49
|
*/
|
|
56
|
-
constructor(adapterDir, testDir) {
|
|
50
|
+
constructor(adapterDir, testDir, dbConnection) {
|
|
57
51
|
super();
|
|
58
52
|
this.adapterDir = adapterDir;
|
|
59
53
|
this.testDir = testDir;
|
|
54
|
+
this.dbConnection = dbConnection;
|
|
60
55
|
this.sendToID = 1;
|
|
61
56
|
debug("Creating instance");
|
|
62
57
|
this.adapterName = (0, adapterTools_1.getAdapterName)(this.adapterDir);
|
|
@@ -68,15 +63,26 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
68
63
|
debug(` adapter: ${this.testAdapterDir}`);
|
|
69
64
|
debug(` appName: ${this.appName}`);
|
|
70
65
|
debug(` adapterName: ${this.adapterName}`);
|
|
71
|
-
|
|
66
|
+
dbConnection.on("objectChange", (id, obj) => {
|
|
67
|
+
this.emit("objectChange", id, obj);
|
|
68
|
+
});
|
|
69
|
+
dbConnection.on("stateChange", (id, state) => {
|
|
70
|
+
this.emit("stateChange", id, state);
|
|
71
|
+
});
|
|
72
72
|
}
|
|
73
|
-
/**
|
|
73
|
+
/** Gives direct access to the Objects DB */
|
|
74
74
|
get objects() {
|
|
75
|
-
|
|
75
|
+
if (!this.dbConnection.objectsClient) {
|
|
76
|
+
throw new Error("Objects DB is not running");
|
|
77
|
+
}
|
|
78
|
+
return this.dbConnection.objectsClient;
|
|
76
79
|
}
|
|
77
|
-
/**
|
|
80
|
+
/** Gives direct access to the States DB */
|
|
78
81
|
get states() {
|
|
79
|
-
|
|
82
|
+
if (!this.dbConnection.statesClient) {
|
|
83
|
+
throw new Error("States DB is not running");
|
|
84
|
+
}
|
|
85
|
+
return this.dbConnection.statesClient;
|
|
80
86
|
}
|
|
81
87
|
/** The process the adapter is running in */
|
|
82
88
|
get adapterProcess() {
|
|
@@ -86,68 +92,15 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
86
92
|
get adapterExit() {
|
|
87
93
|
return this._adapterExit;
|
|
88
94
|
}
|
|
89
|
-
/** Creates the objects DB and sets up listeners for it */
|
|
90
|
-
async createObjectsDB() {
|
|
91
|
-
debug("creating objects DB");
|
|
92
|
-
const Objects = require(path.join(this.testControllerDir, "lib/objects/objectsInMemServer"));
|
|
93
|
-
return new Promise((resolve) => {
|
|
94
|
-
this._objects = new Objects({
|
|
95
|
-
connection: {
|
|
96
|
-
type: "file",
|
|
97
|
-
host: "127.0.0.1",
|
|
98
|
-
port: 19001,
|
|
99
|
-
user: "",
|
|
100
|
-
pass: "",
|
|
101
|
-
noFileCache: false,
|
|
102
|
-
connectTimeout: 2000,
|
|
103
|
-
},
|
|
104
|
-
logger,
|
|
105
|
-
connected: () => {
|
|
106
|
-
debug(" => done!");
|
|
107
|
-
this._objects.subscribe("*");
|
|
108
|
-
resolve();
|
|
109
|
-
},
|
|
110
|
-
change: this.emit.bind(this, "objectChange"),
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
/** Creates the states DB and sets up listeners for it */
|
|
115
|
-
async createStatesDB() {
|
|
116
|
-
debug("creating states DB");
|
|
117
|
-
const States = require(path.join(this.testControllerDir, "lib/states/statesInMemServer"));
|
|
118
|
-
return new Promise((resolve) => {
|
|
119
|
-
this._states = new States({
|
|
120
|
-
connection: {
|
|
121
|
-
type: "file",
|
|
122
|
-
host: "127.0.0.1",
|
|
123
|
-
port: 19000,
|
|
124
|
-
options: {
|
|
125
|
-
auth_pass: null,
|
|
126
|
-
retry_max_delay: 15000,
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
logger,
|
|
130
|
-
connected: () => {
|
|
131
|
-
debug(" => done!");
|
|
132
|
-
this._states.subscribe("*");
|
|
133
|
-
resolve();
|
|
134
|
-
},
|
|
135
|
-
change: this.emit.bind(this, "stateChange"),
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
95
|
/** Checks if the controller instance is running */
|
|
140
96
|
isControllerRunning() {
|
|
141
|
-
|
|
97
|
+
// The "controller instance" is just the databases, so if they are running,
|
|
98
|
+
// the "controller" is.
|
|
99
|
+
return this.dbConnection.isRunning;
|
|
142
100
|
}
|
|
143
101
|
/** Starts the controller instance by creating the databases */
|
|
144
102
|
async startController() {
|
|
145
|
-
|
|
146
|
-
if (this.isControllerRunning())
|
|
147
|
-
throw new Error("The Controller is already running!");
|
|
148
|
-
await this.createObjectsDB();
|
|
149
|
-
await this.createStatesDB();
|
|
150
|
-
debug("controller instance created");
|
|
103
|
+
await this.dbConnection.start();
|
|
151
104
|
}
|
|
152
105
|
/** Stops the controller instance (and the adapter if it is running) */
|
|
153
106
|
async stopController() {
|
|
@@ -158,7 +111,7 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
158
111
|
// Give the adapter time to stop (as long as configured in the io-package.json)
|
|
159
112
|
let stopTimeout;
|
|
160
113
|
try {
|
|
161
|
-
stopTimeout = (await this.
|
|
114
|
+
stopTimeout = (await this.dbConnection.getObject(`system.adapter.${this.adapterName}.0`)).common.stopTimeout;
|
|
162
115
|
stopTimeout += 1000;
|
|
163
116
|
}
|
|
164
117
|
catch { }
|
|
@@ -176,16 +129,7 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
176
129
|
else {
|
|
177
130
|
debug("Adapter failed to start - no need to terminate!");
|
|
178
131
|
}
|
|
179
|
-
|
|
180
|
-
if (this._objects) {
|
|
181
|
-
await this._objects.destroy();
|
|
182
|
-
this._objects = null;
|
|
183
|
-
}
|
|
184
|
-
if (this._states) {
|
|
185
|
-
await this._states.destroy();
|
|
186
|
-
this._states = null;
|
|
187
|
-
}
|
|
188
|
-
debug("Controller instance stopped");
|
|
132
|
+
await this.dbConnection.stop();
|
|
189
133
|
}
|
|
190
134
|
/**
|
|
191
135
|
* Starts the adapter in a separate process and monitors its status
|
|
@@ -259,13 +203,14 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
259
203
|
.on("close", onClose)
|
|
260
204
|
.on("exit", onClose);
|
|
261
205
|
// Tell adapter to stop
|
|
262
|
-
|
|
263
|
-
await this.
|
|
206
|
+
try {
|
|
207
|
+
await this.dbConnection.setState(`system.adapter.${this.adapterName}.0.sigKill`, {
|
|
264
208
|
val: -1,
|
|
265
209
|
from: "system.host.testing",
|
|
266
210
|
});
|
|
267
211
|
}
|
|
268
|
-
|
|
212
|
+
catch {
|
|
213
|
+
// DB connection may be closed already, kill the process
|
|
269
214
|
(_a = this._adapterProcess) === null || _a === void 0 ? void 0 : _a.kill("SIGTERM");
|
|
270
215
|
}
|
|
271
216
|
});
|
|
@@ -273,26 +218,25 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
273
218
|
/**
|
|
274
219
|
* Updates the adapter config. The changes can be a subset of the target object
|
|
275
220
|
*/
|
|
276
|
-
async changeAdapterConfig(
|
|
277
|
-
const objects = await this.dbConnection.readObjectsDB();
|
|
221
|
+
async changeAdapterConfig(adapterName, changes) {
|
|
278
222
|
const adapterInstanceId = `system.adapter.${adapterName}.0`;
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
(0, objects_1.extend)(
|
|
282
|
-
await this.dbConnection.
|
|
223
|
+
const obj = await this.dbConnection.getObject(adapterInstanceId);
|
|
224
|
+
if (obj) {
|
|
225
|
+
(0, objects_1.extend)(obj, changes);
|
|
226
|
+
await this.dbConnection.setObject(adapterInstanceId, obj);
|
|
283
227
|
}
|
|
284
228
|
}
|
|
229
|
+
getAdapterExecutionMode() {
|
|
230
|
+
return (0, adapterTools_1.getAdapterExecutionMode)(this.testAdapterDir);
|
|
231
|
+
}
|
|
285
232
|
/** Enables the sendTo method */
|
|
286
|
-
enableSendTo() {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}, () => {
|
|
292
|
-
this._states.subscribeMessage(fromAdapterID);
|
|
293
|
-
resolve();
|
|
294
|
-
});
|
|
233
|
+
async enableSendTo() {
|
|
234
|
+
await this.dbConnection.setObject(fromAdapterID, {
|
|
235
|
+
type: "instance",
|
|
236
|
+
common: {},
|
|
237
|
+
native: {},
|
|
295
238
|
});
|
|
239
|
+
this.dbConnection.subscribeMessage(fromAdapterID);
|
|
296
240
|
}
|
|
297
241
|
/** Sends a message to an adapter instance */
|
|
298
242
|
sendTo(target, command, message, callback) {
|
|
@@ -303,7 +247,7 @@ class TestHarness extends events_1.EventEmitter {
|
|
|
303
247
|
}
|
|
304
248
|
};
|
|
305
249
|
this.addListener("stateChange", stateChangedHandler);
|
|
306
|
-
this.
|
|
250
|
+
this.dbConnection.pushMessage(`system.adapter.${target}`, {
|
|
307
251
|
command: command,
|
|
308
252
|
message: message,
|
|
309
253
|
from: fromAdapterID,
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|