@yarkivaev/source-to-sink 1.1.1 → 1.2.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/.github/workflows/ci.yml +1 -1
- package/eslint.config.js +176 -0
- package/index.js +1 -0
- package/package.json +11 -5
- package/src/batch.js +2 -2
- package/src/lokiSource.js +3 -3
- package/src/modbusSource.js +4 -4
- package/src/mqttSource.js +5 -5
- package/src/pollingSource.js +4 -3
- package/src/postgresSink.js +7 -7
- package/src/sqliteSink.js +55 -0
- package/src/stompSource.js +20 -11
- package/src/timedBatch.js +4 -4
- package/test/integration_clickhouseSink.js +5 -5
- package/test/integration_lokiSource.js +13 -13
- package/test/integration_mqttSink.js +12 -12
- package/test/integration_mqttSource.js +19 -19
- package/test/test_batch.js +21 -35
- package/test/test_circuit.js +12 -12
- package/test/test_clickhouseSink.js +8 -8
- package/test/test_lokiSource.js +12 -12
- package/test/test_modbusSource.js +16 -16
- package/test/test_mqttSink.js +6 -6
- package/test/test_mqttSource.js +8 -8
- package/test/test_pollingSource.js +23 -23
- package/test/test_postgresSink.js +12 -12
- package/test/test_sqliteSink.js +176 -0
- package/test/test_stompSource.js +8 -8
- package/test/test_timedBatch.js +13 -13
package/test/test_mqttSource.js
CHANGED
|
@@ -6,8 +6,8 @@ describe('mqttSource', () => {
|
|
|
6
6
|
it('throws on missing url', () => {
|
|
7
7
|
const collector = { accept: () => {} };
|
|
8
8
|
assert.throws(
|
|
9
|
-
() => mqttSource(null, 'test/topic', collector),
|
|
10
|
-
/URL must be a non-empty string
|
|
9
|
+
() => {return mqttSource(null, 'test/topic', collector)},
|
|
10
|
+
/URL must be a non-empty string/u,
|
|
11
11
|
'Should reject missing url'
|
|
12
12
|
);
|
|
13
13
|
});
|
|
@@ -15,8 +15,8 @@ describe('mqttSource', () => {
|
|
|
15
15
|
it('throws on empty url', () => {
|
|
16
16
|
const collector = { accept: () => {} };
|
|
17
17
|
assert.throws(
|
|
18
|
-
() => mqttSource('', 'test/topic', collector),
|
|
19
|
-
/URL must be a non-empty string
|
|
18
|
+
() => {return mqttSource('', 'test/topic', collector)},
|
|
19
|
+
/URL must be a non-empty string/u,
|
|
20
20
|
'Should reject empty url'
|
|
21
21
|
);
|
|
22
22
|
});
|
|
@@ -24,16 +24,16 @@ describe('mqttSource', () => {
|
|
|
24
24
|
it('throws on empty topic', () => {
|
|
25
25
|
const collector = { accept: () => {} };
|
|
26
26
|
assert.throws(
|
|
27
|
-
() => mqttSource('mqtt://localhost:1883', '', collector),
|
|
28
|
-
/Topic must be a non-empty string
|
|
27
|
+
() => {return mqttSource('mqtt://localhost:1883', '', collector)},
|
|
28
|
+
/Topic must be a non-empty string/u,
|
|
29
29
|
'Should reject empty topic'
|
|
30
30
|
);
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('throws on missing collector', () => {
|
|
34
34
|
assert.throws(
|
|
35
|
-
() => mqttSource('mqtt://localhost:1883', 'test', null),
|
|
36
|
-
/Collector must have an accept\(\) method
|
|
35
|
+
() => {return mqttSource('mqtt://localhost:1883', 'test', null)},
|
|
36
|
+
/Collector must have an accept\(\) method/u,
|
|
37
37
|
'Should reject missing collector'
|
|
38
38
|
);
|
|
39
39
|
});
|
|
@@ -6,7 +6,7 @@ import fakeClock from './fakeClock.js';
|
|
|
6
6
|
describe('pollingSource', () => {
|
|
7
7
|
it('polls fetch after interval', async () => {
|
|
8
8
|
let polled = false;
|
|
9
|
-
const fetch =
|
|
9
|
+
const fetch = () => {
|
|
10
10
|
polled = true;
|
|
11
11
|
return [];
|
|
12
12
|
};
|
|
@@ -14,7 +14,7 @@ describe('pollingSource', () => {
|
|
|
14
14
|
const clk = fakeClock(Math.floor(Math.random() * 10000));
|
|
15
15
|
const source = pollingSource(fetch, 0.05, collector, clk);
|
|
16
16
|
source.start();
|
|
17
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
17
|
+
await new Promise(resolve => { setTimeout(resolve, 100); });
|
|
18
18
|
source.stop();
|
|
19
19
|
assert.strictEqual(polled, true, 'Should poll fetch after interval');
|
|
20
20
|
});
|
|
@@ -25,19 +25,19 @@ describe('pollingSource', () => {
|
|
|
25
25
|
{ ts: Math.random(), line: `\u00e9${Math.random()}` },
|
|
26
26
|
{ ts: Math.random(), line: `\u4e2d${Math.random()}` }
|
|
27
27
|
];
|
|
28
|
-
const fetch =
|
|
29
|
-
const collector = { accept: (entry) => received.push(entry) };
|
|
28
|
+
const fetch = () => {return entries};
|
|
29
|
+
const collector = { accept: (entry) => {return received.push(entry)} };
|
|
30
30
|
const clk = fakeClock(Math.floor(Math.random() * 10000));
|
|
31
31
|
const source = pollingSource(fetch, 0.05, collector, clk);
|
|
32
32
|
source.start();
|
|
33
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
33
|
+
await new Promise(resolve => { setTimeout(resolve, 100); });
|
|
34
34
|
source.stop();
|
|
35
35
|
assert.strictEqual(received.length, entries.length, 'Should forward all entries to collector');
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
it('passes time window to fetch', async () => {
|
|
39
39
|
let captured = null;
|
|
40
|
-
const fetch =
|
|
40
|
+
const fetch = (since, until) => {
|
|
41
41
|
captured = { since, until };
|
|
42
42
|
return [];
|
|
43
43
|
};
|
|
@@ -45,14 +45,14 @@ describe('pollingSource', () => {
|
|
|
45
45
|
const clk = fakeClock(1000);
|
|
46
46
|
const source = pollingSource(fetch, 0.05, collector, clk);
|
|
47
47
|
source.start();
|
|
48
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
48
|
+
await new Promise(resolve => { setTimeout(resolve, 100); });
|
|
49
49
|
source.stop();
|
|
50
50
|
assert.strictEqual(captured !== null, true, 'Should pass time window to fetch');
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
it('ignores duplicate start calls', () => {
|
|
54
54
|
let count = 0;
|
|
55
|
-
const fetch =
|
|
55
|
+
const fetch = () => {
|
|
56
56
|
count += 1;
|
|
57
57
|
return [];
|
|
58
58
|
};
|
|
@@ -66,7 +66,7 @@ describe('pollingSource', () => {
|
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
it('ignores stop when not started', () => {
|
|
69
|
-
const fetch =
|
|
69
|
+
const fetch = () => {return []};
|
|
70
70
|
const collector = { accept: () => {} };
|
|
71
71
|
const clk = fakeClock(0);
|
|
72
72
|
const source = pollingSource(fetch, 60, collector, clk);
|
|
@@ -76,7 +76,7 @@ describe('pollingSource', () => {
|
|
|
76
76
|
|
|
77
77
|
it('stops polling on stop', async () => {
|
|
78
78
|
let count = 0;
|
|
79
|
-
const fetch =
|
|
79
|
+
const fetch = () => {
|
|
80
80
|
count += 1;
|
|
81
81
|
return [];
|
|
82
82
|
};
|
|
@@ -84,10 +84,10 @@ describe('pollingSource', () => {
|
|
|
84
84
|
const clk = fakeClock(0);
|
|
85
85
|
const source = pollingSource(fetch, 0.03, collector, clk);
|
|
86
86
|
source.start();
|
|
87
|
-
await new Promise(resolve => setTimeout(resolve, 50));
|
|
87
|
+
await new Promise(resolve => { setTimeout(resolve, 50); });
|
|
88
88
|
source.stop();
|
|
89
89
|
const before = count;
|
|
90
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
90
|
+
await new Promise(resolve => { setTimeout(resolve, 100); });
|
|
91
91
|
assert.strictEqual(count, before, 'Should stop polling after stop');
|
|
92
92
|
});
|
|
93
93
|
|
|
@@ -95,39 +95,39 @@ describe('pollingSource', () => {
|
|
|
95
95
|
const collector = { accept: () => {} };
|
|
96
96
|
const clk = fakeClock(0);
|
|
97
97
|
assert.throws(
|
|
98
|
-
() => pollingSource(null, 10, collector, clk),
|
|
99
|
-
/Fetch must be a function
|
|
98
|
+
() => {return pollingSource(null, 10, collector, clk)},
|
|
99
|
+
/Fetch must be a function/u,
|
|
100
100
|
'Should reject missing fetch'
|
|
101
101
|
);
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
it('throws on invalid interval', () => {
|
|
105
|
-
const fetch =
|
|
105
|
+
const fetch = () => {return []};
|
|
106
106
|
const collector = { accept: () => {} };
|
|
107
107
|
const clk = fakeClock(0);
|
|
108
108
|
assert.throws(
|
|
109
|
-
() => pollingSource(fetch, -1, collector, clk),
|
|
110
|
-
/Interval must be a positive number
|
|
109
|
+
() => {return pollingSource(fetch, -1, collector, clk)},
|
|
110
|
+
/Interval must be a positive number/u,
|
|
111
111
|
'Should reject invalid interval'
|
|
112
112
|
);
|
|
113
113
|
});
|
|
114
114
|
|
|
115
115
|
it('throws on missing collector', () => {
|
|
116
|
-
const fetch =
|
|
116
|
+
const fetch = () => {return []};
|
|
117
117
|
const clk = fakeClock(0);
|
|
118
118
|
assert.throws(
|
|
119
|
-
() => pollingSource(fetch, 10, null, clk),
|
|
120
|
-
/Collector must have an accept\(\) method
|
|
119
|
+
() => {return pollingSource(fetch, 10, null, clk)},
|
|
120
|
+
/Collector must have an accept\(\) method/u,
|
|
121
121
|
'Should reject missing collector'
|
|
122
122
|
);
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
it('throws on missing clock', () => {
|
|
126
|
-
const fetch =
|
|
126
|
+
const fetch = () => {return []};
|
|
127
127
|
const collector = { accept: () => {} };
|
|
128
128
|
assert.throws(
|
|
129
|
-
() => pollingSource(fetch, 10, collector, null),
|
|
130
|
-
/Clock must have a millis\(\) method
|
|
129
|
+
() => {return pollingSource(fetch, 10, collector, null)},
|
|
130
|
+
/Clock must have a millis\(\) method/u,
|
|
131
131
|
'Should reject missing clock'
|
|
132
132
|
);
|
|
133
133
|
});
|
|
@@ -5,48 +5,48 @@ import postgresSink, { deduplicate } from '../src/postgresSink.js';
|
|
|
5
5
|
describe('postgresSink', () => {
|
|
6
6
|
it('throws on missing url', () => {
|
|
7
7
|
assert.throws(
|
|
8
|
-
() => postgresSink(null, 'metrics', ['ts', 'value']),
|
|
9
|
-
/URL must be a non-empty string
|
|
8
|
+
() => {return postgresSink(null, 'metrics', ['ts', 'value'])},
|
|
9
|
+
/URL must be a non-empty string/u,
|
|
10
10
|
'Should reject missing url'
|
|
11
11
|
);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it('throws on empty url', () => {
|
|
15
15
|
assert.throws(
|
|
16
|
-
() => postgresSink('', 'metrics', ['ts', 'value']),
|
|
17
|
-
/URL must be a non-empty string
|
|
16
|
+
() => {return postgresSink('', 'metrics', ['ts', 'value'])},
|
|
17
|
+
/URL must be a non-empty string/u,
|
|
18
18
|
'Should reject empty url'
|
|
19
19
|
);
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
it('throws on missing table', () => {
|
|
23
23
|
assert.throws(
|
|
24
|
-
() => postgresSink('postgresql://localhost:5432/db', null, ['ts', 'value']),
|
|
25
|
-
/Table must be a non-empty string
|
|
24
|
+
() => {return postgresSink('postgresql://localhost:5432/db', null, ['ts', 'value'])},
|
|
25
|
+
/Table must be a non-empty string/u,
|
|
26
26
|
'Should reject missing table'
|
|
27
27
|
);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
it('throws on empty table', () => {
|
|
31
31
|
assert.throws(
|
|
32
|
-
() => postgresSink('postgresql://localhost:5432/db', '', ['ts', 'value']),
|
|
33
|
-
/Table must be a non-empty string
|
|
32
|
+
() => {return postgresSink('postgresql://localhost:5432/db', '', ['ts', 'value'])},
|
|
33
|
+
/Table must be a non-empty string/u,
|
|
34
34
|
'Should reject empty table'
|
|
35
35
|
);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
it('throws on missing columns', () => {
|
|
39
39
|
assert.throws(
|
|
40
|
-
() => postgresSink('postgresql://localhost:5432/db', 'metrics', null),
|
|
41
|
-
/Columns must be a non-empty array
|
|
40
|
+
() => {return postgresSink('postgresql://localhost:5432/db', 'metrics', null)},
|
|
41
|
+
/Columns must be a non-empty array/u,
|
|
42
42
|
'Should reject missing columns'
|
|
43
43
|
);
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
it('throws on empty columns', () => {
|
|
47
47
|
assert.throws(
|
|
48
|
-
() => postgresSink('postgresql://localhost:5432/db', 'metrics', []),
|
|
49
|
-
/Columns must be a non-empty array
|
|
48
|
+
() => {return postgresSink('postgresql://localhost:5432/db', 'metrics', [])},
|
|
49
|
+
/Columns must be a non-empty array/u,
|
|
50
50
|
'Should reject empty columns'
|
|
51
51
|
);
|
|
52
52
|
});
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { describe, it } from 'mocha';
|
|
3
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import Database from 'better-sqlite3';
|
|
7
|
+
import sqliteSink from '../src/sqliteSink.js';
|
|
8
|
+
|
|
9
|
+
describe('sqliteSink', () => {
|
|
10
|
+
it('throws on missing path', () => {
|
|
11
|
+
assert.throws(
|
|
12
|
+
() => {return sqliteSink(null, 'metrics', ['ts', 'value'])},
|
|
13
|
+
/Path must be a non-empty string/u,
|
|
14
|
+
'Should reject missing path'
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('throws on empty path', () => {
|
|
19
|
+
assert.throws(
|
|
20
|
+
() => {return sqliteSink('', 'metrics', ['ts', 'value'])},
|
|
21
|
+
/Path must be a non-empty string/u,
|
|
22
|
+
'Should reject empty path'
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('throws on missing table', () => {
|
|
27
|
+
const dir = mkdtempSync(join(tmpdir(), 'sink-'));
|
|
28
|
+
try {
|
|
29
|
+
assert.throws(
|
|
30
|
+
() => {return sqliteSink(join(dir, 'db.sqlite'), null, ['ts', 'value'])},
|
|
31
|
+
/Table must be a non-empty string/u,
|
|
32
|
+
'Should reject missing table'
|
|
33
|
+
);
|
|
34
|
+
} finally {
|
|
35
|
+
rmSync(dir, { recursive: true });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('throws on empty table', () => {
|
|
40
|
+
const dir = mkdtempSync(join(tmpdir(), 'sink-'));
|
|
41
|
+
try {
|
|
42
|
+
assert.throws(
|
|
43
|
+
() => {return sqliteSink(join(dir, 'db.sqlite'), '', ['ts', 'value'])},
|
|
44
|
+
/Table must be a non-empty string/u,
|
|
45
|
+
'Should reject empty table'
|
|
46
|
+
);
|
|
47
|
+
} finally {
|
|
48
|
+
rmSync(dir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('throws on missing columns', () => {
|
|
53
|
+
const dir = mkdtempSync(join(tmpdir(), 'sink-'));
|
|
54
|
+
try {
|
|
55
|
+
assert.throws(
|
|
56
|
+
() => {return sqliteSink(join(dir, 'db.sqlite'), 'metrics', null)},
|
|
57
|
+
/Columns must be a non-empty array/u,
|
|
58
|
+
'Should reject missing columns'
|
|
59
|
+
);
|
|
60
|
+
} finally {
|
|
61
|
+
rmSync(dir, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('throws on empty columns', () => {
|
|
66
|
+
const dir = mkdtempSync(join(tmpdir(), 'sink-'));
|
|
67
|
+
try {
|
|
68
|
+
assert.throws(
|
|
69
|
+
() => {return sqliteSink(join(dir, 'db.sqlite'), 'metrics', [])},
|
|
70
|
+
/Columns must be a non-empty array/u,
|
|
71
|
+
'Should reject empty columns'
|
|
72
|
+
);
|
|
73
|
+
} finally {
|
|
74
|
+
rmSync(dir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('returns sink with write method', () => {
|
|
79
|
+
const dir = mkdtempSync(join(tmpdir(), 'sink-'));
|
|
80
|
+
const path = join(dir, 'db.sqlite');
|
|
81
|
+
const db = new Database(path);
|
|
82
|
+
db.exec('CREATE TABLE metrics (topic TEXT, ts REAL, value REAL)');
|
|
83
|
+
db.close();
|
|
84
|
+
try {
|
|
85
|
+
const sink = sqliteSink(path, 'metrics', ['topic', 'ts', 'value']);
|
|
86
|
+
assert.strictEqual(typeof sink.write, 'function', 'Should have write method');
|
|
87
|
+
sink.close();
|
|
88
|
+
} finally {
|
|
89
|
+
rmSync(dir, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('inserts records into the database', () => {
|
|
94
|
+
const dir = mkdtempSync(join(tmpdir(), 'sink-'));
|
|
95
|
+
const path = join(dir, `db-${Math.random()}.sqlite`);
|
|
96
|
+
const db = new Database(path);
|
|
97
|
+
db.exec('CREATE TABLE metrics (topic TEXT, ts REAL, value REAL)');
|
|
98
|
+
db.close();
|
|
99
|
+
const topic = `sénsör/${Math.random()}`;
|
|
100
|
+
const ts = Date.now();
|
|
101
|
+
const value = Math.random() * 1000;
|
|
102
|
+
try {
|
|
103
|
+
const sink = sqliteSink(path, 'metrics', ['topic', 'ts', 'value']);
|
|
104
|
+
sink.write([{ topic, ts, value }]);
|
|
105
|
+
sink.close();
|
|
106
|
+
const reader = new Database(path);
|
|
107
|
+
const rows = reader.prepare('SELECT topic, ts, value FROM metrics').all();
|
|
108
|
+
reader.close();
|
|
109
|
+
assert.strictEqual(rows.length, 1, 'Should insert exactly one record');
|
|
110
|
+
} finally {
|
|
111
|
+
rmSync(dir, { recursive: true });
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('inserts batch of records atomically', () => {
|
|
116
|
+
const dir = mkdtempSync(join(tmpdir(), 'sink-'));
|
|
117
|
+
const path = join(dir, `db-${Math.random()}.sqlite`);
|
|
118
|
+
const db = new Database(path);
|
|
119
|
+
db.exec('CREATE TABLE metrics (topic TEXT, ts REAL, value REAL)');
|
|
120
|
+
db.close();
|
|
121
|
+
const count = 5 + Math.floor(Math.random() * 10);
|
|
122
|
+
const records = Array.from({ length: count }, (_, i) => {return {
|
|
123
|
+
topic: `tøpic/${Math.random()}`,
|
|
124
|
+
ts: Date.now() + i,
|
|
125
|
+
value: Math.random()
|
|
126
|
+
}});
|
|
127
|
+
try {
|
|
128
|
+
const sink = sqliteSink(path, 'metrics', ['topic', 'ts', 'value']);
|
|
129
|
+
sink.write(records);
|
|
130
|
+
sink.close();
|
|
131
|
+
const reader = new Database(path);
|
|
132
|
+
const rows = reader.prepare('SELECT COUNT(*) as cnt FROM metrics').get();
|
|
133
|
+
reader.close();
|
|
134
|
+
assert.strictEqual(rows.cnt, count, 'Should insert all records in batch');
|
|
135
|
+
} finally {
|
|
136
|
+
rmSync(dir, { recursive: true });
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('preserves record values', () => {
|
|
141
|
+
const dir = mkdtempSync(join(tmpdir(), 'sink-'));
|
|
142
|
+
const path = join(dir, `db-${Math.random()}.sqlite`);
|
|
143
|
+
const db = new Database(path);
|
|
144
|
+
db.exec('CREATE TABLE metrics (topic TEXT, ts REAL, value REAL)');
|
|
145
|
+
db.close();
|
|
146
|
+
const topic = `données/capteur-${Math.random()}`;
|
|
147
|
+
const ts = Date.now() + Math.floor(Math.random() * 100000);
|
|
148
|
+
const value = Math.random() * 500;
|
|
149
|
+
try {
|
|
150
|
+
const sink = sqliteSink(path, 'metrics', ['topic', 'ts', 'value']);
|
|
151
|
+
sink.write([{ topic, ts, value }]);
|
|
152
|
+
sink.close();
|
|
153
|
+
const reader = new Database(path);
|
|
154
|
+
const row = reader.prepare('SELECT topic, ts, value FROM metrics').get();
|
|
155
|
+
reader.close();
|
|
156
|
+
assert.strictEqual(row.topic, topic, 'Should preserve topic value');
|
|
157
|
+
} finally {
|
|
158
|
+
rmSync(dir, { recursive: true });
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('returns sink with close method', () => {
|
|
163
|
+
const dir = mkdtempSync(join(tmpdir(), 'sink-'));
|
|
164
|
+
const path = join(dir, 'db.sqlite');
|
|
165
|
+
const db = new Database(path);
|
|
166
|
+
db.exec('CREATE TABLE metrics (topic TEXT, ts REAL, value REAL)');
|
|
167
|
+
db.close();
|
|
168
|
+
try {
|
|
169
|
+
const sink = sqliteSink(path, 'metrics', ['topic', 'ts', 'value']);
|
|
170
|
+
assert.strictEqual(typeof sink.close, 'function', 'Should have close method');
|
|
171
|
+
sink.close();
|
|
172
|
+
} finally {
|
|
173
|
+
rmSync(dir, { recursive: true });
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
});
|
package/test/test_stompSource.js
CHANGED
|
@@ -6,8 +6,8 @@ describe('stompSource', () => {
|
|
|
6
6
|
it('throws on missing url', () => {
|
|
7
7
|
const collector = { accept: () => {} };
|
|
8
8
|
assert.throws(
|
|
9
|
-
() => stompSource(null, '/queue/test', collector),
|
|
10
|
-
/URL must be a non-empty string
|
|
9
|
+
() => {return stompSource(null, '/queue/test', collector)},
|
|
10
|
+
/URL must be a non-empty string/u,
|
|
11
11
|
'Should reject missing url'
|
|
12
12
|
);
|
|
13
13
|
});
|
|
@@ -15,8 +15,8 @@ describe('stompSource', () => {
|
|
|
15
15
|
it('throws on empty url', () => {
|
|
16
16
|
const collector = { accept: () => {} };
|
|
17
17
|
assert.throws(
|
|
18
|
-
() => stompSource('', '/queue/test', collector),
|
|
19
|
-
/URL must be a non-empty string
|
|
18
|
+
() => {return stompSource('', '/queue/test', collector)},
|
|
19
|
+
/URL must be a non-empty string/u,
|
|
20
20
|
'Should reject empty url'
|
|
21
21
|
);
|
|
22
22
|
});
|
|
@@ -24,16 +24,16 @@ describe('stompSource', () => {
|
|
|
24
24
|
it('throws on empty destination', () => {
|
|
25
25
|
const collector = { accept: () => {} };
|
|
26
26
|
assert.throws(
|
|
27
|
-
() => stompSource('stomp://localhost:61613', '', collector),
|
|
28
|
-
/Destination must be a non-empty string
|
|
27
|
+
() => {return stompSource('stomp://localhost:61613', '', collector)},
|
|
28
|
+
/Destination must be a non-empty string/u,
|
|
29
29
|
'Should reject empty destination'
|
|
30
30
|
);
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
it('throws on missing collector', () => {
|
|
34
34
|
assert.throws(
|
|
35
|
-
() => stompSource('stomp://localhost:61613', '/queue/test', null),
|
|
36
|
-
/Collector must have an accept\(\) method
|
|
35
|
+
() => {return stompSource('stomp://localhost:61613', '/queue/test', null)},
|
|
36
|
+
/Collector must have an accept\(\) method/u,
|
|
37
37
|
'Should reject missing collector'
|
|
38
38
|
);
|
|
39
39
|
});
|
package/test/test_timedBatch.js
CHANGED
|
@@ -6,7 +6,7 @@ describe('timedBatch', () => {
|
|
|
6
6
|
it('flushes after interval expires', async () => {
|
|
7
7
|
const received = [];
|
|
8
8
|
const origin = {
|
|
9
|
-
accept: (record) => received.push(record),
|
|
9
|
+
accept: (record) => {return received.push(record)},
|
|
10
10
|
flush: () => {},
|
|
11
11
|
stop: () => {}
|
|
12
12
|
};
|
|
@@ -15,7 +15,7 @@ describe('timedBatch', () => {
|
|
|
15
15
|
const interval = 0.05;
|
|
16
16
|
const timed = timedBatch(origin, interval);
|
|
17
17
|
timed.accept({ data: `\u0410\u0411\u0412${Math.random()}` });
|
|
18
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
18
|
+
await new Promise(resolve => { setTimeout(resolve, 100); });
|
|
19
19
|
timed.stop();
|
|
20
20
|
assert.strictEqual(flushed, true, 'Should flush after interval');
|
|
21
21
|
});
|
|
@@ -23,7 +23,7 @@ describe('timedBatch', () => {
|
|
|
23
23
|
it('delegates accept to origin', () => {
|
|
24
24
|
const received = [];
|
|
25
25
|
const origin = {
|
|
26
|
-
accept: (record) => received.push(record),
|
|
26
|
+
accept: (record) => {return received.push(record)},
|
|
27
27
|
flush: () => {},
|
|
28
28
|
stop: () => {}
|
|
29
29
|
};
|
|
@@ -65,14 +65,14 @@ describe('timedBatch', () => {
|
|
|
65
65
|
let count = 0;
|
|
66
66
|
const origin = {
|
|
67
67
|
accept: () => {},
|
|
68
|
-
flush: () => { count
|
|
68
|
+
flush: () => { count += 1; },
|
|
69
69
|
stop: () => {}
|
|
70
70
|
};
|
|
71
71
|
const interval = 0.05;
|
|
72
72
|
const timed = timedBatch(origin, interval);
|
|
73
73
|
timed.accept({ z: Math.random() });
|
|
74
74
|
timed.flush();
|
|
75
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
75
|
+
await new Promise(resolve => { setTimeout(resolve, 100); });
|
|
76
76
|
timed.stop();
|
|
77
77
|
assert.strictEqual(count, 1, 'Should not flush twice after manual flush');
|
|
78
78
|
});
|
|
@@ -80,8 +80,8 @@ describe('timedBatch', () => {
|
|
|
80
80
|
it('throws on missing accept method', () => {
|
|
81
81
|
const origin = { flush: () => {}, stop: () => {} };
|
|
82
82
|
assert.throws(
|
|
83
|
-
() => timedBatch(origin, 1),
|
|
84
|
-
/Origin must have an accept\(\) method
|
|
83
|
+
() => {return timedBatch(origin, 1)},
|
|
84
|
+
/Origin must have an accept\(\) method/u,
|
|
85
85
|
'Should reject origin without accept'
|
|
86
86
|
);
|
|
87
87
|
});
|
|
@@ -89,8 +89,8 @@ describe('timedBatch', () => {
|
|
|
89
89
|
it('throws on missing flush method', () => {
|
|
90
90
|
const origin = { accept: () => {}, stop: () => {} };
|
|
91
91
|
assert.throws(
|
|
92
|
-
() => timedBatch(origin, 1),
|
|
93
|
-
/Origin must have a flush\(\) method
|
|
92
|
+
() => {return timedBatch(origin, 1)},
|
|
93
|
+
/Origin must have a flush\(\) method/u,
|
|
94
94
|
'Should reject origin without flush'
|
|
95
95
|
);
|
|
96
96
|
});
|
|
@@ -98,8 +98,8 @@ describe('timedBatch', () => {
|
|
|
98
98
|
it('throws on missing stop method', () => {
|
|
99
99
|
const origin = { accept: () => {}, flush: () => {} };
|
|
100
100
|
assert.throws(
|
|
101
|
-
() => timedBatch(origin, 1),
|
|
102
|
-
/Origin must have a stop\(\) method
|
|
101
|
+
() => {return timedBatch(origin, 1)},
|
|
102
|
+
/Origin must have a stop\(\) method/u,
|
|
103
103
|
'Should reject origin without stop'
|
|
104
104
|
);
|
|
105
105
|
});
|
|
@@ -108,8 +108,8 @@ describe('timedBatch', () => {
|
|
|
108
108
|
const origin = { accept: () => {}, flush: () => {}, stop: () => {} };
|
|
109
109
|
const invalid = -Math.random() * 10;
|
|
110
110
|
assert.throws(
|
|
111
|
-
() => timedBatch(origin, invalid),
|
|
112
|
-
/Interval must be a positive number
|
|
111
|
+
() => {return timedBatch(origin, invalid)},
|
|
112
|
+
/Interval must be a positive number/u,
|
|
113
113
|
'Should reject invalid interval'
|
|
114
114
|
);
|
|
115
115
|
});
|