Skip to main content
Glama
real-data-correctness.test.js11 kB
/** * Real Data Accuracy Tests * * Validates that indexed data accurately reflects source data: * - Field mapping correctness * - Data transformation accuracy * - Embedding quality */ import { describe, it, expect, beforeAll } from 'vitest' import fs from 'fs' import { execSync } from 'child_process' import { checkDataSources, buildProductionIndex, isProductionIndexReady, searchProductionIndex, embed, MAIL_DIR, MESSAGES_DB, CALENDAR_DB, PRODUCTION_INDEX_DIR } from '../helpers/real-data.js' const sources = checkDataSources() describe.skipIf(!sources.mail && !sources.messages && !sources.calendar || !sources.productionIndex)( 'Real Data Accuracy', () => { beforeAll(async () => { // Production index must already exist - tests only validate, don't build const ready = await isProductionIndexReady() if (!ready) { throw new Error( 'Production index not found or empty. ' + 'Run "npm run rebuild-index" to build it first.' ) } }, 60000) describe.skipIf(!sources.mail)('Email Field Correctness', () => { it('should have valid filePath pointing to real .emlx file', async () => { const results = await searchProductionIndex('email', 'emails', 10) for (const email of results) { expect(email.filePath).toBeTruthy() expect(email.filePath).toMatch(/\.emlx$/) expect(email.filePath).toContain(MAIL_DIR) // Verify file exists (sample a few) if (results.indexOf(email) < 3) { expect(fs.existsSync(email.filePath)).toBe(true) } } }, 60000) it('should have valid email addresses in from field', async () => { const results = await searchProductionIndex('from', 'emails', 10) for (const email of results) { // from should be a string (may contain name + email or just email) expect(typeof email.from).toBe('string') } }, 30000) it('should have fromEmail in email format', async () => { const results = await searchProductionIndex('test', 'emails', 10) for (const email of results) { if (email.fromEmail) { expect(email.fromEmail).toMatch(/.*@.*/) } } }, 30000) it('should have numeric dateTimestamp', async () => { const results = await searchProductionIndex('meeting', 'emails', 10) for (const email of results) { expect(typeof email.dateTimestamp).toBe('number') expect(email.dateTimestamp).toBeGreaterThan(0) // Should be reasonable (after year 2000, before year 2100) const year2000 = new Date('2000-01-01').getTime() const year2100 = new Date('2100-01-01').getTime() expect(email.dateTimestamp).toBeGreaterThan(year2000) expect(email.dateTimestamp).toBeLessThan(year2100) } }, 30000) it('should have 384-dim vector embeddings', async () => { const results = await searchProductionIndex('hello', 'emails', 5) for (const email of results) { expect(email.vector).toBeDefined() expect(email.vector).toHaveLength(384) const vectorArray = Array.from(email.vector) expect(Number.isFinite(vectorArray[0])).toBe(true) } }, 30000) it('should have mailbox extracted from path', async () => { const results = await searchProductionIndex('inbox', 'emails', 5) for (const email of results) { expect(email.mailbox).toBeTruthy() expect(typeof email.mailbox).toBe('string') } }, 30000) }) describe.skipIf(!sources.messages)('Message Field Correctness', () => { it('should have valid message id', async () => { const results = await searchProductionIndex('hello', 'messages', 10) for (const msg of results) { expect(msg.id).toBeTruthy() expect(typeof msg.id).toBe('string') } }, 30000) it('should have text content', async () => { const results = await searchProductionIndex('meeting', 'messages', 10) for (const msg of results) { expect(msg.text).toBeTruthy() expect(typeof msg.text).toBe('string') expect(msg.text.length).toBeGreaterThan(0) } }, 30000) it('should have valid dateTimestamp', async () => { const results = await searchProductionIndex('hi', 'messages', 10) for (const msg of results) { expect(typeof msg.dateTimestamp).toBe('number') expect(msg.dateTimestamp).toBeGreaterThan(0) } }, 30000) it('should have sender information', async () => { const results = await searchProductionIndex('text', 'messages', 10) for (const msg of results) { expect(msg.sender).toBeTruthy() // Sender is either "Me" or a phone/email identifier expect(typeof msg.sender).toBe('string') } }, 30000) it('should have 384-dim vector embeddings', async () => { const results = await searchProductionIndex('message', 'messages', 5) for (const msg of results) { expect(msg.vector).toBeDefined() expect(msg.vector).toHaveLength(384) const vectorArray = Array.from(msg.vector) expect(Number.isFinite(vectorArray[0])).toBe(true) } }, 30000) }) describe.skipIf(!sources.calendar)('Calendar Field Correctness', () => { it('should have valid event id', async () => { const results = await searchProductionIndex('meeting', 'calendar', 10) for (const event of results) { expect(event.id).toBeTruthy() expect(typeof event.id).toBe('string') } }, 30000) it('should have event title', async () => { const results = await searchProductionIndex('appointment', 'calendar', 10) for (const event of results) { expect(event.title).toBeTruthy() expect(typeof event.title).toBe('string') } }, 30000) it('should have start and end timestamps', async () => { const results = await searchProductionIndex('event', 'calendar', 10) for (const event of results) { expect(typeof event.startTimestamp).toBe('number') expect(event.startTimestamp).toBeGreaterThan(0) } }, 30000) it('should have calendar name', async () => { const results = await searchProductionIndex('calendar', 'calendar', 10) for (const event of results) { expect(event.calendar).toBeTruthy() expect(typeof event.calendar).toBe('string') } }, 30000) it('should have 384-dim vector embeddings', async () => { const results = await searchProductionIndex('schedule', 'calendar', 5) for (const event of results) { expect(event.vector).toBeDefined() expect(event.vector).toHaveLength(384) const vectorArray = Array.from(event.vector) expect(Number.isFinite(vectorArray[0])).toBe(true) } }, 30000) }) } ) describe('Embedding Accuracy', () => { it('should produce consistent embeddings for same text', async () => { const text = 'Important meeting about quarterly review' const vec1 = await embed(text) const vec2 = await embed(text) // Same text should produce identical vectors expect(vec1).toHaveLength(384) expect(vec2).toHaveLength(384) // Compare first few elements (floating point comparison) for (let i = 0; i < 10; i++) { expect(Math.abs(vec1[i] - vec2[i])).toBeLessThan(1e-6) } }, 30000) it('should produce normalized vectors (unit length)', async () => { const text = 'Test email about project updates' const vector = await embed(text) // Calculate magnitude let magnitude = 0 for (const v of vector) { magnitude += v * v } magnitude = Math.sqrt(magnitude) // Normalized vectors should have magnitude ~1 expect(magnitude).toBeCloseTo(1, 3) }, 30000) it('should capture semantic similarity', async () => { // Similar texts const text1 = 'Schedule a team meeting for next Tuesday' const text2 = 'Set up a group meeting for Tuesday next week' // Unrelated text const text3 = 'Recipe for chocolate cake with frosting' const vec1 = await embed(text1) const vec2 = await embed(text2) const vec3 = await embed(text3) // Calculate cosine similarities const cosineSim = (a, b) => { let dot = 0, norm1 = 0, norm2 = 0 for (let i = 0; i < a.length; i++) { dot += a[i] * b[i] norm1 += a[i] * a[i] norm2 += b[i] * b[i] } return dot / (Math.sqrt(norm1) * Math.sqrt(norm2)) } const simSimilar = cosineSim(vec1, vec2) const simUnrelated = cosineSim(vec1, vec3) // Similar texts should have higher similarity expect(simSimilar).toBeGreaterThan(simUnrelated) expect(simSimilar).toBeGreaterThan(0.7) expect(simUnrelated).toBeLessThan(0.5) }, 30000) }) describe.skipIf(!sources.messages)('Message Database Accuracy', () => { it('should match message count with database', async () => { // Get count from production index const lancedb = await import('@lancedb/lancedb') const db = await lancedb.connect(PRODUCTION_INDEX_DIR) const tables = await db.tableNames() if (!tables.includes('messages')) { return // Skip if not indexed } const table = await db.openTable('messages') const indexedCount = await table.countRows() // Get count from database (with text) try { const dbCount = execSync( `sqlite3 "${MESSAGES_DB}" "SELECT COUNT(*) FROM message WHERE text IS NOT NULL AND text != ''"`, { encoding: 'utf-8' } ) const actualCount = parseInt(dbCount.trim()) // Indexed count should be reasonable compared to actual // (may differ due to filtering, limits, etc.) expect(indexedCount).toBeGreaterThan(0) console.log(`Messages: ${indexedCount} indexed / ${actualCount} in database`) } catch (e) { console.warn('Could not verify message count:', e.message) } }, 30000) }) describe.skipIf(!sources.mail)('Email Source Accuracy', () => { it('should verify indexed email matches source file', async () => { const results = await searchProductionIndex('test', 'emails', 1) if (results.length === 0) return const email = results[0] // Read source file if (fs.existsSync(email.filePath)) { const content = fs.readFileSync(email.filePath, 'utf-8') // Subject from index should appear in source file if (email.subject) { // Subject might be encoded, so just check it's reasonable expect(typeof email.subject).toBe('string') } // From should appear in source if (email.from) { expect(typeof email.from).toBe('string') } } }, 30000) })

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sfls1397/Apple-Tools-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server