@alt-javascript/camel-lite-core 1.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.
@@ -0,0 +1,497 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {
4
+ Exchange, RouteDefinition, Pipeline, CamelContext,
5
+ simple, js, normaliseExpression,
6
+ AggregationStrategies, CamelFilterStopException,
7
+ } from '../src/index.js';
8
+ import { DirectComponent } from '@alt-javascript/camel-lite-component-direct';
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Expression builders: simple() and js()
12
+ // ---------------------------------------------------------------------------
13
+ describe('ExpressionBuilder: simple()', () => {
14
+ it('${body} numeric comparison', () => {
15
+ const ex = new Exchange(); ex.in.body = 5;
16
+ assert.equal(simple('${body} > 3')._fn(ex), true);
17
+ assert.equal(simple('${body} > 10')._fn(ex), false);
18
+ assert.equal(simple('${body} == 5')._fn(ex), true);
19
+ assert.equal(simple('${body} != 3')._fn(ex), true);
20
+ });
21
+
22
+ it('${header.X} access', () => {
23
+ const ex = new Exchange();
24
+ ex.in.setHeader('type', 'A');
25
+ assert.equal(simple('${header.type} == "A"')._fn(ex), true);
26
+ assert.equal(simple('${header.type} == "B"')._fn(ex), false);
27
+ });
28
+
29
+ it('${exchangeProperty.X} access', () => {
30
+ const ex = new Exchange();
31
+ ex.setProperty('count', 3);
32
+ assert.equal(simple('${exchangeProperty.count} == 3')._fn(ex), true);
33
+ });
34
+
35
+ it('${in.body} alias for ${body}', () => {
36
+ const ex = new Exchange(); ex.in.body = 7;
37
+ assert.equal(simple('${in.body} > 5')._fn(ex), true);
38
+ });
39
+
40
+ it('logical and / or', () => {
41
+ const ex = new Exchange(); ex.in.body = 5;
42
+ assert.equal(simple('${body} > 3 and ${body} < 10')._fn(ex), true);
43
+ assert.equal(simple('${body} > 10 or ${body} == 5')._fn(ex), true);
44
+ });
45
+ });
46
+
47
+ describe('ExpressionBuilder: js()', () => {
48
+ it('arbitrary JS expression on exchange', () => {
49
+ const ex = new Exchange(); ex.in.body = 5;
50
+ assert.equal(js('exchange.in.body * 2')._fn(ex), 10);
51
+ });
52
+
53
+ it('string manipulation', () => {
54
+ const ex = new Exchange(); ex.in.body = 'hello';
55
+ assert.equal(js('exchange.in.body.toUpperCase()')._fn(ex), 'HELLO');
56
+ });
57
+
58
+ it('header access', () => {
59
+ const ex = new Exchange();
60
+ ex.in.setHeader('x', 'world');
61
+ assert.equal(js('exchange.in.getHeader("x") + "!"')._fn(ex), 'world!');
62
+ });
63
+ });
64
+
65
+ describe('normaliseExpression', () => {
66
+ it('passes native function through', () => {
67
+ const fn = (e) => e.in.body;
68
+ assert.strictEqual(normaliseExpression(fn), fn);
69
+ });
70
+
71
+ it('extracts _fn from simple() result', () => {
72
+ const expr = simple('${body}');
73
+ const fn = normaliseExpression(expr);
74
+ assert.equal(typeof fn, 'function');
75
+ });
76
+
77
+ it('extracts _fn from js() result', () => {
78
+ const expr = js('exchange.in.body');
79
+ const fn = normaliseExpression(expr);
80
+ assert.equal(typeof fn, 'function');
81
+ });
82
+
83
+ it('throws on non-function non-expr input', () => {
84
+ assert.throws(() => normaliseExpression('bad'), TypeError);
85
+ assert.throws(() => normaliseExpression(42), TypeError);
86
+ });
87
+ });
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // filter()
91
+ // ---------------------------------------------------------------------------
92
+ describe('RouteDefinition.filter()', () => {
93
+ it('predicate true — downstream step called', async () => {
94
+ let called = false;
95
+ const rd = new RouteDefinition('direct:test');
96
+ rd.filter((e) => e.in.body > 0).process(() => { called = true; });
97
+ const pipeline = rd.compile();
98
+ const ex = new Exchange(); ex.in.body = 5;
99
+ await pipeline.run(ex);
100
+ assert.equal(called, true);
101
+ assert.equal(ex.exception, null);
102
+ });
103
+
104
+ it('predicate false — downstream step NOT called, exception null', async () => {
105
+ let called = false;
106
+ const rd = new RouteDefinition('direct:test');
107
+ rd.filter((e) => e.in.body > 0).process(() => { called = true; });
108
+ const pipeline = rd.compile();
109
+ const ex = new Exchange(); ex.in.body = -1;
110
+ await pipeline.run(ex);
111
+ assert.equal(called, false);
112
+ assert.equal(ex.exception, null);
113
+ });
114
+
115
+ it('filter(simple(...)): filters negative bodies', async () => {
116
+ let called = false;
117
+ const rd = new RouteDefinition('direct:test');
118
+ rd.filter(simple('${body} > 0')).process(() => { called = true; });
119
+ const pipeline = rd.compile();
120
+
121
+ const pos = new Exchange(); pos.in.body = 3;
122
+ await pipeline.run(pos);
123
+ assert.equal(called, true);
124
+
125
+ called = false;
126
+ const neg = new Exchange(); neg.in.body = -1;
127
+ await pipeline.run(neg);
128
+ assert.equal(called, false);
129
+ });
130
+
131
+ it('filter(js(...)): filters short strings', async () => {
132
+ let called = false;
133
+ const rd = new RouteDefinition('direct:test');
134
+ rd.filter(js('exchange.in.body.length > 2')).process(() => { called = true; });
135
+ const pipeline = rd.compile();
136
+
137
+ const long = new Exchange(); long.in.body = 'hello';
138
+ await pipeline.run(long);
139
+ assert.equal(called, true);
140
+
141
+ called = false;
142
+ const short = new Exchange(); short.in.body = 'hi';
143
+ await pipeline.run(short);
144
+ assert.equal(called, false);
145
+ });
146
+
147
+ it('filter sets CamelFilterMatched=true when passing', async () => {
148
+ const rd = new RouteDefinition('direct:test');
149
+ rd.filter((e) => true);
150
+ const pipeline = rd.compile();
151
+ const ex = new Exchange();
152
+ await pipeline.run(ex);
153
+ assert.equal(ex.getProperty('CamelFilterMatched'), true);
154
+ });
155
+ });
156
+
157
+ // ---------------------------------------------------------------------------
158
+ // transform()
159
+ // ---------------------------------------------------------------------------
160
+ describe('RouteDefinition.transform()', () => {
161
+ it('replaces body with expression return value', async () => {
162
+ const rd = new RouteDefinition('direct:test');
163
+ rd.transform((e) => e.in.body * 2);
164
+ const pipeline = rd.compile();
165
+ const ex = new Exchange(); ex.in.body = 5;
166
+ await pipeline.run(ex);
167
+ assert.equal(ex.in.body, 10);
168
+ });
169
+
170
+ it('transform(simple(...)): identity', async () => {
171
+ const rd = new RouteDefinition('direct:test');
172
+ rd.transform(simple('${body}'));
173
+ const pipeline = rd.compile();
174
+ const ex = new Exchange(); ex.in.body = 42;
175
+ await pipeline.run(ex);
176
+ assert.equal(ex.in.body, 42);
177
+ });
178
+
179
+ it('transform(js(...)): uppercase', async () => {
180
+ const rd = new RouteDefinition('direct:test');
181
+ rd.transform(js('exchange.in.body.toUpperCase()'));
182
+ const pipeline = rd.compile();
183
+ const ex = new Exchange(); ex.in.body = 'hello';
184
+ await pipeline.run(ex);
185
+ assert.equal(ex.in.body, 'HELLO');
186
+ });
187
+
188
+ it('chained: process → transform → process', async () => {
189
+ const rd = new RouteDefinition('direct:test');
190
+ rd.process((e) => { e.in.body = 3; })
191
+ .transform((e) => e.in.body * 2)
192
+ .process((e) => { e.in.body = e.in.body + 1; });
193
+ const pipeline = rd.compile();
194
+ const ex = new Exchange();
195
+ await pipeline.run(ex);
196
+ assert.equal(ex.in.body, 7); // (3*2)+1
197
+ });
198
+
199
+ it('filter(false) blocks transform', async () => {
200
+ let transformed = false;
201
+ const rd = new RouteDefinition('direct:test');
202
+ rd.filter((e) => false).transform((e) => { transformed = true; return e.in.body; });
203
+ const pipeline = rd.compile();
204
+ const ex = new Exchange(); ex.in.body = 'x';
205
+ await pipeline.run(ex);
206
+ assert.equal(transformed, false);
207
+ assert.equal(ex.exception, null);
208
+ });
209
+ });
210
+
211
+ // ---------------------------------------------------------------------------
212
+ // choice() / when() / otherwise() / end()
213
+ // ---------------------------------------------------------------------------
214
+ describe('RouteDefinition.choice() CBR', () => {
215
+ it('when() predicate matches — correct branch dispatched', async () => {
216
+ const context = new CamelContext();
217
+ context.addComponent('direct', new DirectComponent());
218
+
219
+ const routeA = new RouteDefinition('direct:a');
220
+ routeA.process((e) => { e.setProperty('branch', 'A'); });
221
+
222
+ const routeB = new RouteDefinition('direct:b');
223
+ routeB.process((e) => { e.setProperty('branch', 'B'); });
224
+
225
+ const routeMain = new RouteDefinition('direct:main');
226
+ routeMain.choice()
227
+ .when((e) => e.in.body === 'A').to('direct:a')
228
+ .when((e) => e.in.body === 'B').to('direct:b')
229
+ .end();
230
+
231
+ context.addRoutes({ configure() {}, getRoutes() { return [routeA, routeB, routeMain]; } });
232
+ await context.start();
233
+
234
+ const exA = new Exchange(); exA.in.body = 'A';
235
+ await context.getConsumer('direct:main').process(exA);
236
+ assert.equal(exA.getProperty('branch'), 'A');
237
+
238
+ const exB = new Exchange(); exB.in.body = 'B';
239
+ await context.getConsumer('direct:main').process(exB);
240
+ assert.equal(exB.getProperty('branch'), 'B');
241
+
242
+ await context.stop();
243
+ });
244
+
245
+ it('otherwise() catches unmatched exchanges', async () => {
246
+ const context = new CamelContext();
247
+ context.addComponent('direct', new DirectComponent());
248
+
249
+ const routeDefault = new RouteDefinition('direct:default');
250
+ routeDefault.process((e) => { e.setProperty('branch', 'default'); });
251
+
252
+ const routeMain = new RouteDefinition('direct:main');
253
+ routeMain.choice()
254
+ .when((e) => e.in.body === 'X').to('direct:default')
255
+ .otherwise().to('direct:default')
256
+ .end();
257
+
258
+ context.addRoutes({ configure() {}, getRoutes() { return [routeDefault, routeMain]; } });
259
+ await context.start();
260
+
261
+ const ex = new Exchange(); ex.in.body = 'other';
262
+ await context.getConsumer('direct:main').process(ex);
263
+ assert.equal(ex.getProperty('branch'), 'default');
264
+
265
+ await context.stop();
266
+ });
267
+
268
+ it('no match and no otherwise — exchange passes through unmodified', async () => {
269
+ const context = new CamelContext();
270
+ context.addComponent('direct', new DirectComponent());
271
+
272
+ const routeMain = new RouteDefinition('direct:main');
273
+ routeMain.choice()
274
+ .when((e) => e.in.body === 'X').to('direct:missing')
275
+ .end()
276
+ .process((e) => { e.in.body = 'after-choice'; });
277
+
278
+ context.addRoutes({ configure() {}, getRoutes() { return [routeMain]; } });
279
+ await context.start();
280
+
281
+ const ex = new Exchange(); ex.in.body = 'other';
282
+ await context.getConsumer('direct:main').process(ex);
283
+ assert.equal(ex.in.body, 'after-choice');
284
+ assert.equal(ex.exception, null);
285
+
286
+ await context.stop();
287
+ });
288
+
289
+ it('end() returns RouteDefinition for further chaining', () => {
290
+ const rd = new RouteDefinition('direct:test');
291
+ const result = rd.choice().when((e) => true).to('direct:a').end();
292
+ assert.strictEqual(result, rd);
293
+ });
294
+
295
+ it('when(simple(...)): routes by header value', async () => {
296
+ const context = new CamelContext();
297
+ context.addComponent('direct', new DirectComponent());
298
+
299
+ const routeVip = new RouteDefinition('direct:vip');
300
+ routeVip.process((e) => { e.setProperty('tier', 'vip'); });
301
+
302
+ const routeStd = new RouteDefinition('direct:std');
303
+ routeStd.process((e) => { e.setProperty('tier', 'standard'); });
304
+
305
+ const routeMain = new RouteDefinition('direct:main');
306
+ routeMain.choice()
307
+ .when(simple('${header.tier} == "vip"')).to('direct:vip')
308
+ .otherwise().to('direct:std')
309
+ .end();
310
+
311
+ context.addRoutes({ configure() {}, getRoutes() { return [routeVip, routeStd, routeMain]; } });
312
+ await context.start();
313
+
314
+ const exVip = new Exchange(); exVip.in.setHeader('tier', 'vip');
315
+ await context.getConsumer('direct:main').process(exVip);
316
+ assert.equal(exVip.getProperty('tier'), 'vip');
317
+
318
+ const exStd = new Exchange(); exStd.in.setHeader('tier', 'regular');
319
+ await context.getConsumer('direct:main').process(exStd);
320
+ assert.equal(exStd.getProperty('tier'), 'standard');
321
+
322
+ await context.stop();
323
+ });
324
+ });
325
+
326
+ // ---------------------------------------------------------------------------
327
+ // split()
328
+ // ---------------------------------------------------------------------------
329
+ describe('RouteDefinition.split()', () => {
330
+ it('splits array body into N sub-exchanges, collects results', async () => {
331
+ const rd = new RouteDefinition('direct:test');
332
+ rd.split((e) => e.in.body)
333
+ .process((e) => { e.in.body = e.in.body * 2; });
334
+ const pipeline = rd.compile();
335
+ const ex = new Exchange(); ex.in.body = [1, 2, 3];
336
+ await pipeline.run(ex);
337
+ assert.deepEqual(ex.in.body, [2, 4, 6]);
338
+ });
339
+
340
+ it('empty array produces []', async () => {
341
+ const rd = new RouteDefinition('direct:test');
342
+ rd.split((e) => e.in.body);
343
+ const pipeline = rd.compile();
344
+ const ex = new Exchange(); ex.in.body = [];
345
+ await pipeline.run(ex);
346
+ assert.deepEqual(ex.in.body, []);
347
+ });
348
+
349
+ it('split with expression function on nested property', async () => {
350
+ const rd = new RouteDefinition('direct:test');
351
+ rd.split((e) => e.in.body.items);
352
+ const pipeline = rd.compile();
353
+ const ex = new Exchange(); ex.in.body = { items: ['a', 'b'] };
354
+ await pipeline.run(ex);
355
+ assert.deepEqual(ex.in.body, ['a', 'b']);
356
+ });
357
+
358
+ it('sub-exchanges are independent — error in one does not stop others', async () => {
359
+ const results = [];
360
+ const rd = new RouteDefinition('direct:test');
361
+ rd.split((e) => e.in.body)
362
+ .process((e) => {
363
+ if (e.in.body === 2) throw new Error('fail-2');
364
+ results.push(e.in.body);
365
+ });
366
+ const pipeline = rd.compile();
367
+ const ex = new Exchange(); ex.in.body = [1, 2, 3];
368
+ await pipeline.run(ex);
369
+ // Sub-exchange 2 failed, others processed
370
+ assert.ok(results.includes(1));
371
+ assert.ok(results.includes(3));
372
+ });
373
+
374
+ it('split(simple(...)): splits via expression', async () => {
375
+ const rd = new RouteDefinition('direct:test');
376
+ // simple returns body directly; works when body is array
377
+ rd.split((e) => e.in.body).transform((e) => String(e.in.body) + '!');
378
+ const pipeline = rd.compile();
379
+ const ex = new Exchange(); ex.in.body = ['a', 'b'];
380
+ await pipeline.run(ex);
381
+ assert.deepEqual(ex.in.body, ['a!', 'b!']);
382
+ });
383
+
384
+ it('Exchange.clone() copies body and headers but not exception', () => {
385
+ const ex = new Exchange();
386
+ ex.in.body = 'hello';
387
+ ex.in.setHeader('h', '1');
388
+ ex.exception = new Error('orig');
389
+
390
+ const c = ex.clone();
391
+ assert.equal(c.in.body, 'hello');
392
+ assert.equal(c.in.getHeader('h'), '1');
393
+ assert.equal(c.exception, null);
394
+ });
395
+ });
396
+
397
+ // ---------------------------------------------------------------------------
398
+ // aggregate()
399
+ // ---------------------------------------------------------------------------
400
+ describe('RouteDefinition.aggregate()', () => {
401
+ it('completes at count=3, downstream called once with aggregated body', async () => {
402
+ let downstreamCount = 0;
403
+ const rd = new RouteDefinition('direct:test');
404
+ rd.aggregate(
405
+ (e) => e.in.getHeader('corrId'),
406
+ AggregationStrategies.collectBodies(),
407
+ 3
408
+ ).process((e) => { downstreamCount++; });
409
+
410
+ const pipeline = rd.compile();
411
+
412
+ for (let i = 0; i < 3; i++) {
413
+ const ex = new Exchange();
414
+ ex.in.body = i;
415
+ ex.in.setHeader('corrId', 'batch-1');
416
+ await pipeline.run(ex);
417
+ }
418
+
419
+ assert.equal(downstreamCount, 1);
420
+ });
421
+
422
+ it('first 2 of 3 stop cleanly (no exception)', async () => {
423
+ const rd = new RouteDefinition('direct:test');
424
+ rd.aggregate(
425
+ (e) => 'key',
426
+ AggregationStrategies.collectBodies(),
427
+ 3
428
+ );
429
+ const pipeline = rd.compile();
430
+
431
+ for (let i = 0; i < 2; i++) {
432
+ const ex = new Exchange(); ex.in.body = i;
433
+ await pipeline.run(ex);
434
+ assert.equal(ex.exception, null, `exchange ${i} should have no exception`);
435
+ }
436
+ });
437
+
438
+ it('collectBodies() strategy: result.in.body is array of all bodies', async () => {
439
+ let aggregatedBody;
440
+ const rd = new RouteDefinition('direct:test');
441
+ rd.aggregate(
442
+ (e) => 'key',
443
+ AggregationStrategies.collectBodies(),
444
+ 3
445
+ ).process((e) => { aggregatedBody = e.in.body; });
446
+
447
+ const pipeline = rd.compile();
448
+ for (let i = 0; i < 3; i++) {
449
+ const ex = new Exchange(); ex.in.body = `item-${i}`; ex.in.setHeader('corrId', 'k');
450
+ await pipeline.run(ex);
451
+ }
452
+ assert.deepEqual(aggregatedBody, ['item-0', 'item-1', 'item-2']);
453
+ });
454
+
455
+ it('latest() strategy: result is last exchange body', async () => {
456
+ let aggregatedBody;
457
+ const rd = new RouteDefinition('direct:test');
458
+ rd.aggregate(
459
+ (e) => 'key',
460
+ AggregationStrategies.latest(),
461
+ 3
462
+ ).process((e) => { aggregatedBody = e.in.body; });
463
+
464
+ const pipeline = rd.compile();
465
+ for (let i = 0; i < 3; i++) {
466
+ const ex = new Exchange(); ex.in.body = `msg-${i}`;
467
+ await pipeline.run(ex);
468
+ }
469
+ assert.equal(aggregatedBody, 'msg-2');
470
+ });
471
+
472
+ it('two correlation IDs complete independently', async () => {
473
+ const completions = [];
474
+ const rd = new RouteDefinition('direct:test');
475
+ rd.aggregate(
476
+ (e) => e.in.getHeader('batch'),
477
+ AggregationStrategies.collectBodies(),
478
+ 2
479
+ ).process((e) => { completions.push(e.in.body); });
480
+
481
+ const pipeline = rd.compile();
482
+
483
+ const send = async (body, batch) => {
484
+ const ex = new Exchange(); ex.in.body = body; ex.in.setHeader('batch', batch);
485
+ await pipeline.run(ex);
486
+ };
487
+
488
+ await send('a1', 'batchA');
489
+ await send('b1', 'batchB');
490
+ await send('a2', 'batchA'); // completes A
491
+ await send('b2', 'batchB'); // completes B
492
+
493
+ assert.equal(completions.length, 2);
494
+ assert.ok(completions.some(c => Array.isArray(c) && c.includes('a1') && c.includes('a2')));
495
+ assert.ok(completions.some(c => Array.isArray(c) && c.includes('b1') && c.includes('b2')));
496
+ });
497
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { Exchange } from '../src/Exchange.js';
4
+ import { Message } from '../src/Message.js';
5
+
6
+ describe('Exchange', () => {
7
+ it('constructs with default pattern InOnly', () => {
8
+ const ex = new Exchange();
9
+ assert.equal(ex.pattern, 'InOnly');
10
+ });
11
+
12
+ it('in and out are Message instances', () => {
13
+ const ex = new Exchange();
14
+ assert.ok(ex.in instanceof Message);
15
+ assert.ok(ex.out instanceof Message);
16
+ });
17
+
18
+ it('properties Map works via setProperty/getProperty', () => {
19
+ const ex = new Exchange();
20
+ assert.ok(ex.properties instanceof Map);
21
+ ex.setProperty('foo', 'bar');
22
+ assert.equal(ex.getProperty('foo'), 'bar');
23
+ });
24
+
25
+ it('exception defaults to null and isFailed() is false', () => {
26
+ const ex = new Exchange();
27
+ assert.equal(ex.exception, null);
28
+ assert.equal(ex.isFailed(), false);
29
+ });
30
+
31
+ it('setting exception makes isFailed() return true', () => {
32
+ const ex = new Exchange();
33
+ ex.exception = new Error('boom');
34
+ assert.equal(ex.isFailed(), true);
35
+ assert.ok(ex.exception instanceof Error);
36
+ });
37
+
38
+ it('supports InOut pattern', () => {
39
+ const ex = new Exchange('InOut');
40
+ assert.equal(ex.pattern, 'InOut');
41
+ });
42
+ });
@@ -0,0 +1,58 @@
1
+ routes:
2
+ - route:
3
+ id: "full-step-coverage"
4
+ from:
5
+ uri: "direct:loader-test"
6
+ steps:
7
+ - setBody:
8
+ constant: "initial-value"
9
+ - setHeader:
10
+ name: "X-Type"
11
+ simple: "${body}"
12
+ - setProperty:
13
+ name: "savedBody"
14
+ js: "exchange.in.body"
15
+ - removeHeader:
16
+ name: "X-Type"
17
+ - setBody:
18
+ constant:
19
+ amount: 100
20
+ currency: "USD"
21
+ - marshal:
22
+ format: json
23
+ - unmarshal:
24
+ format: json
25
+ - convertBodyTo: String
26
+ - log: "route step executed"
27
+ - stop: {}
28
+
29
+ - route:
30
+ id: "choice-route"
31
+ from:
32
+ uri: "direct:choice-test"
33
+ steps:
34
+ - choice:
35
+ when:
36
+ - simple: "${header.type} == 'A'"
37
+ to: "direct:branch-a"
38
+ - simple: "${header.type} == 'B'"
39
+ to: "direct:branch-b"
40
+ otherwise:
41
+ to: "direct:branch-default"
42
+
43
+ - route:
44
+ id: "bean-route"
45
+ from:
46
+ uri: "direct:bean-test"
47
+ steps:
48
+ - bean: "myTestBean"
49
+
50
+ - route:
51
+ id: "filter-route"
52
+ from:
53
+ uri: "direct:filter-test"
54
+ steps:
55
+ - filter:
56
+ simple: "${header.pass} == 'yes'"
57
+ - setBody:
58
+ constant: "filtered-through"
@@ -0,0 +1,36 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { Message } from '../src/Message.js';
4
+
5
+ describe('Message', () => {
6
+ it('constructs with a non-empty messageId', () => {
7
+ const msg = new Message();
8
+ assert.ok(msg.messageId, 'messageId should be truthy');
9
+ assert.equal(typeof msg.messageId, 'string');
10
+ assert.ok(msg.messageId.length > 0);
11
+ });
12
+
13
+ it('body defaults to null and can be set', () => {
14
+ const msg = new Message();
15
+ assert.equal(msg.body, null);
16
+ msg.body = 'hello';
17
+ assert.equal(msg.body, 'hello');
18
+ });
19
+
20
+ it('headers is a Map', () => {
21
+ const msg = new Message();
22
+ assert.ok(msg.headers instanceof Map);
23
+ });
24
+
25
+ it('setHeader and getHeader round-trip', () => {
26
+ const msg = new Message();
27
+ msg.setHeader('Content-Type', 'application/json');
28
+ assert.equal(msg.getHeader('Content-Type'), 'application/json');
29
+ });
30
+
31
+ it('two Messages have different messageIds', () => {
32
+ const a = new Message();
33
+ const b = new Message();
34
+ assert.notEqual(a.messageId, b.messageId);
35
+ });
36
+ });