@forgehive/hive-sdk 0.0.1
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/LICENSE +21 -0
- package/README.md +357 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +123 -0
- package/dist/test/getLog.test.d.ts +1 -0
- package/dist/test/getLog.test.js +144 -0
- package/dist/test/index.test.d.ts +1 -0
- package/dist/test/index.test.js +96 -0
- package/dist/test/sendLog.test.d.ts +1 -0
- package/dist/test/sendLog.test.js +111 -0
- package/dist/test/setQuality.test.d.ts +1 -0
- package/dist/test/setQuality.test.js +192 -0
- package/jest.config.js +11 -0
- package/package.json +25 -0
- package/src/index.ts +168 -0
- package/src/test/getLog.test.ts +181 -0
- package/src/test/index.test.ts +126 -0
- package/src/test/sendLog.test.ts +148 -0
- package/src/test/setQuality.test.ts +268 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
import { HiveLogClient, Quality } from '../index'
|
|
3
|
+
|
|
4
|
+
// Mock axios
|
|
5
|
+
jest.mock('axios')
|
|
6
|
+
const mockedAxios = axios as jest.Mocked<typeof axios>
|
|
7
|
+
|
|
8
|
+
describe('HiveLogClient setQuality', () => {
|
|
9
|
+
const originalEnv = process.env
|
|
10
|
+
let client: HiveLogClient
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.resetModules()
|
|
14
|
+
process.env = { ...originalEnv }
|
|
15
|
+
|
|
16
|
+
// Set up environment variables
|
|
17
|
+
process.env.HIVE_API_KEY = 'test-api-key'
|
|
18
|
+
process.env.HIVE_API_SECRET = 'test-api-secret'
|
|
19
|
+
process.env.HIVE_HOST = 'https://test-host.com'
|
|
20
|
+
|
|
21
|
+
// Create client instance
|
|
22
|
+
client = new HiveLogClient('test-project')
|
|
23
|
+
|
|
24
|
+
// Clear all mocks
|
|
25
|
+
jest.clearAllMocks()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
afterAll(() => {
|
|
29
|
+
process.env = originalEnv
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
describe('successful setQuality', () => {
|
|
33
|
+
it('should set quality successfully and return true', async () => {
|
|
34
|
+
// Mock successful axios response
|
|
35
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
36
|
+
|
|
37
|
+
const quality: Quality = {
|
|
38
|
+
score: 8.5,
|
|
39
|
+
reason: 'Good performance with minor improvements needed',
|
|
40
|
+
suggestions: 'Consider optimizing the database query for better performance'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const result = await client.setQuality('test-task', 'test-uuid-123', quality)
|
|
44
|
+
|
|
45
|
+
expect(result).toBe(true)
|
|
46
|
+
expect(mockedAxios.post).toHaveBeenCalledTimes(1)
|
|
47
|
+
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
48
|
+
'https://test-host.com/api/tasks/test-task/logs/test-uuid-123/set-quality',
|
|
49
|
+
{
|
|
50
|
+
quality
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
headers: {
|
|
54
|
+
Authorization: 'Bearer test-api-key:test-api-secret',
|
|
55
|
+
'Content-Type': 'application/json'
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('should handle perfect score quality', async () => {
|
|
62
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
63
|
+
|
|
64
|
+
const perfectQuality: Quality = {
|
|
65
|
+
score: 10,
|
|
66
|
+
reason: 'Excellent implementation with no issues found',
|
|
67
|
+
suggestions: 'No improvements needed, great work!'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const result = await client.setQuality('perfect-task', 'perfect-uuid', perfectQuality)
|
|
71
|
+
|
|
72
|
+
expect(result).toBe(true)
|
|
73
|
+
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
74
|
+
'https://test-host.com/api/tasks/perfect-task/logs/perfect-uuid/set-quality',
|
|
75
|
+
{
|
|
76
|
+
quality: perfectQuality
|
|
77
|
+
},
|
|
78
|
+
expect.any(Object)
|
|
79
|
+
)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('should handle poor score quality with detailed suggestions', async () => {
|
|
83
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
84
|
+
|
|
85
|
+
const poorQuality: Quality = {
|
|
86
|
+
score: 2.0,
|
|
87
|
+
reason: 'Multiple issues found including performance problems and code quality issues',
|
|
88
|
+
suggestions: 'Refactor the main function, add error handling, optimize database queries, and improve variable naming conventions'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const result = await client.setQuality('poor-task', 'poor-uuid', poorQuality)
|
|
92
|
+
|
|
93
|
+
expect(result).toBe(true)
|
|
94
|
+
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
95
|
+
'https://test-host.com/api/tasks/poor-task/logs/poor-uuid/set-quality',
|
|
96
|
+
{
|
|
97
|
+
quality: poorQuality
|
|
98
|
+
},
|
|
99
|
+
expect.any(Object)
|
|
100
|
+
)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('should handle edge case scores', async () => {
|
|
104
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
105
|
+
|
|
106
|
+
const edgeCaseQuality: Quality = {
|
|
107
|
+
score: 0,
|
|
108
|
+
reason: 'Critical failure in implementation',
|
|
109
|
+
suggestions: 'Complete rewrite required'
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const result = await client.setQuality('edge-task', 'edge-uuid', edgeCaseQuality)
|
|
113
|
+
|
|
114
|
+
expect(result).toBe(true)
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
describe('failed setQuality', () => {
|
|
119
|
+
it('should return false when axios throws an error', async () => {
|
|
120
|
+
// Mock axios to throw an error
|
|
121
|
+
mockedAxios.post.mockRejectedValueOnce(new Error('Network error'))
|
|
122
|
+
|
|
123
|
+
const quality: Quality = {
|
|
124
|
+
score: 7.0,
|
|
125
|
+
reason: 'Test quality',
|
|
126
|
+
suggestions: 'Test suggestions'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const result = await client.setQuality('test-task', 'test-uuid', quality)
|
|
130
|
+
|
|
131
|
+
expect(result).toBe(false)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('should return false when server returns 404', async () => {
|
|
135
|
+
// Mock axios to throw a 404 error
|
|
136
|
+
const notFoundError = new Error('Request failed with status code 404')
|
|
137
|
+
mockedAxios.post.mockRejectedValueOnce(notFoundError)
|
|
138
|
+
|
|
139
|
+
const quality: Quality = {
|
|
140
|
+
score: 5.0,
|
|
141
|
+
reason: 'Not found test',
|
|
142
|
+
suggestions: 'Test suggestions for not found'
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const result = await client.setQuality('non-existent-task', 'non-existent-uuid', quality)
|
|
146
|
+
|
|
147
|
+
expect(result).toBe(false)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('should return false when server returns 500', async () => {
|
|
151
|
+
// Mock axios to throw a server error
|
|
152
|
+
const serverError = new Error('Internal Server Error')
|
|
153
|
+
mockedAxios.post.mockRejectedValueOnce(serverError)
|
|
154
|
+
|
|
155
|
+
const quality: Quality = {
|
|
156
|
+
score: 6.0,
|
|
157
|
+
reason: 'Server error test',
|
|
158
|
+
suggestions: 'Test suggestions for server error'
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const result = await client.setQuality('test-task', 'test-uuid', quality)
|
|
162
|
+
|
|
163
|
+
expect(result).toBe(false)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
it('should return false when unauthorized', async () => {
|
|
167
|
+
// Mock axios to throw an unauthorized error
|
|
168
|
+
const unauthorizedError = new Error('Request failed with status code 401')
|
|
169
|
+
mockedAxios.post.mockRejectedValueOnce(unauthorizedError)
|
|
170
|
+
|
|
171
|
+
const quality: Quality = {
|
|
172
|
+
score: 3.0,
|
|
173
|
+
reason: 'Unauthorized test',
|
|
174
|
+
suggestions: 'Check API credentials'
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const result = await client.setQuality('test-task', 'test-uuid', quality)
|
|
178
|
+
|
|
179
|
+
expect(result).toBe(false)
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
describe('setQuality parameters', () => {
|
|
184
|
+
it('should handle special characters in taskName and uuid', async () => {
|
|
185
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
186
|
+
|
|
187
|
+
const quality: Quality = {
|
|
188
|
+
score: 4.5,
|
|
189
|
+
reason: 'Special characters test',
|
|
190
|
+
suggestions: 'Handle special characters properly'
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const result = await client.setQuality('task-with-special-chars-!@#', 'uuid-with-special-chars-!@#', quality)
|
|
194
|
+
|
|
195
|
+
expect(result).toBe(true)
|
|
196
|
+
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
197
|
+
'https://test-host.com/api/tasks/task-with-special-chars-!@#/logs/uuid-with-special-chars-!@#/set-quality',
|
|
198
|
+
{ quality },
|
|
199
|
+
expect.any(Object)
|
|
200
|
+
)
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('should handle decimal scores correctly', async () => {
|
|
204
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
205
|
+
|
|
206
|
+
const quality: Quality = {
|
|
207
|
+
score: 7.123456789,
|
|
208
|
+
reason: 'Decimal precision test',
|
|
209
|
+
suggestions: 'Maintain precision in quality scores'
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const result = await client.setQuality('decimal-task', 'decimal-uuid', quality)
|
|
213
|
+
|
|
214
|
+
expect(result).toBe(true)
|
|
215
|
+
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
216
|
+
'https://test-host.com/api/tasks/decimal-task/logs/decimal-uuid/set-quality',
|
|
217
|
+
{ quality },
|
|
218
|
+
expect.any(Object)
|
|
219
|
+
)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('should handle long reason and suggestions', async () => {
|
|
223
|
+
mockedAxios.post.mockResolvedValueOnce({ data: { success: true } })
|
|
224
|
+
|
|
225
|
+
const longReason = 'This is a very long reason that explains in detail what went wrong with the implementation and why the score is what it is. '.repeat(5)
|
|
226
|
+
const longSuggestions = 'Here are detailed suggestions for improvement: 1. Refactor the main function, 2. Add comprehensive error handling, 3. Optimize database queries, 4. Improve code documentation, 5. Add unit tests. '.repeat(3)
|
|
227
|
+
|
|
228
|
+
const quality: Quality = {
|
|
229
|
+
score: 3.5,
|
|
230
|
+
reason: longReason,
|
|
231
|
+
suggestions: longSuggestions
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const result = await client.setQuality('long-text-task', 'long-text-uuid', quality)
|
|
235
|
+
|
|
236
|
+
expect(result).toBe(true)
|
|
237
|
+
expect(mockedAxios.post).toHaveBeenCalledWith(
|
|
238
|
+
'https://test-host.com/api/tasks/long-text-task/logs/long-text-uuid/set-quality',
|
|
239
|
+
{ quality },
|
|
240
|
+
expect.any(Object)
|
|
241
|
+
)
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
describe('silent mode behavior', () => {
|
|
246
|
+
it('should throw error when credentials are missing', async () => {
|
|
247
|
+
// Create client without credentials
|
|
248
|
+
process.env.HIVE_API_KEY = ''
|
|
249
|
+
process.env.HIVE_API_SECRET = ''
|
|
250
|
+
process.env.HIVE_HOST = ''
|
|
251
|
+
|
|
252
|
+
const silentClient = new HiveLogClient('silent-project')
|
|
253
|
+
|
|
254
|
+
const quality: Quality = {
|
|
255
|
+
score: 8.0,
|
|
256
|
+
reason: 'Test quality for silent mode',
|
|
257
|
+
suggestions: 'This should not be processed'
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
await expect(silentClient.setQuality('test-task', 'test-uuid', quality))
|
|
261
|
+
.rejects
|
|
262
|
+
.toThrow('Missing Hive API credentials or host, get them at https://forgehive.dev')
|
|
263
|
+
|
|
264
|
+
// Verify axios was never called
|
|
265
|
+
expect(mockedAxios.post).not.toHaveBeenCalled()
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
})
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"strictNullChecks": true,
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"resolveJsonModule": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"module": "commonjs",
|
|
9
|
+
"moduleResolution": "node",
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"target": "es2020",
|
|
12
|
+
"lib": ["es2020", "dom"]
|
|
13
|
+
},
|
|
14
|
+
"files": ["src/index.ts"],
|
|
15
|
+
"include": ["src/**/*.ts", "src/**/*.json"],
|
|
16
|
+
"exclude": ["node_modules", "dist/*"]
|
|
17
|
+
}
|