@@ -2,22 +2,30 @@ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
2
import { createTestHttpServer } from "@epic-web/test-server/http" ;
3
3
import { StandardMetadataManager } from "../src/v3/runMetadata/manager.js" ;
4
4
import { ApiClient } from "../src/v3/apiClient/index.js" ;
5
+ import { UpdateMetadataRequestBody } from "../src/v3/schemas/index.js" ;
6
+ import { applyMetadataOperations } from "../src/v3/runMetadata/operations.js" ;
5
7
6
8
describe ( "StandardMetadataManager" , ( ) => {
7
9
const runId = "test-run-id" ;
8
10
let server : Awaited < ReturnType < typeof createTestHttpServer > > ;
9
- let metadataUpdates : Array < Record < string , any > > = [ ] ;
11
+ let metadataUpdates : Array < UpdateMetadataRequestBody > = [ ] ;
10
12
let manager : StandardMetadataManager ;
11
13
12
14
beforeEach ( async ( ) => {
13
15
metadataUpdates = [ ] ;
16
+ const store = { } ;
14
17
15
18
server = await createTestHttpServer ( {
16
19
defineRoutes ( router ) {
17
20
router . put ( "/api/v1/runs/:runId/metadata" , async ( { req } ) => {
18
21
const body = await req . json ( ) ;
19
- metadataUpdates . push ( body ) ;
20
- return Response . json ( { metadata : body . metadata } ) ;
22
+ const parsedBody = UpdateMetadataRequestBody . parse ( body ) ;
23
+
24
+ metadataUpdates . push ( parsedBody ) ;
25
+
26
+ const { newMetadata } = applyMetadataOperations ( store , parsedBody . operations ?? [ ] ) ;
27
+
28
+ return Response . json ( { metadata : newMetadata } ) ;
21
29
} ) ;
22
30
} ,
23
31
} ) ;
@@ -37,13 +45,13 @@ describe("StandardMetadataManager", () => {
37
45
} ) ;
38
46
39
47
test ( "should set and get simple keys" , ( ) => {
40
- manager . setKey ( "test" , "value" ) ;
48
+ manager . set ( "test" , "value" ) ;
41
49
expect ( manager . getKey ( "test" ) ) . toBe ( "value" ) ;
42
50
} ) ;
43
51
44
52
test ( "should handle JSON path keys" , ( ) => {
45
- manager . setKey ( "nested" , { foo : "bar" } ) ;
46
- manager . setKey ( "$.nested.path" , "value" ) ;
53
+ manager . set ( "nested" , { foo : "bar" } ) ;
54
+ manager . set ( "$.nested.path" , "value" ) ;
47
55
expect ( manager . current ( ) ) . toEqual ( {
48
56
nested : {
49
57
foo : "bar" ,
@@ -53,79 +61,74 @@ describe("StandardMetadataManager", () => {
53
61
} ) ;
54
62
55
63
test ( "should flush changes to server" , async ( ) => {
56
- manager . setKey ( "test" , "value" ) ;
64
+ manager . set ( "test" , "value" ) ;
57
65
await manager . flush ( ) ;
58
66
59
67
expect ( metadataUpdates ) . toHaveLength ( 1 ) ;
60
- expect ( metadataUpdates [ 0 ] ) . toEqual ( {
61
- metadata : {
62
- test : "value" ,
63
- } ,
64
- } ) ;
65
68
} ) ;
66
69
67
70
test ( "should only flush to server when data has actually changed" , async ( ) => {
68
71
// Initial set and flush
69
- manager . setKey ( "test" , "value" ) ;
72
+ manager . set ( "test" , "value" ) ;
70
73
await manager . flush ( ) ;
71
74
expect ( metadataUpdates ) . toHaveLength ( 1 ) ;
72
75
73
76
// Same value set again
74
- manager . setKey ( "test" , "value" ) ;
77
+ manager . set ( "test" , "value" ) ;
75
78
await manager . flush ( ) ;
76
79
// Should not trigger another update since value hasn't changed
77
80
expect ( metadataUpdates ) . toHaveLength ( 1 ) ;
78
81
79
82
// Different value set
80
- manager . setKey ( "test" , "new value" ) ;
83
+ manager . set ( "test" , "new value" ) ;
81
84
await manager . flush ( ) ;
82
85
// Should trigger new update
83
86
expect ( metadataUpdates ) . toHaveLength ( 2 ) ;
84
87
} ) ;
85
88
86
89
test ( "should only flush to server when nested data has actually changed" , async ( ) => {
87
90
// Initial nested object
88
- manager . setKey ( "nested" , { foo : "bar" } ) ;
91
+ manager . set ( "nested" , { foo : "bar" } ) ;
89
92
await manager . flush ( ) ;
90
93
expect ( metadataUpdates ) . toHaveLength ( 1 ) ;
91
94
92
95
// Same nested value
93
- manager . setKey ( "nested" , { foo : "bar" } ) ;
96
+ manager . set ( "nested" , { foo : "bar" } ) ;
94
97
await manager . flush ( ) ;
95
98
// Should not trigger another update
96
99
expect ( metadataUpdates ) . toHaveLength ( 1 ) ;
97
100
98
101
// Different nested value
99
- manager . setKey ( "nested" , { foo : "baz" } ) ;
102
+ manager . set ( "nested" , { foo : "baz" } ) ;
100
103
await manager . flush ( ) ;
101
104
// Should trigger new update
102
105
expect ( metadataUpdates ) . toHaveLength ( 2 ) ;
103
106
} ) ;
104
107
105
108
test ( "should append to list with simple key" , ( ) => {
106
109
// First append creates the array
107
- manager . appendKey ( "myList" , "first" ) ;
110
+ manager . append ( "myList" , "first" ) ;
108
111
expect ( manager . getKey ( "myList" ) ) . toEqual ( [ "first" ] ) ;
109
112
110
113
// Second append adds to existing array
111
- manager . appendKey ( "myList" , "second" ) ;
114
+ manager . append ( "myList" , "second" ) ;
112
115
expect ( manager . getKey ( "myList" ) ) . toEqual ( [ "first" , "second" ] ) ;
113
116
} ) ;
114
117
115
118
test ( "should append to list with JSON path" , ( ) => {
116
119
// First create nested structure
117
- manager . setKey ( "nested" , { items : [ ] } ) ;
120
+ manager . set ( "nested" , { items : [ ] } ) ;
118
121
119
122
// Append to empty array
120
- manager . appendKey ( "$.nested.items" , "first" ) ;
123
+ manager . append ( "$.nested.items" , "first" ) ;
121
124
expect ( manager . current ( ) ) . toEqual ( {
122
125
nested : {
123
126
items : [ "first" ] ,
124
127
} ,
125
128
} ) ;
126
129
127
130
// Append another item
128
- manager . appendKey ( "$.nested.items" , "second" ) ;
131
+ manager . append ( "$.nested.items" , "second" ) ;
129
132
expect ( manager . current ( ) ) . toEqual ( {
130
133
nested : {
131
134
items : [ "first" , "second" ] ,
@@ -135,19 +138,19 @@ describe("StandardMetadataManager", () => {
135
138
136
139
test ( "should convert non-array values to array when appending" , ( ) => {
137
140
// Set initial non-array value
138
- manager . setKey ( "value" , "initial" ) ;
141
+ manager . set ( "value" , "initial" ) ;
139
142
140
143
// Append should convert to array
141
- manager . appendKey ( "value" , "second" ) ;
144
+ manager . append ( "value" , "second" ) ;
142
145
expect ( manager . getKey ( "value" ) ) . toEqual ( [ "initial" , "second" ] ) ;
143
146
} ) ;
144
147
145
148
test ( "should convert non-array values to array when appending with JSON path" , ( ) => {
146
149
// Set initial nested non-array value
147
- manager . setKey ( "nested" , { value : "initial" } ) ;
150
+ manager . set ( "nested" , { value : "initial" } ) ;
148
151
149
152
// Append should convert to array
150
- manager . appendKey ( "$.nested.value" , "second" ) ;
153
+ manager . append ( "$.nested.value" , "second" ) ;
151
154
expect ( manager . current ( ) ) . toEqual ( {
152
155
nested : {
153
156
value : [ "initial" , "second" ] ,
@@ -156,70 +159,60 @@ describe("StandardMetadataManager", () => {
156
159
} ) ;
157
160
158
161
test ( "should trigger server update when appending to list" , async ( ) => {
159
- manager . appendKey ( "myList" , "first" ) ;
162
+ manager . append ( "myList" , "first" ) ;
160
163
await manager . flush ( ) ;
161
164
162
165
expect ( metadataUpdates ) . toHaveLength ( 1 ) ;
163
- expect ( metadataUpdates [ 0 ] ) . toEqual ( {
164
- metadata : {
165
- myList : [ "first" ] ,
166
- } ,
167
- } ) ;
168
166
169
- manager . appendKey ( "myList" , "second" ) ;
167
+ manager . append ( "myList" , "second" ) ;
170
168
await manager . flush ( ) ;
171
169
172
170
expect ( metadataUpdates ) . toHaveLength ( 2 ) ;
173
- expect ( metadataUpdates [ 1 ] ) . toEqual ( {
174
- metadata : {
175
- myList : [ "first" , "second" ] ,
176
- } ,
177
- } ) ;
178
171
} ) ;
179
172
180
173
test ( "should not trigger server update when appending same value" , async ( ) => {
181
- manager . appendKey ( "myList" , "first" ) ;
174
+ manager . append ( "myList" , "first" ) ;
182
175
await manager . flush ( ) ;
183
176
184
177
expect ( metadataUpdates ) . toHaveLength ( 1 ) ;
185
178
186
179
// Append same value
187
- manager . appendKey ( "myList" , "first" ) ;
180
+ manager . append ( "myList" , "first" ) ;
188
181
await manager . flush ( ) ;
189
182
190
183
// Should still be only one update
191
184
expect ( metadataUpdates ) . toHaveLength ( 2 ) ;
192
185
} ) ;
193
186
194
187
test ( "should increment and decrement keys" , ( ) => {
195
- manager . incrementKey ( "counter" ) ;
188
+ manager . increment ( "counter" ) ;
196
189
expect ( manager . getKey ( "counter" ) ) . toBe ( 1 ) ;
197
190
198
- manager . incrementKey ( "counter" , 5 ) ;
191
+ manager . increment ( "counter" , 5 ) ;
199
192
expect ( manager . getKey ( "counter" ) ) . toBe ( 6 ) ;
200
193
201
- manager . decrementKey ( "counter" ) ;
194
+ manager . decrement ( "counter" ) ;
202
195
expect ( manager . getKey ( "counter" ) ) . toBe ( 5 ) ;
203
196
204
- manager . decrementKey ( "counter" , 3 ) ;
197
+ manager . decrement ( "counter" , 3 ) ;
205
198
expect ( manager . getKey ( "counter" ) ) . toBe ( 2 ) ;
206
199
} ) ;
207
200
208
201
test ( "should remove value from array with simple key" , ( ) => {
209
202
// Setup initial array
210
- manager . setKey ( "myList" , [ "first" , "second" , "third" ] ) ;
203
+ manager . set ( "myList" , [ "first" , "second" , "third" ] ) ;
211
204
212
205
// Remove a value
213
- manager . removeFromKey ( "myList" , "second" ) ;
206
+ manager . remove ( "myList" , "second" ) ;
214
207
expect ( manager . getKey ( "myList" ) ) . toEqual ( [ "first" , "third" ] ) ;
215
208
} ) ;
216
209
217
210
test ( "should remove value from array with JSON path" , ( ) => {
218
211
// Setup initial nested array
219
- manager . setKey ( "nested" , { items : [ "first" , "second" , "third" ] } ) ;
212
+ manager . set ( "nested" , { items : [ "first" , "second" , "third" ] } ) ;
220
213
221
214
// Remove a value
222
- manager . removeFromKey ( "$.nested.items" , "second" ) ;
215
+ manager . remove ( "$.nested.items" , "second" ) ;
223
216
expect ( manager . current ( ) ) . toEqual ( {
224
217
nested : {
225
218
items : [ "first" , "third" ] ,
@@ -229,32 +222,32 @@ describe("StandardMetadataManager", () => {
229
222
230
223
test ( "should handle removing non-existent value" , ( ) => {
231
224
// Setup initial array
232
- manager . setKey ( "myList" , [ "first" , "second" ] ) ;
225
+ manager . set ( "myList" , [ "first" , "second" ] ) ;
233
226
234
227
// Try to remove non-existent value
235
- manager . removeFromKey ( "myList" , "third" ) ;
228
+ manager . remove ( "myList" , "third" ) ;
236
229
expect ( manager . getKey ( "myList" ) ) . toEqual ( [ "first" , "second" ] ) ;
237
230
} ) ;
238
231
239
232
test ( "should handle removing from non-array values" , ( ) => {
240
233
// Setup non-array value
241
- manager . setKey ( "value" , "string" ) ;
234
+ manager . set ( "value" , "string" ) ;
242
235
243
236
// Try to remove from non-array
244
- manager . removeFromKey ( "value" , "something" ) ;
237
+ manager . remove ( "value" , "something" ) ;
245
238
expect ( manager . getKey ( "value" ) ) . toBe ( "string" ) ;
246
239
} ) ;
247
240
248
241
test ( "should remove object from array using deep equality" , ( ) => {
249
242
// Setup array with objects
250
- manager . setKey ( "objects" , [
243
+ manager . set ( "objects" , [
251
244
{ id : 1 , name : "first" } ,
252
245
{ id : 2 , name : "second" } ,
253
246
{ id : 3 , name : "third" } ,
254
247
] ) ;
255
248
256
249
// Remove object
257
- manager . removeFromKey ( "objects" , { id : 2 , name : "second" } ) ;
250
+ manager . remove ( "objects" , { id : 2 , name : "second" } ) ;
258
251
expect ( manager . getKey ( "objects" ) ) . toEqual ( [
259
252
{ id : 1 , name : "first" } ,
260
253
{ id : 3 , name : "third" } ,
@@ -263,30 +256,25 @@ describe("StandardMetadataManager", () => {
263
256
264
257
test ( "should trigger server update when removing from array" , async ( ) => {
265
258
// Setup initial array
266
- manager . setKey ( "myList" , [ "first" , "second" , "third" ] ) ;
259
+ manager . set ( "myList" , [ "first" , "second" , "third" ] ) ;
267
260
await manager . flush ( ) ;
268
261
expect ( metadataUpdates ) . toHaveLength ( 1 ) ;
269
262
270
263
// Remove value
271
- manager . removeFromKey ( "myList" , "second" ) ;
264
+ manager . remove ( "myList" , "second" ) ;
272
265
await manager . flush ( ) ;
273
266
274
267
expect ( metadataUpdates ) . toHaveLength ( 2 ) ;
275
- expect ( metadataUpdates [ 1 ] ) . toEqual ( {
276
- metadata : {
277
- myList : [ "first" , "third" ] ,
278
- } ,
279
- } ) ;
280
268
} ) ;
281
269
282
270
test ( "should not trigger server update when removing non-existent value" , async ( ) => {
283
271
// Setup initial array
284
- manager . setKey ( "myList" , [ "first" , "second" ] ) ;
272
+ manager . set ( "myList" , [ "first" , "second" ] ) ;
285
273
await manager . flush ( ) ;
286
274
expect ( metadataUpdates ) . toHaveLength ( 1 ) ;
287
275
288
276
// Try to remove non-existent value
289
- manager . removeFromKey ( "myList" , "third" ) ;
277
+ manager . remove ( "myList" , "third" ) ;
290
278
await manager . flush ( ) ;
291
279
292
280
// Should not trigger new update since nothing changed
0 commit comments