Files
oai-swift/oAITests/DatabaseServiceTests.swift
T
rune f3c6271c9e Phase 4 tests: DatabaseService migrations + ContextSelectionService DB paths
17 tests against throwaway in-memory DatabaseService instances: all
v1-v8 tables/columns exist post-migration, settings CRUD, conversation
save/load round-trip, instance isolation between separate in-memory
queues, and ContextSelectionService's DB-coupled paths (starring,
excluded-range summaries, smartSelection end to end) that were
previously untestable.
2026-07-24 09:16:46 +02:00

124 lines
4.6 KiB
Swift

//
// DatabaseServiceTests.swift
// oAITests
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen
import Testing
import Foundation
@testable import oAI
@Suite("DatabaseService migrations, against a throwaway in-memory queue")
struct DatabaseServiceMigrationTests {
@Test("All v1-v8 tables exist after migration")
func allTablesExist() {
let db = DatabaseService.makeInMemory()
let expectedTables = [
"conversations", "messages", "settings", "command_history",
"email_logs", "message_metadata", "message_embeddings",
"conversation_embeddings", "conversation_summaries",
]
for table in expectedTables {
#expect(db.tableExists(table), "expected table \(table) to exist")
}
}
@Test("v4 adds modelId to messages and primaryModel to conversations")
func v4AddsModelColumns() {
let db = DatabaseService.makeInMemory()
#expect(db.columnNames(in: "messages").contains("modelId"))
#expect(db.columnNames(in: "conversations").contains("primaryModel"))
}
@Test("messages table has the expected v1 columns")
func messagesTableColumns() {
let db = DatabaseService.makeInMemory()
let columns = Set(db.columnNames(in: "messages"))
let expected: Set<String> = ["id", "conversationId", "role", "content", "tokens", "cost", "timestamp", "sortOrder"]
#expect(expected.isSubset(of: columns))
}
@Test("message_metadata table has the expected v6 columns")
func messageMetadataColumns() {
let db = DatabaseService.makeInMemory()
let columns = Set(db.columnNames(in: "message_metadata"))
#expect(columns == ["message_id", "importance_score", "user_starred", "summary", "chunk_index"])
}
@Test("conversation_summaries table has the expected v8 columns")
func conversationSummariesColumns() {
let db = DatabaseService.makeInMemory()
let columns = Set(db.columnNames(in: "conversation_summaries"))
#expect(columns == ["id", "conversation_id", "start_message_index", "end_message_index", "summary", "token_count", "created_at", "summary_model"])
}
@Test("A nonexistent table reports as absent, not a crash")
func nonexistentTableReportsAbsent() {
let db = DatabaseService.makeInMemory()
#expect(db.tableExists("not_a_real_table") == false)
}
@Test("Two in-memory instances are isolated from each other")
func instancesAreIsolated() throws {
let dbA = DatabaseService.makeInMemory()
let dbB = DatabaseService.makeInMemory()
_ = try dbA.saveConversation(name: "only in A", messages: [Message(role: .user, content: "hi")])
#expect(try dbA.listConversations().count == 1)
#expect(try dbB.listConversations().count == 0)
}
}
@Suite("DatabaseService settings CRUD, against a throwaway in-memory queue")
struct DatabaseServiceSettingsTests {
@Test("Round-trips a plain setting")
func roundTripsSetting() {
let db = DatabaseService.makeInMemory()
db.setSetting(key: "theme", value: "dark")
#expect((try? db.loadAllSettings()["theme"]) == "dark")
}
@Test("Deletes a setting")
func deletesSetting() {
let db = DatabaseService.makeInMemory()
db.setSetting(key: "temp", value: "1")
db.deleteSetting(key: "temp")
#expect((try? db.loadAllSettings()["temp"]) == nil)
}
}
@Suite("DatabaseService conversation + message persistence, against a throwaway in-memory queue")
struct DatabaseServiceConversationTests {
@Test("Saving a conversation round-trips its messages via loadConversation")
func savesAndLoadsConversation() throws {
let db = DatabaseService.makeInMemory()
let messages = [
Message(role: .user, content: "hello"),
Message(role: .assistant, content: "hi there"),
]
let saved = try db.saveConversation(name: "Test Chat", messages: messages)
let loaded = try db.loadConversation(id: saved.id)
#expect(loaded?.0.name == "Test Chat")
#expect(loaded?.1.map(\.content) == ["hello", "hi there"])
}
@Test("System messages are excluded from persistence")
func systemMessagesExcluded() throws {
let db = DatabaseService.makeInMemory()
let messages = [
Message(role: .system, content: "tool call"),
Message(role: .user, content: "hello"),
]
let saved = try db.saveConversation(name: "Test", messages: messages)
let loaded = try db.loadConversation(id: saved.id)
#expect(loaded?.1.count == 1)
#expect(loaded?.1.first?.content == "hello")
}
}