deepdebug-local-agent 1.0.22 → 1.0.23
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/README.md +81 -0
- package/docs/legacy-connectors.md +268 -0
- package/package.json +4 -1
- package/scripts/sync-fixtures.mjs +246 -0
- package/src/adapters/as400/as400-parser.js +12 -0
- package/src/adapters/as400/index.js +134 -0
- package/src/adapters/cobol/cobol-parser.js +37 -0
- package/src/adapters/cobol/index.js +151 -0
- package/src/adapters/ibmmq/ibmmq-parser.js +23 -0
- package/src/adapters/ibmmq/index.js +137 -0
- package/src/adapters/index.js +79 -0
- package/src/adapters/oracle-forms/index.js +145 -0
- package/src/adapters/oracle-forms/oracle-forms-parser.js +11 -0
- package/src/adapters/sap/index.js +146 -0
- package/src/adapters/sap/sap-parser.js +41 -0
- package/src/server.js +46 -2
- package/test/adapters/as400/as400.test.js +121 -0
- package/test/adapters/cobol/cobol.test.js +217 -0
- package/test/adapters/ibmmq/ibmmq.test.js +122 -0
- package/test/adapters/oracle-forms/oracle-forms.test.js +180 -0
- package/test/adapters/registry.test.js +101 -0
- package/test/adapters/sap/sap.test.js +142 -0
- package/src/local-agent-source.tar.gz +0 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { test, describe, before, after } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { writeFileSync, appendFileSync, truncateSync, mkdirSync, rmSync } from 'node:fs';
|
|
4
|
+
import { mkdtempSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
8
|
+
import { SapLogAdapter } from '../../../src/adapters/sap/index.js';
|
|
9
|
+
import { SAP_DEV_W_REGEX, SAP_SLOG_REGEX } from '../../../src/adapters/sap/sap-parser.js';
|
|
10
|
+
|
|
11
|
+
function tempSapTree() {
|
|
12
|
+
const root = mkdtempSync(join(tmpdir(), 'sap-test-'));
|
|
13
|
+
const workDir = join(root, 'D00', 'work');
|
|
14
|
+
const logDir = join(root, 'D00', 'log');
|
|
15
|
+
mkdirSync(workDir, { recursive: true });
|
|
16
|
+
mkdirSync(logDir, { recursive: true });
|
|
17
|
+
return { root, workDir, logDir };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function awaitEvents(adapter, n, timeoutMs = 12000) {
|
|
21
|
+
const events = [];
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const onErr = (e) => { events.push(e); if (events.length >= n) { adapter.off('error', onErr); resolve(events); } };
|
|
24
|
+
adapter.on('error', onErr);
|
|
25
|
+
setTimeout(() => { adapter.off('error', onErr); resolve(events); }, timeoutMs);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('SapLogAdapter', () => {
|
|
30
|
+
test('TAIL mode default — pre-existing content not emitted (AC-9)', async () => {
|
|
31
|
+
const { root, workDir } = tempSapTree();
|
|
32
|
+
const f = join(workDir, 'dev_w0');
|
|
33
|
+
writeFileSync(f, [
|
|
34
|
+
'trc file: "dev_w0"',
|
|
35
|
+
'M *** ERROR => Pre-existing CONVT_NO_NUMBER',
|
|
36
|
+
].join('\n') + '\n');
|
|
37
|
+
|
|
38
|
+
const adapter = new SapLogAdapter({ sapDir: root, instanceNumber: '00', interval: 200 });
|
|
39
|
+
await adapter.start();
|
|
40
|
+
const events = await awaitEvents(adapter, 1, 1500);
|
|
41
|
+
await adapter.stop();
|
|
42
|
+
assert.equal(events.length, 0, 'no events should fire for pre-existing content');
|
|
43
|
+
rmSync(root, { recursive: true, force: true });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('emits 6-key event on appended dev_w error line (AC-2)', async () => {
|
|
47
|
+
const { root, workDir } = tempSapTree();
|
|
48
|
+
const f = join(workDir, 'dev_w0');
|
|
49
|
+
writeFileSync(f, 'trc file: "dev_w0"\n');
|
|
50
|
+
|
|
51
|
+
const adapter = new SapLogAdapter({ sapDir: root, instanceNumber: '00', interval: 200 });
|
|
52
|
+
await adapter.start();
|
|
53
|
+
await sleep(400);
|
|
54
|
+
appendFileSync(f, 'M *** ERROR => Runtime error CONVT_NO_NUMBER\n');
|
|
55
|
+
const events = await awaitEvents(adapter, 1, 5000);
|
|
56
|
+
await adapter.stop();
|
|
57
|
+
|
|
58
|
+
assert.equal(events.length, 1);
|
|
59
|
+
const e = events[0];
|
|
60
|
+
assert.equal(Object.keys(e).sort().join(','), 'adapter,errorCode,file,message,source,timestamp');
|
|
61
|
+
assert.equal(e.adapter, 'sap');
|
|
62
|
+
assert.equal(e.errorCode, 'CONVT_NO_NUMBER');
|
|
63
|
+
assert.equal(e.file, f);
|
|
64
|
+
assert.match(e.message, /CONVT_NO_NUMBER/);
|
|
65
|
+
assert.equal(e.source, workDir);
|
|
66
|
+
assert.match(e.timestamp, /^\d{4}-\d{2}-\d{2}T/);
|
|
67
|
+
rmSync(root, { recursive: true, force: true });
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('emits event on SLOG line', async () => {
|
|
71
|
+
const { root, logDir } = tempSapTree();
|
|
72
|
+
const f = join(logDir, 'SLOG00');
|
|
73
|
+
writeFileSync(f, '| 2024-01-15 09:00:00 | I | 00 | System log opened |\n');
|
|
74
|
+
|
|
75
|
+
const adapter = new SapLogAdapter({ sapDir: root, instanceNumber: '00', interval: 200 });
|
|
76
|
+
await adapter.start();
|
|
77
|
+
await sleep(400);
|
|
78
|
+
appendFileSync(f, '| 2024-01-15 09:12:44 | E | 04 | Database error in select on ZSALES_ORDER, sy-subrc = 4 |\n');
|
|
79
|
+
const events = await awaitEvents(adapter, 1, 5000);
|
|
80
|
+
await adapter.stop();
|
|
81
|
+
assert.equal(events.length, 1);
|
|
82
|
+
assert.equal(events[0].adapter, 'sap');
|
|
83
|
+
rmSync(root, { recursive: true, force: true });
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('start/stop/start lifecycle idempotent (AC-1)', async () => {
|
|
87
|
+
const { root, workDir } = tempSapTree();
|
|
88
|
+
writeFileSync(join(workDir, 'dev_w0'), 'trc\n');
|
|
89
|
+
const adapter = new SapLogAdapter({ sapDir: root, instanceNumber: '00', interval: 200 });
|
|
90
|
+
await adapter.start();
|
|
91
|
+
await adapter.start(); // idempotent
|
|
92
|
+
await adapter.stop();
|
|
93
|
+
await adapter.stop(); // idempotent
|
|
94
|
+
await adapter.start();
|
|
95
|
+
await adapter.stop();
|
|
96
|
+
rmSync(root, { recursive: true, force: true });
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('rotation: truncate + append → event emitted (AC-10)', async () => {
|
|
100
|
+
const { root, workDir } = tempSapTree();
|
|
101
|
+
const f = join(workDir, 'dev_w0');
|
|
102
|
+
writeFileSync(f, 'trc\nM *** ERROR => OLD_BASELINE\n');
|
|
103
|
+
|
|
104
|
+
const adapter = new SapLogAdapter({ sapDir: root, instanceNumber: '00', interval: 200 });
|
|
105
|
+
await adapter.start();
|
|
106
|
+
await sleep(400);
|
|
107
|
+
truncateSync(f, 0);
|
|
108
|
+
await sleep(400);
|
|
109
|
+
appendFileSync(f, 'M *** ERROR => Runtime error CONVT_NO_NUMBER\n');
|
|
110
|
+
const events = await awaitEvents(adapter, 1, 5000);
|
|
111
|
+
await adapter.stop();
|
|
112
|
+
assert.ok(events.length >= 1, 'rotation should produce at least 1 event');
|
|
113
|
+
rmSync(root, { recursive: true, force: true });
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('ENOENT silent — no event, no throw', async () => {
|
|
117
|
+
const adapter = new SapLogAdapter({ sapDir: '/nonexistent/path-' + Date.now(), instanceNumber: '00', interval: 200 });
|
|
118
|
+
await adapter.start();
|
|
119
|
+
await sleep(500);
|
|
120
|
+
await adapter.stop();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('parser regexes exported and callable (T-2-03)', () => {
|
|
124
|
+
assert.ok(SAP_DEV_W_REGEX instanceof RegExp);
|
|
125
|
+
assert.ok(SAP_SLOG_REGEX instanceof RegExp);
|
|
126
|
+
const m = 'M *** ERROR => Runtime error CONVT_NO_NUMBER'.match(SAP_DEV_W_REGEX);
|
|
127
|
+
assert.ok(m, 'dev_w regex should match runtime error line');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('replayOnStart: true emits pre-existing content', async () => {
|
|
131
|
+
const { root, workDir } = tempSapTree();
|
|
132
|
+
const f = join(workDir, 'dev_w0');
|
|
133
|
+
writeFileSync(f, 'M *** ERROR => Runtime error CONVT_NO_NUMBER\n');
|
|
134
|
+
|
|
135
|
+
const adapter = new SapLogAdapter({ sapDir: root, instanceNumber: '00', interval: 200, replayOnStart: true });
|
|
136
|
+
await adapter.start();
|
|
137
|
+
const events = await awaitEvents(adapter, 1, 5000);
|
|
138
|
+
await adapter.stop();
|
|
139
|
+
assert.ok(events.length >= 1);
|
|
140
|
+
rmSync(root, { recursive: true, force: true });
|
|
141
|
+
});
|
|
142
|
+
});
|
|
Binary file
|