holosphere 1.1.2 → 1.1.3
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/holosphere.js +1054 -208
- package/package.json +2 -2
- package/test/federation.test.js +418 -0
- package/test/holosphere.test.js +686 -133
- package/test/spacesauth.test.js +337 -0
package/test/holosphere.test.js
CHANGED
|
@@ -2,15 +2,43 @@ import HoloSphere from '../holosphere.js';
|
|
|
2
2
|
import * as h3 from 'h3-js';
|
|
3
3
|
|
|
4
4
|
describe('HoloSphere', () => {
|
|
5
|
-
let holoSphere;
|
|
6
5
|
const testAppName = 'test-app';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
const testCredentials = {
|
|
7
|
+
spacename: 'testuser',
|
|
8
|
+
password: 'testpass'
|
|
9
|
+
};
|
|
10
|
+
let holoSphere = new HoloSphere(testAppName, false);
|
|
11
|
+
beforeAll(async () => {
|
|
12
|
+
// Initialize HoloSphere once for all tests
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// Set up test space and authenticate
|
|
16
|
+
try {
|
|
17
|
+
await holoSphere.createSpace(testCredentials.spacename, testCredentials.password);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
// Space might already exist, try to delete it first
|
|
20
|
+
try {
|
|
21
|
+
await holoSphere.deleteGlobal('spaces', testCredentials.spacename);
|
|
22
|
+
await holoSphere.createSpace(testCredentials.spacename, testCredentials.password);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error('Failed to recreate space:', error);
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Ensure we're logged in
|
|
30
|
+
await holoSphere.login(testCredentials.spacename, testCredentials.password);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
beforeEach(async () => {
|
|
34
|
+
// Ensure we're logged in before each test
|
|
35
|
+
if (!holoSphere.currentSpace || holoSphere.currentSpace.exp < Date.now()) {
|
|
36
|
+
await holoSphere.login(testCredentials.spacename, testCredentials.password);
|
|
37
|
+
}
|
|
10
38
|
});
|
|
11
39
|
|
|
12
40
|
describe('Constructor', () => {
|
|
13
|
-
test('should
|
|
41
|
+
test('should have initialized with correct properties', () => {
|
|
14
42
|
expect(holoSphere).toBeInstanceOf(HoloSphere);
|
|
15
43
|
expect(holoSphere.gun).toBeDefined();
|
|
16
44
|
expect(holoSphere.validator).toBeDefined();
|
|
@@ -20,6 +48,8 @@ describe('HoloSphere', () => {
|
|
|
20
48
|
test('should initialize with OpenAI when key provided', () => {
|
|
21
49
|
const hsWithAI = new HoloSphere(testAppName, false, 'fake-key');
|
|
22
50
|
expect(hsWithAI.openai).toBeDefined();
|
|
51
|
+
// Clean up additional instance
|
|
52
|
+
if (hsWithAI.gun) hsWithAI.gun.off();
|
|
23
53
|
});
|
|
24
54
|
});
|
|
25
55
|
|
|
@@ -34,25 +64,31 @@ describe('HoloSphere', () => {
|
|
|
34
64
|
required: ['id', 'data']
|
|
35
65
|
};
|
|
36
66
|
|
|
67
|
+
beforeEach(async () => {
|
|
68
|
+
// Ensure we're logged in before each schema test
|
|
69
|
+
if (!holoSphere.currentSpace || holoSphere.currentSpace.exp < Date.now()) {
|
|
70
|
+
await holoSphere.login(testCredentials.spacename, testCredentials.password);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
37
74
|
test('should set and get schema', async () => {
|
|
38
75
|
await holoSphere.setSchema(testLens, validSchema);
|
|
39
|
-
|
|
40
|
-
// Wait for GunDB to process
|
|
41
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
42
|
-
|
|
43
76
|
const retrievedSchema = await holoSphere.getSchema(testLens);
|
|
44
77
|
expect(retrievedSchema).toBeDefined();
|
|
45
78
|
expect(retrievedSchema).toEqual(validSchema);
|
|
46
|
-
}
|
|
79
|
+
});
|
|
47
80
|
|
|
48
81
|
test('should handle invalid schema parameters', async () => {
|
|
49
82
|
await expect(holoSphere.setSchema(null, null))
|
|
50
83
|
.rejects.toThrow('setSchema: Missing required parameters');
|
|
51
|
-
}
|
|
84
|
+
});
|
|
52
85
|
|
|
53
86
|
test('should enforce strict mode schema validation', async () => {
|
|
54
87
|
const strictHoloSphere = new HoloSphere(testAppName, true);
|
|
55
88
|
|
|
89
|
+
// Login to the strict instance
|
|
90
|
+
await strictHoloSphere.login(testCredentials.spacename, testCredentials.password);
|
|
91
|
+
|
|
56
92
|
const invalidSchema = {
|
|
57
93
|
type: 'object',
|
|
58
94
|
properties: {
|
|
@@ -62,30 +98,207 @@ describe('HoloSphere', () => {
|
|
|
62
98
|
|
|
63
99
|
await expect(strictHoloSphere.setSchema(testLens, invalidSchema))
|
|
64
100
|
.rejects.toThrow();
|
|
65
|
-
|
|
101
|
+
|
|
102
|
+
// Clean up
|
|
103
|
+
await strictHoloSphere.logout();
|
|
104
|
+
});
|
|
66
105
|
|
|
67
106
|
test('should handle schema retrieval for non-existent lens', async () => {
|
|
68
107
|
const result = await holoSphere.getSchema('nonexistent-lens');
|
|
69
108
|
expect(result).toBeNull();
|
|
70
109
|
});
|
|
71
110
|
|
|
111
|
+
test('should maintain schema integrity across storage and retrieval', async () => {
|
|
112
|
+
const testLens = 'schemaTestLens';
|
|
113
|
+
const strictHoloSphere = new HoloSphere(testAppName, true);
|
|
114
|
+
|
|
115
|
+
// Login to the strict instance
|
|
116
|
+
await strictHoloSphere.login(testCredentials.spacename, testCredentials.password);
|
|
117
|
+
|
|
118
|
+
// Create test schemas of increasing complexity
|
|
119
|
+
const testSchemas = [
|
|
120
|
+
{
|
|
121
|
+
type: 'object',
|
|
122
|
+
properties: {
|
|
123
|
+
id: { type: 'string' },
|
|
124
|
+
data: { type: 'string' }
|
|
125
|
+
},
|
|
126
|
+
required: ['id', 'data']
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
type: 'object',
|
|
130
|
+
properties: {
|
|
131
|
+
id: { type: 'string' },
|
|
132
|
+
data: { type: 'object' },
|
|
133
|
+
metadata: {
|
|
134
|
+
type: 'object',
|
|
135
|
+
properties: {
|
|
136
|
+
timestamp: { type: 'number' },
|
|
137
|
+
tags: {
|
|
138
|
+
type: 'array',
|
|
139
|
+
items: { type: 'string' }
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
required: ['id', 'data']
|
|
145
|
+
}
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
for (let i = 0; i < testSchemas.length; i++) {
|
|
149
|
+
const testLensWithIndex = `${testLens}_${i}`;
|
|
150
|
+
const schema = testSchemas[i];
|
|
151
|
+
|
|
152
|
+
// Store schema
|
|
153
|
+
await strictHoloSphere.setSchema(testLensWithIndex, schema);
|
|
154
|
+
|
|
155
|
+
// Add delay to ensure schema is stored
|
|
156
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
157
|
+
|
|
158
|
+
// Retrieve schema
|
|
159
|
+
const retrievedSchema = await strictHoloSphere.getSchema(testLensWithIndex);
|
|
160
|
+
|
|
161
|
+
// Verify schema is retrieved correctly
|
|
162
|
+
expect(retrievedSchema).toBeDefined();
|
|
163
|
+
expect(retrievedSchema).toEqual(schema);
|
|
164
|
+
|
|
165
|
+
// Test schema validation with valid data
|
|
166
|
+
const validData = {
|
|
167
|
+
id: 'test1',
|
|
168
|
+
data: i === 0 ? 'test' : { field: 'value' }
|
|
169
|
+
};
|
|
170
|
+
if (i === 1) {
|
|
171
|
+
validData.metadata = {
|
|
172
|
+
timestamp: Date.now(),
|
|
173
|
+
tags: ['test']
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Valid data should work
|
|
178
|
+
await expect(strictHoloSphere.put('testHolon', testLensWithIndex, validData))
|
|
179
|
+
.resolves.toBe(true);
|
|
180
|
+
|
|
181
|
+
// Invalid data should fail in strict mode
|
|
182
|
+
const invalidData = {
|
|
183
|
+
id: 'test2'
|
|
184
|
+
// Missing required 'data' field
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
await expect(strictHoloSphere.put('testHolon', testLensWithIndex, invalidData))
|
|
188
|
+
.rejects.toThrow('Schema validation failed');
|
|
189
|
+
|
|
190
|
+
// Clean up after each schema test
|
|
191
|
+
await strictHoloSphere.deleteAll('testHolon', testLensWithIndex);
|
|
192
|
+
await strictHoloSphere.gun.get(strictHoloSphere.appname)
|
|
193
|
+
.get(testLensWithIndex)
|
|
194
|
+
.get('schema')
|
|
195
|
+
.put(null);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Clean up the strict instance
|
|
199
|
+
if (strictHoloSphere.gun) {
|
|
200
|
+
await strictHoloSphere.logout();
|
|
201
|
+
await new Promise(resolve => setTimeout(resolve, 100)); // Allow time for cleanup
|
|
202
|
+
}
|
|
203
|
+
}, 10000); // Increase timeout to 10 seconds
|
|
204
|
+
|
|
205
|
+
test('should handle concurrent schema operations', async () => {
|
|
206
|
+
const baseLens = 'concurrentSchemaTest';
|
|
207
|
+
const numOperations = 5;
|
|
208
|
+
const promises = [];
|
|
209
|
+
const expectedSchemas = [];
|
|
210
|
+
|
|
211
|
+
// Create and store schemas concurrently
|
|
212
|
+
for (let i = 0; i < numOperations; i++) {
|
|
213
|
+
const lens = `${baseLens}_${i}`;
|
|
214
|
+
const schema = {
|
|
215
|
+
type: 'object',
|
|
216
|
+
properties: {
|
|
217
|
+
id: { type: 'string' },
|
|
218
|
+
value: { type: 'string' }
|
|
219
|
+
},
|
|
220
|
+
required: ['id', 'value']
|
|
221
|
+
};
|
|
222
|
+
expectedSchemas.push({ lens, schema });
|
|
223
|
+
// Add small delay between operations to prevent race conditions
|
|
224
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
225
|
+
promises.push(holoSphere.setSchema(lens, schema));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Wait for all operations to complete
|
|
229
|
+
await Promise.all(promises);
|
|
230
|
+
|
|
231
|
+
// Add delay before verification to ensure data is settled
|
|
232
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
233
|
+
|
|
234
|
+
// Verify each schema was stored correctly
|
|
235
|
+
for (const { lens, schema } of expectedSchemas) {
|
|
236
|
+
const retrievedSchema = await holoSphere.getSchema(lens);
|
|
237
|
+
expect(retrievedSchema).toEqual(schema);
|
|
238
|
+
}
|
|
239
|
+
}, 10000); // Increase timeout to 10 seconds
|
|
240
|
+
|
|
241
|
+
test('should handle schema updates correctly', async () => {
|
|
242
|
+
const testLens = 'schemaUpdateTest';
|
|
243
|
+
|
|
244
|
+
// Initial schema
|
|
245
|
+
const initialSchema = {
|
|
246
|
+
type: 'object',
|
|
247
|
+
properties: {
|
|
248
|
+
id: { type: 'string' },
|
|
249
|
+
data: { type: 'string' }
|
|
250
|
+
},
|
|
251
|
+
required: ['id']
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// Updated schema
|
|
255
|
+
const updatedSchema = {
|
|
256
|
+
type: 'object',
|
|
257
|
+
properties: {
|
|
258
|
+
id: { type: 'string' },
|
|
259
|
+
data: { type: 'string' },
|
|
260
|
+
metadata: { type: 'object' }
|
|
261
|
+
},
|
|
262
|
+
required: ['id', 'data']
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// Set initial schema
|
|
266
|
+
await holoSphere.setSchema(testLens, initialSchema);
|
|
267
|
+
|
|
268
|
+
// Verify initial schema
|
|
269
|
+
let retrievedSchema = await holoSphere.getSchema(testLens);
|
|
270
|
+
expect(retrievedSchema).toEqual(initialSchema);
|
|
271
|
+
|
|
272
|
+
// Update schema
|
|
273
|
+
await holoSphere.setSchema(testLens, updatedSchema);
|
|
274
|
+
|
|
275
|
+
// Verify updated schema
|
|
276
|
+
retrievedSchema = await holoSphere.getSchema(testLens);
|
|
277
|
+
expect(retrievedSchema).toEqual(updatedSchema);
|
|
278
|
+
});
|
|
279
|
+
|
|
72
280
|
afterEach(async () => {
|
|
73
281
|
// Clean up schemas after each test
|
|
74
282
|
await holoSphere.gun.get(holoSphere.appname)
|
|
75
283
|
.get(testLens)
|
|
76
284
|
.get('schema')
|
|
77
285
|
.put(null);
|
|
78
|
-
|
|
79
|
-
// Wait for GunDB to process
|
|
80
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
81
286
|
});
|
|
82
287
|
});
|
|
83
288
|
|
|
84
289
|
describe('Data Operations', () => {
|
|
85
290
|
const testHolon = h3.latLngToCell(40.7128, -74.0060, 7);
|
|
86
291
|
const testLens = 'testLens';
|
|
87
|
-
const validData = { id: '
|
|
292
|
+
const validData = { id: 'test1', data: 'test data' };
|
|
88
293
|
const invalidData = { id: 'test456', wrongField: 'wrong data' };
|
|
294
|
+
const expectedValidData = {
|
|
295
|
+
...validData,
|
|
296
|
+
owner: testCredentials.spacename,
|
|
297
|
+
federation: expect.objectContaining({
|
|
298
|
+
origin: testCredentials.spacename,
|
|
299
|
+
timestamp: expect.any(Number)
|
|
300
|
+
})
|
|
301
|
+
};
|
|
89
302
|
|
|
90
303
|
beforeEach(async () => {
|
|
91
304
|
// Set up schema for validation tests
|
|
@@ -93,7 +306,8 @@ describe('HoloSphere', () => {
|
|
|
93
306
|
type: 'object',
|
|
94
307
|
properties: {
|
|
95
308
|
id: { type: 'string' },
|
|
96
|
-
data: { type: 'string' }
|
|
309
|
+
data: { type: 'string' },
|
|
310
|
+
owner: { type: 'string' }
|
|
97
311
|
},
|
|
98
312
|
required: ['id', 'data']
|
|
99
313
|
};
|
|
@@ -101,20 +315,22 @@ describe('HoloSphere', () => {
|
|
|
101
315
|
});
|
|
102
316
|
|
|
103
317
|
test('should put and get data with schema validation', async () => {
|
|
104
|
-
const validData = { id: 'test1', data: 'test data' };
|
|
105
|
-
const invalidData = { id: 'test2' }; // Missing required 'data' field
|
|
106
|
-
|
|
107
318
|
// Test valid data
|
|
108
|
-
await holoSphere.put(testHolon, testLens, validData)
|
|
319
|
+
await expect(holoSphere.put(testHolon, testLens, validData))
|
|
320
|
+
.resolves.toBe(true);
|
|
109
321
|
|
|
110
322
|
// Test invalid data
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
323
|
+
await expect(holoSphere.put(testHolon, testLens, invalidData))
|
|
324
|
+
.rejects.toThrow('Schema validation failed');
|
|
325
|
+
|
|
326
|
+
// Verify the valid data was stored correctly
|
|
327
|
+
const result = await holoSphere.get(testHolon, testLens, validData.id);
|
|
328
|
+
expect(result).toEqual(expect.objectContaining(expectedValidData));
|
|
329
|
+
|
|
330
|
+
// Verify the invalid data was not stored
|
|
331
|
+
const invalidResult = await holoSphere.get(testHolon, testLens, invalidData.id);
|
|
332
|
+
expect(invalidResult).toBeNull();
|
|
333
|
+
});
|
|
118
334
|
|
|
119
335
|
test('should get all data with schema validation', async () => {
|
|
120
336
|
await holoSphere.put(testHolon, testLens, validData);
|
|
@@ -124,7 +340,7 @@ describe('HoloSphere', () => {
|
|
|
124
340
|
expect(Array.isArray(results)).toBeTruthy();
|
|
125
341
|
expect(results.length).toBeGreaterThan(0);
|
|
126
342
|
expect(results.some(item => item.id === validData.id)).toBeTruthy();
|
|
127
|
-
}
|
|
343
|
+
});
|
|
128
344
|
|
|
129
345
|
test('should delete data', async () => {
|
|
130
346
|
await holoSphere.put(testHolon, testLens, validData);
|
|
@@ -132,7 +348,7 @@ describe('HoloSphere', () => {
|
|
|
132
348
|
|
|
133
349
|
const result = await holoSphere.get(testHolon, testLens, validData.id);
|
|
134
350
|
expect(result).toBeNull();
|
|
135
|
-
}
|
|
351
|
+
});
|
|
136
352
|
|
|
137
353
|
test('should delete all data', async () => {
|
|
138
354
|
await holoSphere.put(testHolon, testLens, validData);
|
|
@@ -143,11 +359,14 @@ describe('HoloSphere', () => {
|
|
|
143
359
|
|
|
144
360
|
const results = await holoSphere.getAll(testHolon, testLens);
|
|
145
361
|
expect(results).toEqual([]);
|
|
146
|
-
}
|
|
362
|
+
});
|
|
147
363
|
|
|
148
364
|
test('should enforce strict mode data validation', async () => {
|
|
149
365
|
const strictHoloSphere = new HoloSphere(testAppName, true);
|
|
150
366
|
|
|
367
|
+
// Login to the strict instance
|
|
368
|
+
await strictHoloSphere.login(testCredentials.spacename, testCredentials.password);
|
|
369
|
+
|
|
151
370
|
// Define schema for strict mode tests
|
|
152
371
|
const strictSchema = {
|
|
153
372
|
type: 'object',
|
|
@@ -164,7 +383,172 @@ describe('HoloSphere', () => {
|
|
|
164
383
|
// Try to put data without schema in strict mode
|
|
165
384
|
await expect(strictHoloSphere.put(testHolon, 'no-schema-lens', validData))
|
|
166
385
|
.rejects.toThrow('Schema required in strict mode');
|
|
167
|
-
|
|
386
|
+
|
|
387
|
+
// Clean up
|
|
388
|
+
await strictHoloSphere.logout();
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
test('should maintain content integrity in holon storage', async () => {
|
|
392
|
+
const testData = [
|
|
393
|
+
{ id: 'test1', data: 'content1' },
|
|
394
|
+
{ id: 'test2', data: 'content2' },
|
|
395
|
+
{ id: 'test3', data: 'content3' }
|
|
396
|
+
];
|
|
397
|
+
|
|
398
|
+
const expectedData = testData.map(data => ({
|
|
399
|
+
...data,
|
|
400
|
+
owner: testCredentials.spacename,
|
|
401
|
+
federation: expect.objectContaining({
|
|
402
|
+
origin: testCredentials.spacename,
|
|
403
|
+
timestamp: expect.any(Number)
|
|
404
|
+
})
|
|
405
|
+
}));
|
|
406
|
+
|
|
407
|
+
// Store all test data
|
|
408
|
+
for (const data of testData) {
|
|
409
|
+
await holoSphere.put(testHolon, testLens, data);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Retrieve all data
|
|
413
|
+
const retrievedData = await holoSphere.getAll(testHolon, testLens);
|
|
414
|
+
|
|
415
|
+
// Sort both arrays by id for comparison
|
|
416
|
+
const sortedExpectedData = [...expectedData].sort((a, b) => a.id.localeCompare(b.id));
|
|
417
|
+
const sortedRetrievedData = [...retrievedData].sort((a, b) => a.id.localeCompare(b.id));
|
|
418
|
+
|
|
419
|
+
// Verify no duplicates
|
|
420
|
+
const uniqueIds = new Set(retrievedData.map(item => item.id));
|
|
421
|
+
expect(uniqueIds.size).toBe(testData.length);
|
|
422
|
+
|
|
423
|
+
// Verify all items are present and correct
|
|
424
|
+
expect(sortedRetrievedData).toEqual(expect.arrayContaining(sortedExpectedData));
|
|
425
|
+
|
|
426
|
+
// Verify individual item retrieval
|
|
427
|
+
for (let i = 0; i < testData.length; i++) {
|
|
428
|
+
const item = await holoSphere.get(testHolon, testLens, testData[i].id);
|
|
429
|
+
expect(item).toEqual(expect.objectContaining(expectedData[i]));
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test('should handle data consistency in get operations', async () => {
|
|
434
|
+
const testData = [
|
|
435
|
+
{ id: 'test1', data: 'content1' },
|
|
436
|
+
{ id: 'test2', data: 'content2' },
|
|
437
|
+
{ id: 'test3', data: 'content3' }
|
|
438
|
+
].map(data => ({
|
|
439
|
+
...data,
|
|
440
|
+
owner: testCredentials.spacename,
|
|
441
|
+
federation: expect.objectContaining({
|
|
442
|
+
origin: testCredentials.spacename,
|
|
443
|
+
timestamp: expect.any(Number)
|
|
444
|
+
})
|
|
445
|
+
}));
|
|
446
|
+
|
|
447
|
+
// Store test data
|
|
448
|
+
for (const data of testData) {
|
|
449
|
+
const { federation, ...storeData } = data;
|
|
450
|
+
await holoSphere.put(testHolon, testLens, storeData);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Test individual get operations
|
|
454
|
+
for (const expected of testData) {
|
|
455
|
+
const result = await holoSphere.get(testHolon, testLens, expected.id);
|
|
456
|
+
expect(result).toEqual(expect.objectContaining(expected));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Multiple consecutive gets should return same data
|
|
460
|
+
for (let i = 0; i < 5; i++) {
|
|
461
|
+
const result = await holoSphere.get(testHolon, testLens, 'test1');
|
|
462
|
+
expect(result).toEqual(expect.objectContaining(testData[0]));
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
test('should handle data consistency in getAll operations', async () => {
|
|
467
|
+
const testData = Array.from({ length: 10 }, (_, i) => ({
|
|
468
|
+
id: `test${i}`,
|
|
469
|
+
data: `content${i}`,
|
|
470
|
+
owner: testCredentials.spacename,
|
|
471
|
+
federation: expect.objectContaining({
|
|
472
|
+
origin: testCredentials.spacename,
|
|
473
|
+
timestamp: expect.any(Number)
|
|
474
|
+
})
|
|
475
|
+
}));
|
|
476
|
+
|
|
477
|
+
// Store test data sequentially to ensure consistency
|
|
478
|
+
for (const data of testData) {
|
|
479
|
+
const { federation, ...storeData } = data;
|
|
480
|
+
await holoSphere.put(testHolon, testLens, storeData);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Wait a bit to ensure data is settled
|
|
484
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
485
|
+
|
|
486
|
+
// Get data multiple times
|
|
487
|
+
const results = await Promise.all(
|
|
488
|
+
Array.from({ length: 5 }, () => holoSphere.getAll(testHolon, testLens))
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
// Verify results
|
|
492
|
+
results.forEach(result => {
|
|
493
|
+
// Should have correct length
|
|
494
|
+
expect(result.length).toBe(testData.length);
|
|
495
|
+
|
|
496
|
+
// Should have no duplicates
|
|
497
|
+
const ids = result.map(item => item.id);
|
|
498
|
+
const uniqueIds = new Set(ids);
|
|
499
|
+
expect(uniqueIds.size).toBe(testData.length);
|
|
500
|
+
|
|
501
|
+
// Should contain all expected data
|
|
502
|
+
const sortedResult = [...result].sort((a, b) => a.id.localeCompare(b.id));
|
|
503
|
+
const sortedExpected = [...testData].sort((a, b) => a.id.localeCompare(b.id));
|
|
504
|
+
sortedResult.forEach((item, idx) => {
|
|
505
|
+
expect(item).toEqual(expect.objectContaining(sortedExpected[idx]));
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
}, 15000);
|
|
509
|
+
|
|
510
|
+
test('should handle rapid concurrent getAll operations', async () => {
|
|
511
|
+
const testData = Array.from({ length: 5 }, (_, i) => ({
|
|
512
|
+
id: `concurrent${i}`,
|
|
513
|
+
data: `data${i}`
|
|
514
|
+
}));
|
|
515
|
+
|
|
516
|
+
// Store test data
|
|
517
|
+
for (const data of testData) {
|
|
518
|
+
await holoSphere.put(testHolon, testLens, data);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Perform multiple concurrent getAll operations
|
|
522
|
+
const promises = Array.from({ length: 10 }, () =>
|
|
523
|
+
holoSphere.getAll(testHolon, testLens)
|
|
524
|
+
);
|
|
525
|
+
|
|
526
|
+
const results = await Promise.all(promises);
|
|
527
|
+
|
|
528
|
+
// Verify each result has the correct number of items
|
|
529
|
+
results.forEach(result => {
|
|
530
|
+
expect(result.length).toBe(testData.length);
|
|
531
|
+
|
|
532
|
+
// Check for duplicates within each result
|
|
533
|
+
const ids = result.map(item => item.id);
|
|
534
|
+
const uniqueIds = new Set(ids);
|
|
535
|
+
expect(uniqueIds.size).toBe(ids.length);
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// Verify consistency across results
|
|
539
|
+
const sortedResults = results.map(result =>
|
|
540
|
+
[...result].sort((a, b) => a.id.localeCompare(b.id))
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
for (let i = 1; i < sortedResults.length; i++) {
|
|
544
|
+
expect(sortedResults[i]).toEqual(sortedResults[0]);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
// Add cleanup after each test
|
|
549
|
+
afterEach(async () => {
|
|
550
|
+
await holoSphere.deleteAll(testHolon, testLens);
|
|
551
|
+
});
|
|
168
552
|
});
|
|
169
553
|
|
|
170
554
|
describe('Node Operations', () => {
|
|
@@ -175,18 +559,14 @@ describe('HoloSphere', () => {
|
|
|
175
559
|
test('should put and get node', async () => {
|
|
176
560
|
await holoSphere.putNode(testHolon, testLens, testNode);
|
|
177
561
|
|
|
178
|
-
// Wait for GunDB to process
|
|
179
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
180
|
-
|
|
181
562
|
const result = await holoSphere.getNode(testHolon, testLens, 'value');
|
|
182
563
|
expect(result).toBeDefined();
|
|
183
564
|
expect(result).toBe('test node data');
|
|
184
|
-
}
|
|
565
|
+
});
|
|
185
566
|
|
|
186
567
|
test('should delete node', async () => {
|
|
187
568
|
// First put the node
|
|
188
569
|
await holoSphere.putNode(testHolon, testLens, testNode);
|
|
189
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
190
570
|
|
|
191
571
|
// Verify node exists
|
|
192
572
|
const beforeDelete = await holoSphere.getNode(testHolon, testLens, 'value');
|
|
@@ -196,23 +576,19 @@ describe('HoloSphere', () => {
|
|
|
196
576
|
const deleteResult = await holoSphere.deleteNode(testHolon, testLens, 'value');
|
|
197
577
|
expect(deleteResult).toBe(true);
|
|
198
578
|
|
|
199
|
-
// Wait for deletion to process
|
|
200
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
201
|
-
|
|
202
579
|
// Verify node is deleted
|
|
203
580
|
const afterDelete = await holoSphere.getNode(testHolon, testLens, 'value');
|
|
204
581
|
expect(afterDelete).toBeNull();
|
|
205
|
-
}
|
|
582
|
+
});
|
|
206
583
|
|
|
207
584
|
test('should handle invalid node operations', async () => {
|
|
208
585
|
await expect(holoSphere.deleteNode(null, null, null))
|
|
209
586
|
.rejects.toThrow('deleteNode: Missing required parameters');
|
|
210
|
-
}
|
|
587
|
+
});
|
|
211
588
|
|
|
212
589
|
afterEach(async () => {
|
|
213
590
|
// Clean up after each test
|
|
214
591
|
await holoSphere.deleteNode(testHolon, testLens, 'value');
|
|
215
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
216
592
|
});
|
|
217
593
|
});
|
|
218
594
|
|
|
@@ -246,74 +622,144 @@ describe('HoloSphere', () => {
|
|
|
246
622
|
const testLens = 'testLens';
|
|
247
623
|
|
|
248
624
|
beforeEach(async () => {
|
|
249
|
-
// Clear any existing subscriptions and data
|
|
250
|
-
holoSphere.cleanup();
|
|
251
625
|
await holoSphere.deleteAll(testHolon, testLens);
|
|
252
|
-
// Wait for cleanup to complete
|
|
253
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
254
626
|
});
|
|
255
627
|
|
|
256
|
-
test('should
|
|
257
|
-
const
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
628
|
+
test('should receive data through subscription', async () => {
|
|
629
|
+
const testData = { id: 'test1', data: 'test data' };
|
|
630
|
+
const expectedData = {
|
|
631
|
+
...testData,
|
|
632
|
+
owner: testCredentials.spacename,
|
|
633
|
+
federation: expect.objectContaining({
|
|
634
|
+
origin: testCredentials.spacename,
|
|
635
|
+
timestamp: expect.any(Number)
|
|
636
|
+
})
|
|
637
|
+
};
|
|
638
|
+
let received = false;
|
|
639
|
+
|
|
640
|
+
return new Promise((resolve, reject) => {
|
|
641
|
+
const timeout = setTimeout(() => {
|
|
642
|
+
reject(new Error('Subscription timeout'));
|
|
643
|
+
}, 20000);
|
|
644
|
+
|
|
645
|
+
holoSphere.subscribe(testHolon, testLens, (data) => {
|
|
646
|
+
if (!received && data.id === testData.id) {
|
|
647
|
+
try {
|
|
648
|
+
received = true;
|
|
649
|
+
expect(data).toEqual(expect.objectContaining(expectedData));
|
|
650
|
+
clearTimeout(timeout);
|
|
651
|
+
resolve();
|
|
652
|
+
} catch (error) {
|
|
653
|
+
clearTimeout(timeout);
|
|
654
|
+
reject(error);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
});
|
|
261
658
|
|
|
262
|
-
|
|
263
|
-
|
|
659
|
+
// Put data after subscription
|
|
660
|
+
setTimeout(async () => {
|
|
661
|
+
try {
|
|
662
|
+
await holoSphere.put(testHolon, testLens, testData);
|
|
663
|
+
} catch (error) {
|
|
664
|
+
clearTimeout(timeout);
|
|
665
|
+
reject(error);
|
|
666
|
+
}
|
|
667
|
+
}, 1000);
|
|
668
|
+
});
|
|
669
|
+
}, 30000);
|
|
670
|
+
|
|
671
|
+
test('should stop receiving data after unsubscribe', async () => {
|
|
672
|
+
const testData1 = { id: 'test1', data: 'first' };
|
|
673
|
+
const testData2 = { id: 'test2', data: 'second' };
|
|
674
|
+
let received = false;
|
|
675
|
+
|
|
676
|
+
const subscription = await holoSphere.subscribe(testHolon, testLens, async (data) => {
|
|
677
|
+
if (!received && data.id === testData1.id) {
|
|
678
|
+
received = true;
|
|
679
|
+
await subscription.off();
|
|
680
|
+
|
|
681
|
+
// Put second piece of data after unsubscribe
|
|
682
|
+
await holoSphere.put(testHolon, testLens, testData2);
|
|
683
|
+
|
|
684
|
+
// Wait a bit to ensure no more data is received
|
|
685
|
+
setTimeout(() => {
|
|
686
|
+
expect(received).toBe(true);
|
|
687
|
+
}, 1000);
|
|
688
|
+
} else if (data.id === testData2.id) {
|
|
689
|
+
throw new Error('Received data after unsubscribe');
|
|
690
|
+
}
|
|
691
|
+
});
|
|
264
692
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
// Wait longer for subscription to process
|
|
268
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
269
|
-
|
|
270
|
-
expect(changes.length).toBeGreaterThan(0);
|
|
693
|
+
// Put first piece of data
|
|
694
|
+
await holoSphere.put(testHolon, testLens, testData1);
|
|
271
695
|
}, 10000);
|
|
272
696
|
|
|
273
|
-
test('should
|
|
274
|
-
const
|
|
275
|
-
|
|
697
|
+
test('should handle multiple subscriptions', async () => {
|
|
698
|
+
const testData = { id: 'test1', data: 'test data' };
|
|
699
|
+
const expectedData = {
|
|
700
|
+
...testData,
|
|
701
|
+
owner: testCredentials.spacename,
|
|
702
|
+
federation: expect.objectContaining({
|
|
703
|
+
origin: testCredentials.spacename,
|
|
704
|
+
timestamp: expect.any(Number)
|
|
705
|
+
})
|
|
706
|
+
};
|
|
707
|
+
let received1 = false;
|
|
708
|
+
let received2 = false;
|
|
709
|
+
|
|
710
|
+
return new Promise((resolve, reject) => {
|
|
711
|
+
const timeout = setTimeout(() => {
|
|
712
|
+
reject(new Error('Subscription timeout'));
|
|
713
|
+
}, 20000);
|
|
714
|
+
|
|
715
|
+
function checkDone() {
|
|
716
|
+
if (received1 && received2) {
|
|
717
|
+
clearTimeout(timeout);
|
|
718
|
+
resolve();
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
holoSphere.subscribe(testHolon, testLens, (data) => {
|
|
723
|
+
if (data.id === testData.id) {
|
|
724
|
+
try {
|
|
725
|
+
received1 = true;
|
|
726
|
+
expect(data).toEqual(expect.objectContaining(expectedData));
|
|
727
|
+
checkDone();
|
|
728
|
+
} catch (error) {
|
|
729
|
+
clearTimeout(timeout);
|
|
730
|
+
reject(error);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
});
|
|
276
734
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
735
|
+
holoSphere.subscribe(testHolon, testLens, (data) => {
|
|
736
|
+
if (data.id === testData.id) {
|
|
737
|
+
try {
|
|
738
|
+
received2 = true;
|
|
739
|
+
expect(data).toEqual(expect.objectContaining(expectedData));
|
|
740
|
+
checkDone();
|
|
741
|
+
} catch (error) {
|
|
742
|
+
clearTimeout(timeout);
|
|
743
|
+
reject(error);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
282
746
|
});
|
|
747
|
+
|
|
748
|
+
// Put data after both subscriptions
|
|
749
|
+
setTimeout(async () => {
|
|
750
|
+
try {
|
|
751
|
+
await holoSphere.put(testHolon, testLens, testData);
|
|
752
|
+
} catch (error) {
|
|
753
|
+
clearTimeout(timeout);
|
|
754
|
+
reject(error);
|
|
755
|
+
}
|
|
756
|
+
}, 1000);
|
|
283
757
|
});
|
|
758
|
+
}, 30000);
|
|
284
759
|
|
|
285
|
-
|
|
286
|
-
await holoSphere.
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
// Clear changes and unsubscribe
|
|
290
|
-
changes.length = 0;
|
|
291
|
-
subscription.unsubscribe();
|
|
292
|
-
|
|
293
|
-
// Wait longer for unsubscribe to take effect
|
|
294
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
295
|
-
|
|
296
|
-
// Put new data
|
|
297
|
-
await holoSphere.put(testHolon, testLens, { id: 'test2', data: 'new data' });
|
|
298
|
-
|
|
299
|
-
// Wait to ensure no new changes are received
|
|
300
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
301
|
-
|
|
302
|
-
expect(changes.length).toBe(0);
|
|
303
|
-
}, 20000);
|
|
304
|
-
|
|
305
|
-
test('should cleanup all subscriptions', async () => {
|
|
306
|
-
const subs = [];
|
|
307
|
-
for (let i = 0; i < 3; i++) {
|
|
308
|
-
subs.push(await holoSphere.subscribe(testHolon, testLens, () => {}));
|
|
309
|
-
// Wait between subscriptions
|
|
310
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
expect(holoSphere.subscriptions.size).toBe(3);
|
|
314
|
-
holoSphere.cleanup();
|
|
315
|
-
expect(holoSphere.subscriptions.size).toBe(0);
|
|
316
|
-
}, 10000);
|
|
760
|
+
afterEach(async () => {
|
|
761
|
+
await holoSphere.deleteAll(testHolon, testLens);
|
|
762
|
+
});
|
|
317
763
|
});
|
|
318
764
|
|
|
319
765
|
describe('Parse Operations', () => {
|
|
@@ -350,6 +796,84 @@ describe('HoloSphere', () => {
|
|
|
350
796
|
expect(Array.isArray(results)).toBe(true);
|
|
351
797
|
expect(results.length).toBeGreaterThan(0);
|
|
352
798
|
});
|
|
799
|
+
|
|
800
|
+
test('should maintain content integrity in global storage', async () => {
|
|
801
|
+
const testTable = 'testGlobalTable';
|
|
802
|
+
|
|
803
|
+
// Create test data with unique IDs and content
|
|
804
|
+
const testData = [
|
|
805
|
+
{ id: 'global1', value: 'value1' },
|
|
806
|
+
{ id: 'global2', value: 'value2' },
|
|
807
|
+
{ id: 'global3', value: 'value3' }
|
|
808
|
+
];
|
|
809
|
+
|
|
810
|
+
// Store all test data
|
|
811
|
+
for (const data of testData) {
|
|
812
|
+
await holoSphere.putGlobal(testTable, data);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// Retrieve all data
|
|
816
|
+
const retrievedData = await holoSphere.getAllGlobal(testTable);
|
|
817
|
+
|
|
818
|
+
// Sort both arrays by id for comparison
|
|
819
|
+
const sortedTestData = [...testData].sort((a, b) => a.id.localeCompare(b.id));
|
|
820
|
+
const sortedRetrievedData = [...retrievedData].sort((a, b) => a.id.localeCompare(b.id));
|
|
821
|
+
|
|
822
|
+
// Verify no duplicates
|
|
823
|
+
const uniqueIds = new Set(retrievedData.map(item => item.id));
|
|
824
|
+
expect(uniqueIds.size).toBe(testData.length);
|
|
825
|
+
|
|
826
|
+
// Verify all items are present and correct
|
|
827
|
+
expect(sortedRetrievedData).toEqual(sortedTestData);
|
|
828
|
+
|
|
829
|
+
// Verify individual item retrieval
|
|
830
|
+
for (const data of testData) {
|
|
831
|
+
const item = await holoSphere.getGlobal(testTable, data.id);
|
|
832
|
+
expect(item).toEqual(data);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Clean up test data
|
|
836
|
+
await holoSphere.deleteAllGlobal(testTable);
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
test('should handle concurrent global operations without data corruption', async () => {
|
|
840
|
+
const testTable = 'concurrentGlobalTest';
|
|
841
|
+
const numOperations = 5;
|
|
842
|
+
const promises = [];
|
|
843
|
+
const expectedData = [];
|
|
844
|
+
|
|
845
|
+
// Create and store data concurrently with small delays
|
|
846
|
+
for (let i = 0; i < numOperations; i++) {
|
|
847
|
+
const data = { id: `concurrent${i}`, value: `value${i}` };
|
|
848
|
+
expectedData.push(data);
|
|
849
|
+
// Add small delay between operations
|
|
850
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
851
|
+
promises.push(holoSphere.putGlobal(testTable, data));
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// Wait for all operations to complete
|
|
855
|
+
await Promise.all(promises);
|
|
856
|
+
|
|
857
|
+
// Add delay before verification
|
|
858
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
859
|
+
|
|
860
|
+
// Retrieve and verify data
|
|
861
|
+
const retrievedData = await holoSphere.getAllGlobal(testTable);
|
|
862
|
+
|
|
863
|
+
// Sort both arrays by id for comparison
|
|
864
|
+
const sortedExpectedData = [...expectedData].sort((a, b) => a.id.localeCompare(b.id));
|
|
865
|
+
const sortedRetrievedData = [...retrievedData].sort((a, b) => a.id.localeCompare(b.id));
|
|
866
|
+
|
|
867
|
+
// Verify no duplicates
|
|
868
|
+
const uniqueIds = new Set(retrievedData.map(item => item.id));
|
|
869
|
+
expect(uniqueIds.size).toBe(numOperations);
|
|
870
|
+
|
|
871
|
+
// Verify all items are present and correct
|
|
872
|
+
expect(sortedRetrievedData).toEqual(sortedExpectedData);
|
|
873
|
+
|
|
874
|
+
// Clean up test data
|
|
875
|
+
await holoSphere.deleteAllGlobal(testTable);
|
|
876
|
+
}, 15000); // Increase timeout to 15 seconds
|
|
353
877
|
});
|
|
354
878
|
|
|
355
879
|
describe('Compute Operations', () => {
|
|
@@ -363,34 +887,55 @@ describe('HoloSphere', () => {
|
|
|
363
887
|
properties: {
|
|
364
888
|
id: { type: 'string' },
|
|
365
889
|
content: { type: 'string' },
|
|
366
|
-
|
|
890
|
+
timestamp: { type: 'number' }
|
|
367
891
|
},
|
|
368
|
-
required: ['id', '
|
|
892
|
+
required: ['id', 'content']
|
|
369
893
|
};
|
|
370
894
|
await holoSphere.setSchema(testLens, schema);
|
|
371
895
|
});
|
|
372
896
|
|
|
373
|
-
test('should validate
|
|
374
|
-
await expect(holoSphere.compute(null, null))
|
|
897
|
+
test('should validate required parameters', async () => {
|
|
898
|
+
await expect(holoSphere.compute(null, null, null))
|
|
899
|
+
.rejects.toThrow('compute: Missing required parameters');
|
|
900
|
+
|
|
901
|
+
await expect(holoSphere.compute(testHolon, null, null))
|
|
902
|
+
.rejects.toThrow('compute: Missing required parameters');
|
|
903
|
+
|
|
904
|
+
await expect(holoSphere.compute(testHolon, testLens, null))
|
|
375
905
|
.rejects.toThrow('compute: Missing required parameters');
|
|
376
906
|
});
|
|
377
907
|
|
|
908
|
+
|
|
378
909
|
test('should validate holon resolution', async () => {
|
|
379
|
-
const invalidHolon =
|
|
380
|
-
await expect(holoSphere.compute(invalidHolon,
|
|
381
|
-
.rejects.toThrow('compute: Invalid holon resolution');
|
|
910
|
+
const invalidHolon = h3.latLngToCell(40.7128, -74.0060, 0); // Resolution 0
|
|
911
|
+
await expect(holoSphere.compute(invalidHolon, testLens, 'summarize'))
|
|
912
|
+
.rejects.toThrow('compute: Invalid holon resolution (must be between 1 and 15)');
|
|
382
913
|
});
|
|
383
914
|
|
|
384
|
-
test('should
|
|
385
|
-
await holoSphere.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
await expect(holoSphere.compute(testHolon, testLens, 'summarize'))
|
|
392
|
-
.
|
|
393
|
-
}
|
|
915
|
+
test('should validate depth parameters', async () => {
|
|
916
|
+
await expect(holoSphere.compute(testHolon, testLens, 'summarize', -1))
|
|
917
|
+
.rejects.toThrow('compute: Invalid depth parameter');
|
|
918
|
+
|
|
919
|
+
await expect(holoSphere.compute(testHolon, testLens, 'summarize', 0, 0))
|
|
920
|
+
.rejects.toThrow('compute: Invalid maxDepth parameter (must be between 1 and 15)');
|
|
921
|
+
|
|
922
|
+
await expect(holoSphere.compute(testHolon, testLens, 'summarize', 0, 16))
|
|
923
|
+
.rejects.toThrow('compute: Invalid maxDepth parameter (must be between 1 and 15)');
|
|
924
|
+
});
|
|
925
|
+
|
|
926
|
+
test('should validate operation type', async () => {
|
|
927
|
+
await expect(holoSphere.compute(testHolon, testLens, 'invalid-operation'))
|
|
928
|
+
.rejects.toThrow('compute: Invalid operation (must be "summarize")');
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
afterEach(async () => {
|
|
932
|
+
// Clean up test data
|
|
933
|
+
await holoSphere.deleteAll(testHolon, testLens);
|
|
934
|
+
await holoSphere.gun.get(holoSphere.appname)
|
|
935
|
+
.get(testLens)
|
|
936
|
+
.get('schema')
|
|
937
|
+
.put(null);
|
|
938
|
+
});
|
|
394
939
|
});
|
|
395
940
|
|
|
396
941
|
describe('Error Handling', () => {
|
|
@@ -400,7 +945,6 @@ describe('HoloSphere', () => {
|
|
|
400
945
|
beforeEach(async () => {
|
|
401
946
|
// Clear all existing data
|
|
402
947
|
await holoSphere.deleteAll(testHolon, testLens);
|
|
403
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
404
948
|
|
|
405
949
|
// Set up fresh schema
|
|
406
950
|
const schema = {
|
|
@@ -412,7 +956,6 @@ describe('HoloSphere', () => {
|
|
|
412
956
|
required: ['id', 'data']
|
|
413
957
|
};
|
|
414
958
|
await holoSphere.setSchema(testLens, schema);
|
|
415
|
-
await new Promise(resolve => setTimeout(resolve, 500));
|
|
416
959
|
});
|
|
417
960
|
|
|
418
961
|
test('should handle concurrent operations', async () => {
|
|
@@ -420,10 +963,12 @@ describe('HoloSphere', () => {
|
|
|
420
963
|
const promises = [];
|
|
421
964
|
const expectedIds = new Set();
|
|
422
965
|
|
|
423
|
-
// Create concurrent put operations
|
|
966
|
+
// Create concurrent put operations with small delays between them
|
|
424
967
|
for (let i = 0; i < numOperations; i++) {
|
|
425
968
|
const id = `concurrent${i}`;
|
|
426
969
|
expectedIds.add(id);
|
|
970
|
+
// Add small delay between operations to prevent race conditions
|
|
971
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
427
972
|
promises.push(holoSphere.put(testHolon, testLens, {
|
|
428
973
|
id: id,
|
|
429
974
|
data: 'test'
|
|
@@ -432,7 +977,9 @@ describe('HoloSphere', () => {
|
|
|
432
977
|
|
|
433
978
|
// Wait for all operations to complete
|
|
434
979
|
await Promise.all(promises);
|
|
435
|
-
|
|
980
|
+
|
|
981
|
+
// Add delay before verification to ensure data is settled
|
|
982
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
436
983
|
|
|
437
984
|
// Get and verify results
|
|
438
985
|
const results = await holoSphere.getAll(testHolon, testLens);
|
|
@@ -445,7 +992,7 @@ describe('HoloSphere', () => {
|
|
|
445
992
|
expectedIds.forEach(id => {
|
|
446
993
|
expect(resultIds.has(id)).toBe(true);
|
|
447
994
|
});
|
|
448
|
-
},
|
|
995
|
+
}, 15000); // Increase timeout to 15 seconds
|
|
449
996
|
|
|
450
997
|
test('should handle large data sets', async () => {
|
|
451
998
|
const largeData = {
|
|
@@ -456,9 +1003,6 @@ describe('HoloSphere', () => {
|
|
|
456
1003
|
// Put the data
|
|
457
1004
|
await holoSphere.put(testHolon, testLens, largeData);
|
|
458
1005
|
|
|
459
|
-
// Wait for data to be stored
|
|
460
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
461
|
-
|
|
462
1006
|
// Get the data back
|
|
463
1007
|
const result = await holoSphere.get(testHolon, testLens, 'large');
|
|
464
1008
|
|
|
@@ -466,12 +1010,11 @@ describe('HoloSphere', () => {
|
|
|
466
1010
|
expect(result).toBeDefined();
|
|
467
1011
|
expect(result.id).toBe(largeData.id);
|
|
468
1012
|
expect(result.data).toBe(largeData.data);
|
|
469
|
-
}
|
|
1013
|
+
});
|
|
470
1014
|
|
|
471
1015
|
afterEach(async () => {
|
|
472
1016
|
// Clean up after each test
|
|
473
1017
|
await holoSphere.deleteAll(testHolon, testLens);
|
|
474
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
475
1018
|
});
|
|
476
1019
|
});
|
|
477
1020
|
|
|
@@ -492,11 +1035,21 @@ describe('HoloSphere', () => {
|
|
|
492
1035
|
|
|
493
1036
|
afterAll(async () => {
|
|
494
1037
|
// Clean up test data
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
await
|
|
1038
|
+
const testLens = 'testLens';
|
|
1039
|
+
const testHolon = h3.latLngToCell(40.7128, -74.0060, 7);
|
|
1040
|
+
await holoSphere.deleteAll(testHolon, testLens);
|
|
1041
|
+
|
|
1042
|
+
// Clean up test tables
|
|
1043
|
+
await holoSphere.deleteAllGlobal('testTable');
|
|
1044
|
+
await holoSphere.deleteAllGlobal('testGlobalTable');
|
|
1045
|
+
await holoSphere.deleteAllGlobal('concurrentGlobalTest');
|
|
1046
|
+
|
|
1047
|
+
// Clean up test space
|
|
1048
|
+
await holoSphere.deleteGlobal('spaces', testCredentials.spacename);
|
|
1049
|
+
|
|
1050
|
+
// Logout
|
|
1051
|
+
if (holoSphere.currentSpace) {
|
|
1052
|
+
await holoSphere.logout();
|
|
1053
|
+
}
|
|
501
1054
|
});
|
|
502
1055
|
});
|