@forgehive/hive-sdk 0.0.3 → 0.1.0
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/dist/index.d.ts +33 -21
- package/dist/index.js +72 -12
- package/dist/test/getLog.test.js +1 -1
- package/dist/test/index.test.js +8 -1
- package/dist/test/metadata.test.js +67 -20
- package/dist/test/sendLog.test.js +237 -30
- package/package.json +1 -1
- package/src/index.ts +30 -27
- package/src/test/getLog.test.ts +1 -1
- package/src/test/index.test.ts +8 -1
- package/src/test/metadata.test.ts +67 -20
- package/src/test/sendLog.test.ts +282 -30
|
@@ -77,8 +77,15 @@ describe('HiveLogClient Metadata', () => {
|
|
|
77
77
|
it('should send log without metadata parameter', async () => {
|
|
78
78
|
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
79
79
|
|
|
80
|
-
const
|
|
81
|
-
|
|
80
|
+
const executionRecord = {
|
|
81
|
+
input: 'test-input',
|
|
82
|
+
output: 'test-output',
|
|
83
|
+
taskName: 'test-task',
|
|
84
|
+
type: 'success' as const,
|
|
85
|
+
boundaries: {},
|
|
86
|
+
metadata: {}
|
|
87
|
+
}
|
|
88
|
+
const result = await client.sendLog(executionRecord)
|
|
82
89
|
|
|
83
90
|
expect(result).toBe('success')
|
|
84
91
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -89,6 +96,9 @@ describe('HiveLogClient Metadata', () => {
|
|
|
89
96
|
logItem: JSON.stringify({
|
|
90
97
|
input: 'test-input',
|
|
91
98
|
output: 'test-output',
|
|
99
|
+
taskName: 'test-task',
|
|
100
|
+
type: 'success',
|
|
101
|
+
boundaries: {},
|
|
92
102
|
metadata: {}
|
|
93
103
|
})
|
|
94
104
|
},
|
|
@@ -104,13 +114,20 @@ describe('HiveLogClient Metadata', () => {
|
|
|
104
114
|
it('should send log with metadata parameter', async () => {
|
|
105
115
|
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
106
116
|
|
|
107
|
-
const
|
|
117
|
+
const executionRecord = {
|
|
118
|
+
input: 'test-input',
|
|
119
|
+
output: 'test-output',
|
|
120
|
+
taskName: 'test-task',
|
|
121
|
+
type: 'success' as const,
|
|
122
|
+
boundaries: {},
|
|
123
|
+
metadata: {}
|
|
124
|
+
}
|
|
108
125
|
const metadata: Metadata = {
|
|
109
126
|
requestId: 'req-123',
|
|
110
127
|
userId: 'user-456'
|
|
111
128
|
}
|
|
112
129
|
|
|
113
|
-
const result = await client.sendLog(
|
|
130
|
+
const result = await client.sendLog(executionRecord, metadata)
|
|
114
131
|
|
|
115
132
|
expect(result).toBe('success')
|
|
116
133
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -121,6 +138,9 @@ describe('HiveLogClient Metadata', () => {
|
|
|
121
138
|
logItem: JSON.stringify({
|
|
122
139
|
input: 'test-input',
|
|
123
140
|
output: 'test-output',
|
|
141
|
+
taskName: 'test-task',
|
|
142
|
+
type: 'success',
|
|
143
|
+
boundaries: {},
|
|
124
144
|
metadata: {
|
|
125
145
|
requestId: 'req-123',
|
|
126
146
|
userId: 'user-456'
|
|
@@ -140,7 +160,7 @@ describe('HiveLogClient Metadata', () => {
|
|
|
140
160
|
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
141
161
|
|
|
142
162
|
const metadata: Metadata = { type: 'minimal' }
|
|
143
|
-
const result = await client.sendLog('test-task',
|
|
163
|
+
const result = await client.sendLog({ input: 'simple input', taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} }, metadata)
|
|
144
164
|
|
|
145
165
|
expect(result).toBe('success')
|
|
146
166
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -150,6 +170,9 @@ describe('HiveLogClient Metadata', () => {
|
|
|
150
170
|
taskName: 'test-task',
|
|
151
171
|
logItem: JSON.stringify({
|
|
152
172
|
input: 'simple input',
|
|
173
|
+
taskName: 'test-task',
|
|
174
|
+
type: 'success',
|
|
175
|
+
boundaries: {},
|
|
153
176
|
metadata: { type: 'minimal' }
|
|
154
177
|
})
|
|
155
178
|
},
|
|
@@ -161,7 +184,7 @@ describe('HiveLogClient Metadata', () => {
|
|
|
161
184
|
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
162
185
|
|
|
163
186
|
const metadata: Metadata = { type: 'null-test' }
|
|
164
|
-
const result = await client.sendLog('test-task', {
|
|
187
|
+
const result = await client.sendLog({ input: null, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} }, metadata)
|
|
165
188
|
|
|
166
189
|
expect(result).toBe('success')
|
|
167
190
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -171,6 +194,9 @@ describe('HiveLogClient Metadata', () => {
|
|
|
171
194
|
taskName: 'test-task',
|
|
172
195
|
logItem: JSON.stringify({
|
|
173
196
|
input: null,
|
|
197
|
+
taskName: 'test-task',
|
|
198
|
+
type: 'success',
|
|
199
|
+
boundaries: {},
|
|
174
200
|
metadata: { type: 'null-test' }
|
|
175
201
|
})
|
|
176
202
|
},
|
|
@@ -191,10 +217,13 @@ describe('HiveLogClient Metadata', () => {
|
|
|
191
217
|
const client = new HiveLogClient({ ...testConfig, metadata: baseMetadata })
|
|
192
218
|
const logItem = { input: 'test' }
|
|
193
219
|
|
|
194
|
-
await client.sendLog('test-task',
|
|
220
|
+
await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} })
|
|
195
221
|
|
|
196
222
|
const expectedLogItem = {
|
|
197
223
|
input: 'test',
|
|
224
|
+
taskName: 'test-task',
|
|
225
|
+
type: 'success',
|
|
226
|
+
boundaries: {},
|
|
198
227
|
metadata: {
|
|
199
228
|
environment: 'production',
|
|
200
229
|
version: '1.0.0'
|
|
@@ -229,7 +258,7 @@ describe('HiveLogClient Metadata', () => {
|
|
|
229
258
|
}
|
|
230
259
|
}
|
|
231
260
|
|
|
232
|
-
await client.sendLog('test-task', logItem)
|
|
261
|
+
await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} })
|
|
233
262
|
|
|
234
263
|
const expectedLogItem = {
|
|
235
264
|
input: 'test',
|
|
@@ -237,7 +266,10 @@ describe('HiveLogClient Metadata', () => {
|
|
|
237
266
|
environment: 'production', // from base
|
|
238
267
|
version: '1.1.0', // from logItem (overrides base)
|
|
239
268
|
sessionId: 'session-123' // from logItem
|
|
240
|
-
}
|
|
269
|
+
},
|
|
270
|
+
taskName: 'test-task',
|
|
271
|
+
type: 'success',
|
|
272
|
+
boundaries: {}
|
|
241
273
|
}
|
|
242
274
|
|
|
243
275
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -276,7 +308,7 @@ describe('HiveLogClient Metadata', () => {
|
|
|
276
308
|
priority: 'sendLog'
|
|
277
309
|
}
|
|
278
310
|
|
|
279
|
-
await client.sendLog('test-task', logItem, sendLogMetadata)
|
|
311
|
+
await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} }, sendLogMetadata)
|
|
280
312
|
|
|
281
313
|
const expectedLogItem = {
|
|
282
314
|
input: 'test',
|
|
@@ -286,7 +318,10 @@ describe('HiveLogClient Metadata', () => {
|
|
|
286
318
|
priority: 'sendLog', // from sendLog (highest priority)
|
|
287
319
|
sessionId: 'session-123', // from logItem
|
|
288
320
|
requestId: 'req-456' // from sendLog
|
|
289
|
-
}
|
|
321
|
+
},
|
|
322
|
+
taskName: 'test-task',
|
|
323
|
+
type: 'success',
|
|
324
|
+
boundaries: {}
|
|
290
325
|
}
|
|
291
326
|
|
|
292
327
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -327,7 +362,7 @@ describe('HiveLogClient Metadata', () => {
|
|
|
327
362
|
version: '1.2.0' // overrides both base and logItem
|
|
328
363
|
}
|
|
329
364
|
|
|
330
|
-
await client.sendLog('search-task', logItem, sendLogMetadata)
|
|
365
|
+
await client.sendLog({ ...logItem, taskName: 'search-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} }, sendLogMetadata)
|
|
331
366
|
|
|
332
367
|
const expectedLogItem = {
|
|
333
368
|
input: { query: 'search' },
|
|
@@ -341,7 +376,10 @@ describe('HiveLogClient Metadata', () => {
|
|
|
341
376
|
processingTime: '250', // from logItem
|
|
342
377
|
requestId: 'req-789', // from sendLog
|
|
343
378
|
userId: 'user-123' // from sendLog
|
|
344
|
-
}
|
|
379
|
+
},
|
|
380
|
+
taskName: 'search-task',
|
|
381
|
+
type: 'success',
|
|
382
|
+
boundaries: {}
|
|
345
383
|
}
|
|
346
384
|
|
|
347
385
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -368,10 +406,13 @@ describe('HiveLogClient Metadata', () => {
|
|
|
368
406
|
// No metadata property
|
|
369
407
|
}
|
|
370
408
|
|
|
371
|
-
await client.sendLog('test-task',
|
|
409
|
+
await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} })
|
|
372
410
|
|
|
373
411
|
const expectedLogItem = {
|
|
374
412
|
input: 'test',
|
|
413
|
+
taskName: 'test-task',
|
|
414
|
+
type: 'success',
|
|
415
|
+
boundaries: {},
|
|
375
416
|
metadata: {
|
|
376
417
|
environment: 'test' // Only base metadata should be used
|
|
377
418
|
}
|
|
@@ -399,13 +440,16 @@ describe('HiveLogClient Metadata', () => {
|
|
|
399
440
|
metadata: undefined
|
|
400
441
|
}
|
|
401
442
|
|
|
402
|
-
await client.sendLog('test-task', logItem)
|
|
443
|
+
await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} })
|
|
403
444
|
|
|
404
445
|
const expectedLogItem = {
|
|
405
446
|
input: 'test',
|
|
406
447
|
metadata: {
|
|
407
448
|
environment: 'test' // Only base metadata should be used
|
|
408
|
-
}
|
|
449
|
+
},
|
|
450
|
+
taskName: 'test-task',
|
|
451
|
+
type: 'success',
|
|
452
|
+
boundaries: {}
|
|
409
453
|
}
|
|
410
454
|
|
|
411
455
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -425,11 +469,14 @@ describe('HiveLogClient Metadata', () => {
|
|
|
425
469
|
const client = new HiveLogClient({ ...testConfig, metadata: {} })
|
|
426
470
|
const logItem = { input: 'test', metadata: {} }
|
|
427
471
|
|
|
428
|
-
await client.sendLog('test-task', logItem, {})
|
|
472
|
+
await client.sendLog({ ...logItem, taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: logItem.metadata || {} }, {})
|
|
429
473
|
|
|
430
474
|
const expectedLogItem = {
|
|
431
475
|
input: 'test',
|
|
432
|
-
metadata: {} // All empty metadata objects result in empty final metadata
|
|
476
|
+
metadata: {}, // All empty metadata objects result in empty final metadata
|
|
477
|
+
taskName: 'test-task',
|
|
478
|
+
type: 'success',
|
|
479
|
+
boundaries: {}
|
|
433
480
|
}
|
|
434
481
|
|
|
435
482
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -447,7 +494,7 @@ describe('HiveLogClient Metadata', () => {
|
|
|
447
494
|
const baseMetadata: Metadata = { environment: 'test' }
|
|
448
495
|
const silentClient = new HiveLogClient({ projectName: 'silent-project', metadata: baseMetadata })
|
|
449
496
|
|
|
450
|
-
const result = await silentClient.sendLog('test-task',
|
|
497
|
+
const result = await silentClient.sendLog({ input: 'test', taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} }, { requestId: 'req-123' })
|
|
451
498
|
|
|
452
499
|
expect(result).toBe('silent')
|
|
453
500
|
expect(mockedAxios.post).not.toHaveBeenCalled()
|
|
@@ -459,7 +506,7 @@ describe('HiveLogClient Metadata', () => {
|
|
|
459
506
|
const baseMetadata: Metadata = { environment: 'test' }
|
|
460
507
|
const client = new HiveLogClient({ ...testConfig, metadata: baseMetadata })
|
|
461
508
|
|
|
462
|
-
const result = await client.sendLog('test-task',
|
|
509
|
+
const result = await client.sendLog({ input: 'test', taskName: 'test-task', type: 'success' as const, boundaries: {}, metadata: {} }, { requestId: 'req-123' })
|
|
463
510
|
|
|
464
511
|
expect(result).toBe('error')
|
|
465
512
|
})
|
package/src/test/sendLog.test.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { HiveLogClient } from '../index'
|
|
|
5
5
|
jest.mock('axios')
|
|
6
6
|
const mockedAxios = axios as jest.Mocked<typeof axios>
|
|
7
7
|
|
|
8
|
-
describe('HiveLogClient sendLog', () => {
|
|
8
|
+
describe('HiveLogClient sendLog with ExecutionRecord', () => {
|
|
9
9
|
let client: HiveLogClient
|
|
10
10
|
|
|
11
11
|
const testConfig = {
|
|
@@ -23,13 +23,21 @@ describe('HiveLogClient sendLog', () => {
|
|
|
23
23
|
jest.clearAllMocks()
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
describe('successful sendLog', () => {
|
|
27
|
-
it('should send log successfully and return
|
|
26
|
+
describe('successful sendLog with ExecutionRecord', () => {
|
|
27
|
+
it('should send log successfully with ExecutionRecord and return success', async () => {
|
|
28
28
|
// Mock successful axios response
|
|
29
29
|
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
30
30
|
|
|
31
|
-
const
|
|
32
|
-
|
|
31
|
+
const executionRecord = {
|
|
32
|
+
input: { value: 'test-input' },
|
|
33
|
+
output: { result: 'test-output' },
|
|
34
|
+
taskName: 'test-task',
|
|
35
|
+
type: 'success' as const,
|
|
36
|
+
boundaries: {},
|
|
37
|
+
metadata: {}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const result = await client.sendLog(executionRecord)
|
|
33
41
|
|
|
34
42
|
expect(result).toBe('success')
|
|
35
43
|
expect(mockedAxios.post).toHaveBeenCalledTimes(1)
|
|
@@ -38,7 +46,14 @@ describe('HiveLogClient sendLog', () => {
|
|
|
38
46
|
{
|
|
39
47
|
projectName: 'test-project',
|
|
40
48
|
taskName: 'test-task',
|
|
41
|
-
logItem: JSON.stringify({
|
|
49
|
+
logItem: JSON.stringify({
|
|
50
|
+
input: { value: 'test-input' },
|
|
51
|
+
output: { result: 'test-output' },
|
|
52
|
+
taskName: 'test-task',
|
|
53
|
+
type: 'success',
|
|
54
|
+
boundaries: {},
|
|
55
|
+
metadata: {}
|
|
56
|
+
})
|
|
42
57
|
},
|
|
43
58
|
{
|
|
44
59
|
headers: {
|
|
@@ -49,19 +64,22 @@ describe('HiveLogClient sendLog', () => {
|
|
|
49
64
|
)
|
|
50
65
|
})
|
|
51
66
|
|
|
52
|
-
it('should handle complex
|
|
67
|
+
it('should handle ExecutionRecord with complex boundaries', async () => {
|
|
53
68
|
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
54
69
|
|
|
55
|
-
const
|
|
70
|
+
const executionRecord = {
|
|
56
71
|
input: { userId: 123, action: 'login' },
|
|
57
72
|
output: { success: true, sessionId: 'abc123' },
|
|
58
|
-
|
|
73
|
+
taskName: 'complex-task',
|
|
74
|
+
type: 'success' as const,
|
|
59
75
|
boundaries: {
|
|
60
|
-
database: [{ input: 'SELECT * FROM users', output: [{ id: 123 }], error: null }]
|
|
61
|
-
|
|
76
|
+
database: [{ input: 'SELECT * FROM users', output: [{ id: 123 }], error: null }],
|
|
77
|
+
api: [{ input: { endpoint: '/auth' }, output: { token: 'jwt123' }, error: null }]
|
|
78
|
+
},
|
|
79
|
+
metadata: { environment: 'test' }
|
|
62
80
|
}
|
|
63
81
|
|
|
64
|
-
const result = await client.sendLog(
|
|
82
|
+
const result = await client.sendLog(executionRecord)
|
|
65
83
|
|
|
66
84
|
expect(result).toBe('success')
|
|
67
85
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
@@ -69,7 +87,17 @@ describe('HiveLogClient sendLog', () => {
|
|
|
69
87
|
{
|
|
70
88
|
projectName: 'test-project',
|
|
71
89
|
taskName: 'complex-task',
|
|
72
|
-
logItem: JSON.stringify({
|
|
90
|
+
logItem: JSON.stringify({
|
|
91
|
+
input: { userId: 123, action: 'login' },
|
|
92
|
+
output: { success: true, sessionId: 'abc123' },
|
|
93
|
+
taskName: 'complex-task',
|
|
94
|
+
type: 'success',
|
|
95
|
+
boundaries: {
|
|
96
|
+
database: [{ input: 'SELECT * FROM users', output: [{ id: 123 }], error: null }],
|
|
97
|
+
api: [{ input: { endpoint: '/auth' }, output: { token: 'jwt123' }, error: null }]
|
|
98
|
+
},
|
|
99
|
+
metadata: { environment: 'test' }
|
|
100
|
+
})
|
|
73
101
|
},
|
|
74
102
|
{
|
|
75
103
|
headers: {
|
|
@@ -79,64 +107,288 @@ describe('HiveLogClient sendLog', () => {
|
|
|
79
107
|
}
|
|
80
108
|
)
|
|
81
109
|
})
|
|
110
|
+
|
|
111
|
+
it('should handle ExecutionRecord with error', async () => {
|
|
112
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
113
|
+
|
|
114
|
+
const executionRecord = {
|
|
115
|
+
input: { value: 'test-input' },
|
|
116
|
+
output: undefined,
|
|
117
|
+
error: 'Task execution failed',
|
|
118
|
+
taskName: 'error-task',
|
|
119
|
+
type: 'error' as const,
|
|
120
|
+
boundaries: {},
|
|
121
|
+
metadata: {}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const result = await client.sendLog(executionRecord)
|
|
125
|
+
|
|
126
|
+
expect(result).toBe('success')
|
|
127
|
+
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
128
|
+
'https://test-host.com/api/tasks/log-ingest',
|
|
129
|
+
{
|
|
130
|
+
projectName: 'test-project',
|
|
131
|
+
taskName: 'error-task',
|
|
132
|
+
logItem: JSON.stringify({
|
|
133
|
+
input: { value: 'test-input' },
|
|
134
|
+
output: undefined,
|
|
135
|
+
error: 'Task execution failed',
|
|
136
|
+
taskName: 'error-task',
|
|
137
|
+
type: 'error',
|
|
138
|
+
boundaries: {},
|
|
139
|
+
metadata: {}
|
|
140
|
+
})
|
|
141
|
+
},
|
|
142
|
+
expect.any(Object)
|
|
143
|
+
)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('should use "unknown-task" when taskName is missing', async () => {
|
|
147
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
148
|
+
|
|
149
|
+
const executionRecord = {
|
|
150
|
+
input: { value: 'test-input' },
|
|
151
|
+
output: { result: 'test-output' },
|
|
152
|
+
// taskName is missing
|
|
153
|
+
type: 'success' as const,
|
|
154
|
+
boundaries: {},
|
|
155
|
+
metadata: {}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const result = await client.sendLog(executionRecord)
|
|
159
|
+
|
|
160
|
+
expect(result).toBe('success')
|
|
161
|
+
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
162
|
+
'https://test-host.com/api/tasks/log-ingest',
|
|
163
|
+
{
|
|
164
|
+
projectName: 'test-project',
|
|
165
|
+
taskName: 'unknown-task',
|
|
166
|
+
logItem: JSON.stringify({
|
|
167
|
+
input: { value: 'test-input' },
|
|
168
|
+
output: { result: 'test-output' },
|
|
169
|
+
type: 'success',
|
|
170
|
+
boundaries: {},
|
|
171
|
+
metadata: {},
|
|
172
|
+
taskName: 'unknown-task'
|
|
173
|
+
})
|
|
174
|
+
},
|
|
175
|
+
expect.any(Object)
|
|
176
|
+
)
|
|
177
|
+
})
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
describe('sendLog with additional metadata', () => {
|
|
181
|
+
it('should merge metadata from ExecutionRecord and sendLog parameter', async () => {
|
|
182
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
183
|
+
|
|
184
|
+
const executionRecord = {
|
|
185
|
+
input: { value: 'test-input' },
|
|
186
|
+
output: { result: 'test-output' },
|
|
187
|
+
taskName: 'metadata-task',
|
|
188
|
+
type: 'success' as const,
|
|
189
|
+
boundaries: {},
|
|
190
|
+
metadata: {
|
|
191
|
+
recordMeta: 'from-record',
|
|
192
|
+
sharedKey: 'record-value'
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const sendLogMetadata = {
|
|
197
|
+
sendLogMeta: 'from-sendlog',
|
|
198
|
+
sharedKey: 'sendlog-value' // This should override record value
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const result = await client.sendLog(executionRecord, sendLogMetadata)
|
|
202
|
+
|
|
203
|
+
expect(result).toBe('success')
|
|
204
|
+
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
205
|
+
'https://test-host.com/api/tasks/log-ingest',
|
|
206
|
+
{
|
|
207
|
+
projectName: 'test-project',
|
|
208
|
+
taskName: 'metadata-task',
|
|
209
|
+
logItem: JSON.stringify({
|
|
210
|
+
input: { value: 'test-input' },
|
|
211
|
+
output: { result: 'test-output' },
|
|
212
|
+
taskName: 'metadata-task',
|
|
213
|
+
type: 'success',
|
|
214
|
+
boundaries: {},
|
|
215
|
+
metadata: {
|
|
216
|
+
recordMeta: 'from-record',
|
|
217
|
+
sharedKey: 'sendlog-value', // sendLog metadata takes priority
|
|
218
|
+
sendLogMeta: 'from-sendlog'
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
},
|
|
222
|
+
expect.any(Object)
|
|
223
|
+
)
|
|
224
|
+
})
|
|
82
225
|
})
|
|
83
226
|
|
|
84
227
|
describe('failed sendLog', () => {
|
|
85
|
-
it('should return
|
|
228
|
+
it('should return error when axios throws an error', async () => {
|
|
86
229
|
// Mock axios to throw an error
|
|
87
230
|
mockedAxios.post.mockRejectedValueOnce(new Error('Network error'))
|
|
88
231
|
|
|
89
|
-
const
|
|
90
|
-
|
|
232
|
+
const executionRecord = {
|
|
233
|
+
input: { value: 'test-input' },
|
|
234
|
+
taskName: 'test-task',
|
|
235
|
+
type: 'success' as const,
|
|
236
|
+
boundaries: {},
|
|
237
|
+
metadata: {}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const result = await client.sendLog(executionRecord)
|
|
91
241
|
|
|
92
242
|
expect(result).toBe('error')
|
|
93
243
|
})
|
|
94
244
|
|
|
95
|
-
it('should return
|
|
245
|
+
it('should return error when server returns 500', async () => {
|
|
96
246
|
// Mock axios to throw a server error
|
|
97
247
|
const serverError = new Error('Server Error')
|
|
98
248
|
mockedAxios.post.mockRejectedValueOnce(serverError)
|
|
99
249
|
|
|
100
|
-
const
|
|
250
|
+
const executionRecord = {
|
|
251
|
+
input: { value: 'test' },
|
|
252
|
+
taskName: 'test-task',
|
|
253
|
+
type: 'success' as const,
|
|
254
|
+
boundaries: {},
|
|
255
|
+
metadata: {}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const result = await client.sendLog(executionRecord)
|
|
101
259
|
|
|
102
260
|
expect(result).toBe('error')
|
|
103
261
|
})
|
|
104
262
|
})
|
|
105
263
|
|
|
106
|
-
describe('sendLog
|
|
107
|
-
it('should
|
|
264
|
+
describe('sendLog in silent mode', () => {
|
|
265
|
+
it('should return silent when client is not initialized', async () => {
|
|
266
|
+
const uninitializedClient = new HiveLogClient({
|
|
267
|
+
projectName: 'test-project'
|
|
268
|
+
// No API credentials
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
const executionRecord = {
|
|
272
|
+
input: { value: 'test-input' },
|
|
273
|
+
taskName: 'test-task',
|
|
274
|
+
type: 'success' as const,
|
|
275
|
+
boundaries: {},
|
|
276
|
+
metadata: {}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const result = await uninitializedClient.sendLog(executionRecord)
|
|
280
|
+
|
|
281
|
+
expect(result).toBe('silent')
|
|
282
|
+
expect(mockedAxios.post).not.toHaveBeenCalled()
|
|
283
|
+
})
|
|
284
|
+
})
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
describe('HiveLogClient getListener', () => {
|
|
289
|
+
let client: HiveLogClient
|
|
290
|
+
|
|
291
|
+
const testConfig = {
|
|
292
|
+
projectName: 'test-project',
|
|
293
|
+
apiKey: 'test-api-key',
|
|
294
|
+
apiSecret: 'test-api-secret',
|
|
295
|
+
host: 'https://test-host.com'
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
beforeEach(() => {
|
|
299
|
+
client = new HiveLogClient(testConfig)
|
|
300
|
+
jest.clearAllMocks()
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
describe('getListener method', () => {
|
|
304
|
+
it('should return a function that calls sendLog', async () => {
|
|
108
305
|
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
109
306
|
|
|
110
|
-
const
|
|
307
|
+
const listener = client.getListener()
|
|
111
308
|
|
|
112
|
-
expect(
|
|
309
|
+
expect(typeof listener).toBe('function')
|
|
310
|
+
|
|
311
|
+
const executionRecord = {
|
|
312
|
+
input: { value: 'test-input' },
|
|
313
|
+
output: { result: 'test-output' },
|
|
314
|
+
taskName: 'test-task',
|
|
315
|
+
type: 'success' as const,
|
|
316
|
+
boundaries: {},
|
|
317
|
+
metadata: {}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
await listener(executionRecord)
|
|
321
|
+
|
|
322
|
+
expect(mockedAxios.post).toHaveBeenCalledTimes(1)
|
|
113
323
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
114
324
|
'https://test-host.com/api/tasks/log-ingest',
|
|
115
325
|
{
|
|
116
326
|
projectName: 'test-project',
|
|
117
|
-
taskName: '
|
|
118
|
-
logItem: JSON.stringify({
|
|
327
|
+
taskName: 'test-task',
|
|
328
|
+
logItem: JSON.stringify({
|
|
329
|
+
input: { value: 'test-input' },
|
|
330
|
+
output: { result: 'test-output' },
|
|
331
|
+
taskName: 'test-task',
|
|
332
|
+
type: 'success',
|
|
333
|
+
boundaries: {},
|
|
334
|
+
metadata: {}
|
|
335
|
+
})
|
|
119
336
|
},
|
|
120
337
|
expect.any(Object)
|
|
121
338
|
)
|
|
122
339
|
})
|
|
123
340
|
|
|
124
|
-
it('should
|
|
341
|
+
it('should return a function that calls sendLog with provided metadata', async () => {
|
|
125
342
|
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
126
343
|
|
|
127
|
-
const
|
|
128
|
-
|
|
344
|
+
const listener = client.getListener()
|
|
345
|
+
|
|
346
|
+
const executionRecord = {
|
|
347
|
+
input: { value: 'test-input' },
|
|
348
|
+
output: { result: 'test-output' },
|
|
349
|
+
taskName: 'test-task',
|
|
350
|
+
type: 'success' as const,
|
|
351
|
+
boundaries: {},
|
|
352
|
+
metadata: { recordMeta: 'from-record' }
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
await listener(executionRecord)
|
|
129
356
|
|
|
130
|
-
expect(result).toBe('success')
|
|
131
357
|
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
132
358
|
'https://test-host.com/api/tasks/log-ingest',
|
|
133
359
|
{
|
|
134
360
|
projectName: 'test-project',
|
|
135
|
-
taskName: '
|
|
136
|
-
logItem: JSON.stringify({
|
|
361
|
+
taskName: 'test-task',
|
|
362
|
+
logItem: JSON.stringify({
|
|
363
|
+
input: { value: 'test-input' },
|
|
364
|
+
output: { result: 'test-output' },
|
|
365
|
+
taskName: 'test-task',
|
|
366
|
+
type: 'success',
|
|
367
|
+
boundaries: {},
|
|
368
|
+
metadata: {
|
|
369
|
+
recordMeta: 'from-record'
|
|
370
|
+
}
|
|
371
|
+
})
|
|
137
372
|
},
|
|
138
373
|
expect.any(Object)
|
|
139
374
|
)
|
|
140
375
|
})
|
|
376
|
+
|
|
377
|
+
it('should handle listener errors gracefully', async () => {
|
|
378
|
+
mockedAxios.post.mockRejectedValueOnce(new Error('Network error'))
|
|
379
|
+
|
|
380
|
+
const listener = client.getListener()
|
|
381
|
+
|
|
382
|
+
const executionRecord = {
|
|
383
|
+
input: { value: 'test-input' },
|
|
384
|
+
taskName: 'test-task',
|
|
385
|
+
type: 'success' as const,
|
|
386
|
+
boundaries: {},
|
|
387
|
+
metadata: {}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Should not throw, even if sendLog fails
|
|
391
|
+
await expect(listener(executionRecord)).resolves.toBeUndefined()
|
|
392
|
+
})
|
|
141
393
|
})
|
|
142
394
|
})
|