2025-10-08 14:08:43 -07:00
|
|
|
|
/**
|
|
|
|
|
|
* GCS Native Storage Adapter Integration Tests
|
|
|
|
|
|
*
|
|
|
|
|
|
* This test verifies that the GCS native adapter:
|
|
|
|
|
|
* - Properly authenticates with ADC and service accounts
|
|
|
|
|
|
* - Implements UUID-based sharding correctly
|
|
|
|
|
|
* - Handles pagination across shards
|
|
|
|
|
|
* - Persists data correctly
|
|
|
|
|
|
* - Manages statistics and counts
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
|
|
|
|
import { GcsStorage } from '../../src/storage/adapters/gcsStorage.js'
|
|
|
|
|
|
import { randomUUID } from 'node:crypto'
|
|
|
|
|
|
|
|
|
|
|
|
describe('GCS Native Storage Adapter', () => {
|
|
|
|
|
|
// Mock GCS client for testing
|
|
|
|
|
|
let mockGcsObjects: Map<string, any> = new Map()
|
|
|
|
|
|
let storage: GcsStorage | null = null
|
|
|
|
|
|
|
|
|
|
|
|
// Helper to create mock GCS client
|
|
|
|
|
|
function createMockGcsClient() {
|
|
|
|
|
|
const mockBucket = {
|
|
|
|
|
|
exists: async () => [true],
|
|
|
|
|
|
|
|
|
|
|
|
file: (name: string) => ({
|
|
|
|
|
|
save: async (data: string, options: any) => {
|
|
|
|
|
|
mockGcsObjects.set(name, JSON.parse(data))
|
|
|
|
|
|
return {}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
download: async () => {
|
|
|
|
|
|
const data = mockGcsObjects.get(name)
|
|
|
|
|
|
if (!data) {
|
|
|
|
|
|
const error: any = new Error('Not found')
|
|
|
|
|
|
error.code = 404
|
|
|
|
|
|
throw error
|
|
|
|
|
|
}
|
|
|
|
|
|
return [Buffer.from(JSON.stringify(data))]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
delete: async () => {
|
|
|
|
|
|
mockGcsObjects.delete(name)
|
|
|
|
|
|
return [{}]
|
|
|
|
|
|
}
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
|
|
|
|
getFiles: async (options: any) => {
|
|
|
|
|
|
const prefix = options.prefix || ''
|
|
|
|
|
|
const maxResults = options.maxResults || 1000
|
|
|
|
|
|
const pageToken = options.pageToken
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`[Mock GCS] getFiles: Prefix="${prefix}", maxResults=${maxResults}`)
|
|
|
|
|
|
|
|
|
|
|
|
// Filter objects by prefix
|
|
|
|
|
|
const allKeys = Array.from(mockGcsObjects.keys())
|
|
|
|
|
|
const matchingKeys = allKeys.filter(key => key.startsWith(prefix)).sort()
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`[Mock GCS] Total keys=${allKeys.length}, Matching=${matchingKeys.length}`)
|
|
|
|
|
|
if (matchingKeys.length > 0) {
|
|
|
|
|
|
console.log(`[Mock GCS] First match: ${matchingKeys[0]}`)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Apply pagination
|
|
|
|
|
|
let startIndex = 0
|
|
|
|
|
|
if (pageToken) {
|
|
|
|
|
|
startIndex = parseInt(pageToken)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const endIndex = Math.min(startIndex + maxResults, matchingKeys.length)
|
|
|
|
|
|
const pageKeys = matchingKeys.slice(startIndex, endIndex)
|
|
|
|
|
|
|
|
|
|
|
|
const files = pageKeys.map(key => ({
|
|
|
|
|
|
name: key
|
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
const response = {
|
|
|
|
|
|
nextPageToken: endIndex < matchingKeys.length ? String(endIndex) : undefined
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return [files, {}, response]
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
getMetadata: async () => [{
|
|
|
|
|
|
location: 'us-central1',
|
|
|
|
|
|
storageClass: 'STANDARD',
|
|
|
|
|
|
timeCreated: new Date().toISOString()
|
|
|
|
|
|
}]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
bucket: (name: string) => mockBucket
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
|
mockGcsObjects.clear()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
afterEach(async () => {
|
|
|
|
|
|
if (storage) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await storage.clear()
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
// Ignore cleanup errors
|
|
|
|
|
|
}
|
|
|
|
|
|
storage = null
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should initialize with Application Default Credentials (ADC)', async () => {
|
|
|
|
|
|
// Create storage without any credentials (ADC)
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
// Verify initialization
|
|
|
|
|
|
expect((storage as any).bucketName).toBe('test-bucket')
|
|
|
|
|
|
expect((storage as any).keyFilename).toBeUndefined()
|
|
|
|
|
|
expect((storage as any).credentials).toBeUndefined()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should initialize with service account key file', async () => {
|
|
|
|
|
|
// Create storage with key file
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket',
|
|
|
|
|
|
keyFilename: '/path/to/service-account.json'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
// Verify initialization
|
|
|
|
|
|
expect((storage as any).keyFilename).toBe('/path/to/service-account.json')
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should write and read data with UUID-based sharding', async () => {
|
|
|
|
|
|
console.log('\n📝 Test: Write and read with UUID sharding...')
|
|
|
|
|
|
|
|
|
|
|
|
// Create storage
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
// Generate UUIDs for testing
|
|
|
|
|
|
const testData = [
|
|
|
|
|
|
{ id: randomUUID(), vector: [0.1, 0.2, 0.3], metadata: { type: 'user', name: 'Alice' } },
|
|
|
|
|
|
{ id: randomUUID(), vector: [0.4, 0.5, 0.6], metadata: { type: 'user', name: 'Bob' } },
|
|
|
|
|
|
{ id: randomUUID(), vector: [0.7, 0.8, 0.9], metadata: { type: 'user', name: 'Charlie' } }
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
// Save nouns with metadata
|
|
|
|
|
|
for (const item of testData) {
|
|
|
|
|
|
const noun = {
|
|
|
|
|
|
id: item.id,
|
|
|
|
|
|
vector: item.vector,
|
|
|
|
|
|
connections: new Map(),
|
|
|
|
|
|
layer: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
await storage.saveNoun(noun)
|
|
|
|
|
|
await (storage as any).saveNounMetadata_internal(item.id, item.metadata)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`✅ Wrote ${testData.length} entities`)
|
|
|
|
|
|
console.log(`📊 Objects in mock storage: ${mockGcsObjects.size}`)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify data was written to UUID-sharded paths
|
|
|
|
|
|
const shardedKeys = Array.from(mockGcsObjects.keys()).filter(k =>
|
|
|
|
|
|
k.match(/entities\/nouns\/vectors\/[0-9a-f]{2}\//)
|
|
|
|
|
|
)
|
|
|
|
|
|
console.log(`🔑 UUID-sharded keys: ${shardedKeys.length}`)
|
|
|
|
|
|
expect(shardedKeys.length).toBe(testData.length)
|
|
|
|
|
|
|
|
|
|
|
|
// Log shard distribution
|
|
|
|
|
|
const shards = new Set(shardedKeys.map(k => k.match(/entities\/nouns\/vectors\/([0-9a-f]{2})\//)?.[1]))
|
|
|
|
|
|
console.log(`📁 Data distributed across ${shards.size} shards: ${Array.from(shards).join(', ')}`)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify each entity can be retrieved
|
|
|
|
|
|
for (const item of testData) {
|
|
|
|
|
|
const noun = await storage.getNoun(item.id)
|
|
|
|
|
|
expect(noun).toBeTruthy()
|
|
|
|
|
|
expect(noun!.id).toBe(item.id)
|
|
|
|
|
|
expect(noun!.vector).toEqual(item.vector)
|
|
|
|
|
|
|
|
|
|
|
|
const metadata = await storage.getNounMetadata(item.id)
|
|
|
|
|
|
expect(metadata).toBeTruthy()
|
|
|
|
|
|
expect(metadata.name).toBe(item.metadata.name)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log('✅ All entities retrieved successfully')
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should handle pagination across UUID shards', async () => {
|
|
|
|
|
|
console.log('\n🔄 Test: Pagination across shards...')
|
|
|
|
|
|
|
|
|
|
|
|
// Create storage
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
// Write 10 entities with proper UUIDs
|
|
|
|
|
|
console.log('📝 Writing 10 entities...')
|
|
|
|
|
|
for (let i = 0; i < 10; i++) {
|
|
|
|
|
|
const id = randomUUID()
|
|
|
|
|
|
const noun = {
|
|
|
|
|
|
id,
|
|
|
|
|
|
vector: [0.1 * i, 0.2 * i, 0.3 * i],
|
|
|
|
|
|
connections: new Map(),
|
|
|
|
|
|
layer: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
await storage.saveNoun(noun)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Read with pagination (limit: 3)
|
|
|
|
|
|
console.log('\n🔄 Reading with pagination (limit: 3)...')
|
|
|
|
|
|
|
|
|
|
|
|
let allEntities: any[] = []
|
|
|
|
|
|
let cursor: string | undefined
|
|
|
|
|
|
let page = 0
|
|
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
const result = await storage.getNounsWithPagination({
|
|
|
|
|
|
limit: 3,
|
|
|
|
|
|
cursor
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
page++
|
|
|
|
|
|
console.log(`📄 Page ${page}: ${result.items.length} entities, hasMore: ${result.hasMore}`)
|
|
|
|
|
|
|
|
|
|
|
|
allEntities.push(...result.items)
|
|
|
|
|
|
cursor = result.nextCursor
|
|
|
|
|
|
|
|
|
|
|
|
// Safety check to prevent infinite loops
|
|
|
|
|
|
expect(page).toBeLessThan(20)
|
|
|
|
|
|
} while (cursor)
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`✅ Loaded ${allEntities.length} total entities across ${page} pages`)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify all entities were loaded
|
|
|
|
|
|
expect(allEntities.length).toBe(10)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should return correct totalCount on first call', async () => {
|
|
|
|
|
|
console.log('\n📊 Test: Correct totalCount...')
|
|
|
|
|
|
|
|
|
|
|
|
// Create storage
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
// Write 5 entities
|
|
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
|
|
|
|
await storage.saveNoun({
|
|
|
|
|
|
id: randomUUID(),
|
|
|
|
|
|
vector: [0.1, 0.2, 0.3],
|
|
|
|
|
|
connections: new Map(),
|
|
|
|
|
|
layer: 0
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get first page
|
|
|
|
|
|
const result = await storage.getNounsWithPagination({ limit: 2 })
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`📊 First page: ${result.items.length} items`)
|
|
|
|
|
|
|
|
|
|
|
|
expect(result.items.length).toBeLessThanOrEqual(2)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should handle verb operations with UUID sharding', async () => {
|
|
|
|
|
|
console.log('\n🔗 Test: Verb operations with UUID sharding...')
|
|
|
|
|
|
|
|
|
|
|
|
// Create storage
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
// Create verb
|
|
|
|
|
|
const verbId = randomUUID()
|
|
|
|
|
|
const verb = {
|
|
|
|
|
|
id: verbId,
|
|
|
|
|
|
vector: [0.1, 0.2, 0.3],
|
|
|
|
|
|
connections: new Map()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await storage.saveVerb(verb)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify verb was saved with UUID sharding
|
|
|
|
|
|
const shardedKeys = Array.from(mockGcsObjects.keys()).filter(k =>
|
|
|
|
|
|
k.match(/entities\/verbs\/vectors\/[0-9a-f]{2}\//)
|
|
|
|
|
|
)
|
|
|
|
|
|
expect(shardedKeys.length).toBeGreaterThan(0)
|
|
|
|
|
|
|
|
|
|
|
|
// Retrieve verb
|
|
|
|
|
|
const retrieved = await storage.getVerb(verbId)
|
|
|
|
|
|
expect(retrieved).toBeTruthy()
|
|
|
|
|
|
expect(retrieved!.id).toBe(verbId)
|
|
|
|
|
|
|
|
|
|
|
|
console.log('✅ Verb operations successful')
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should handle metadata sharding correctly', async () => {
|
|
|
|
|
|
console.log('\n🗂️ Test: Metadata sharding...')
|
|
|
|
|
|
|
|
|
|
|
|
// Create storage
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
// Create noun with metadata
|
|
|
|
|
|
const nounId = randomUUID()
|
|
|
|
|
|
const noun = {
|
|
|
|
|
|
id: nounId,
|
|
|
|
|
|
vector: [0.1, 0.2, 0.3],
|
|
|
|
|
|
connections: new Map(),
|
|
|
|
|
|
layer: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
const metadata = {
|
|
|
|
|
|
type: 'user',
|
|
|
|
|
|
name: 'Test User',
|
|
|
|
|
|
email: 'test@example.com'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await storage.saveNoun(noun)
|
|
|
|
|
|
await (storage as any).saveNounMetadata_internal(nounId, metadata)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify metadata was saved with UUID sharding
|
|
|
|
|
|
const metadataKeys = Array.from(mockGcsObjects.keys()).filter(k =>
|
|
|
|
|
|
k.match(/entities\/nouns\/metadata\/[0-9a-f]{2}\//)
|
|
|
|
|
|
)
|
|
|
|
|
|
expect(metadataKeys.length).toBeGreaterThan(0)
|
|
|
|
|
|
|
|
|
|
|
|
// Retrieve metadata
|
|
|
|
|
|
const retrieved = await storage.getNounMetadata(nounId)
|
|
|
|
|
|
expect(retrieved).toBeTruthy()
|
|
|
|
|
|
expect(retrieved.name).toBe('Test User')
|
|
|
|
|
|
|
|
|
|
|
|
console.log('✅ Metadata sharding successful')
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should clear all data correctly', async () => {
|
|
|
|
|
|
console.log('\n🧹 Test: Clear all data...')
|
|
|
|
|
|
|
|
|
|
|
|
// Create storage
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
// Write some data
|
|
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
|
|
|
|
await storage.saveNoun({
|
|
|
|
|
|
id: randomUUID(),
|
|
|
|
|
|
vector: [0.1, 0.2, 0.3],
|
|
|
|
|
|
connections: new Map(),
|
|
|
|
|
|
layer: 0
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`📊 Objects before clear: ${mockGcsObjects.size}`)
|
|
|
|
|
|
|
|
|
|
|
|
// Clear all data
|
|
|
|
|
|
await storage.clear()
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`📊 Objects after clear: ${mockGcsObjects.size}`)
|
|
|
|
|
|
|
|
|
|
|
|
expect(mockGcsObjects.size).toBe(0)
|
|
|
|
|
|
console.log('✅ Clear successful')
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should handle throttling errors correctly', async () => {
|
|
|
|
|
|
console.log('\n🚦 Test: Throttling detection...')
|
|
|
|
|
|
|
|
|
|
|
|
// Create storage
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Test throttling error detection
|
|
|
|
|
|
const throttlingError = { code: 429, message: 'Too Many Requests' }
|
|
|
|
|
|
expect((storage as any).isThrottlingError(throttlingError)).toBe(true)
|
|
|
|
|
|
|
|
|
|
|
|
const quotaError = { code: 403, message: 'Quota exceeded' }
|
|
|
|
|
|
expect((storage as any).isThrottlingError(quotaError)).toBe(true)
|
|
|
|
|
|
|
|
|
|
|
|
const normalError = { code: 500, message: 'Internal Server Error' }
|
|
|
|
|
|
expect((storage as any).isThrottlingError(normalError)).toBe(false)
|
|
|
|
|
|
|
|
|
|
|
|
console.log('✅ Throttling detection working')
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should manage statistics correctly', async () => {
|
|
|
|
|
|
console.log('\n📊 Test: Statistics management...')
|
|
|
|
|
|
|
|
|
|
|
|
// Create storage
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
// Create statistics
|
|
|
|
|
|
const stats = {
|
|
|
|
|
|
nounCount: { 'test-service': 5 },
|
|
|
|
|
|
verbCount: { 'test-service': 3 },
|
|
|
|
|
|
metadataCount: {},
|
|
|
|
|
|
hnswIndexSize: 100,
|
|
|
|
|
|
lastUpdated: new Date().toISOString()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Save statistics
|
|
|
|
|
|
await (storage as any).saveStatisticsData(stats)
|
|
|
|
|
|
|
|
|
|
|
|
// Verify statistics key was created
|
|
|
|
|
|
const statsKeys = Array.from(mockGcsObjects.keys()).filter(k =>
|
|
|
|
|
|
k.includes('_system/statistics.json')
|
|
|
|
|
|
)
|
|
|
|
|
|
expect(statsKeys.length).toBe(1)
|
|
|
|
|
|
|
|
|
|
|
|
// Retrieve statistics
|
|
|
|
|
|
const retrieved = await (storage as any).getStatisticsData()
|
|
|
|
|
|
expect(retrieved).toBeTruthy()
|
|
|
|
|
|
expect(retrieved.nounCount['test-service']).toBe(5)
|
|
|
|
|
|
|
|
|
|
|
|
console.log('✅ Statistics management successful')
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
it('should get storage status', async () => {
|
|
|
|
|
|
console.log('\n📊 Test: Storage status...')
|
|
|
|
|
|
|
|
|
|
|
|
// Create storage
|
|
|
|
|
|
storage = new GcsStorage({
|
|
|
|
|
|
bucketName: 'test-bucket'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// Mock the GCS client
|
|
|
|
|
|
;(storage as any).storage = createMockGcsClient()
|
|
|
|
|
|
;(storage as any).bucket = (storage as any).storage.bucket('test-bucket')
|
|
|
|
|
|
;(storage as any).isInitialized = true
|
|
|
|
|
|
|
|
|
|
|
|
const status = await storage.getStorageStatus()
|
|
|
|
|
|
|
2025-10-20 11:11:54 -07:00
|
|
|
|
expect(status.type).toBe('gcs') // Changed from 'gcs-native' to 'gcs'
|
2025-10-08 14:08:43 -07:00
|
|
|
|
expect(status.details).toBeTruthy()
|
|
|
|
|
|
expect(status.details!.bucket).toBe('test-bucket')
|
2025-10-20 11:11:54 -07:00
|
|
|
|
expect(status.details!.sdk).toBe('native') // Verify we're using native SDK
|
2025-10-08 14:08:43 -07:00
|
|
|
|
|
|
|
|
|
|
console.log('✅ Storage status retrieved:', status)
|
|
|
|
|
|
})
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
console.log('\n✅ GCS Native Storage Tests Complete')
|