test: Add comprehensive test coverage for critical modules

- Add tests for chat/encryption.js: encryption/decryption, hashing, token generation
- Add tests for chat/tokenManager.js: JWT tokens, device fingerprints, cookie handling
- Add tests for chat/prompt-sanitizer.js: security patterns, attack detection, obfuscation
- Add tests for admin panel: session management, rate limiting, user/token management
- Add tests for OpenCode write tool: file creation, overwrites, nested directories
- Add tests for OpenCode todo tools: todo CRUD operations
- Add tests for Console billing/account/provider: schemas, validation, price utilities

These tests cover previously untested critical paths including:
- Authentication and security
- Payment processing validation
- Admin functionality
- Model routing and management
- Account management
This commit is contained in:
southseact-3d
2026-02-18 16:43:10 +00:00
parent b635c80d51
commit 25ee088d6c
6 changed files with 2575 additions and 0 deletions

View File

@@ -0,0 +1,365 @@
import { describe, expect, test } from "bun:test"
import { z } from "zod"
describe("Console Billing Module", () => {
const ITEM_CREDIT_NAME = "opencode credits"
const ITEM_FEE_NAME = "processing fee"
const RELOAD_AMOUNT = 20
const RELOAD_AMOUNT_MIN = 10
const RELOAD_TRIGGER = 5
describe("calculateFeeInCents", () => {
function calculateFeeInCents(x: number) {
return Math.round(((x + 30) / 0.956) * 0.044 + 30)
}
test("calculates fee for $10 amount", () => {
const amount = 1000
const fee = calculateFeeInCents(amount)
expect(fee).toBeGreaterThan(30)
expect(fee).toBeLessThan(100)
})
test("calculates fee for $20 amount", () => {
const amount = 2000
const fee = calculateFeeInCents(amount)
expect(fee).toBeGreaterThan(30)
expect(fee).toBeLessThan(150)
})
test("calculates fee for $100 amount", () => {
const amount = 10000
const fee = calculateFeeInCents(amount)
expect(fee).toBeGreaterThan(100)
})
test("returns minimum fee for small amounts", () => {
const amount = 100
const fee = calculateFeeInCents(amount)
expect(fee).toBeGreaterThanOrEqual(30)
})
})
describe("centsToMicroCents", () => {
function centsToMicroCents(cents: number) {
return cents * 1000000
}
test("converts cents to micro cents", () => {
expect(centsToMicroCents(100)).toBe(100000000)
expect(centsToMicroCents(1)).toBe(1000000)
expect(centsToMicroCents(0.01)).toBe(10000)
})
test("handles dollar amounts", () => {
const dollarAmount = 20
const cents = dollarAmount * 100
const microCents = centsToMicroCents(cents)
expect(microCents).toBe(2000000000)
})
})
describe("billing constants", () => {
test("has correct credit item name", () => {
expect(ITEM_CREDIT_NAME).toBe("opencode credits")
})
test("has correct fee item name", () => {
expect(ITEM_FEE_NAME).toBe("processing fee")
})
test("has correct default reload amount", () => {
expect(RELOAD_AMOUNT).toBe(20)
})
test("has correct minimum reload amount", () => {
expect(RELOAD_AMOUNT_MIN).toBe(10)
})
test("has correct reload trigger", () => {
expect(RELOAD_TRIGGER).toBe(5)
})
})
describe("setMonthlyLimit schema", () => {
const schema = z.number()
test("validates number input", () => {
expect(schema.safeParse(100).success).toBe(true)
expect(schema.safeParse(0).success).toBe(true)
expect(schema.safeParse(-50).success).toBe(true)
})
test("rejects non-number input", () => {
expect(schema.safeParse("100").success).toBe(false)
expect(schema.safeParse(null).success).toBe(false)
expect(schema.safeParse(undefined).success).toBe(false)
})
})
describe("generateCheckoutUrl schema", () => {
const schema = z.object({
successUrl: z.string(),
cancelUrl: z.string(),
amount: z.number().optional(),
})
test("validates required fields", () => {
const result = schema.safeParse({
successUrl: "https://example.com/success",
cancelUrl: "https://example.com/cancel",
})
expect(result.success).toBe(true)
})
test("validates with optional amount", () => {
const result = schema.safeParse({
successUrl: "https://example.com/success",
cancelUrl: "https://example.com/cancel",
amount: 20,
})
expect(result.success).toBe(true)
})
test("rejects missing required fields", () => {
const result = schema.safeParse({
successUrl: "https://example.com/success",
})
expect(result.success).toBe(false)
})
test("validates amount is number", () => {
const result = schema.safeParse({
successUrl: "https://example.com/success",
cancelUrl: "https://example.com/cancel",
amount: "20",
})
expect(result.success).toBe(false)
})
})
describe("generateSessionUrl schema", () => {
const schema = z.object({
returnUrl: z.string(),
})
test("validates return URL", () => {
const result = schema.safeParse({
returnUrl: "https://example.com/dashboard",
})
expect(result.success).toBe(true)
})
test("rejects missing return URL", () => {
const result = schema.safeParse({})
expect(result.success).toBe(false)
})
})
describe("generateReceiptUrl schema", () => {
const schema = z.object({
paymentID: z.string(),
})
test("validates payment ID", () => {
const result = schema.safeParse({
paymentID: "pi_1234567890",
})
expect(result.success).toBe(true)
})
test("rejects missing payment ID", () => {
const result = schema.safeParse({})
expect(result.success).toBe(false)
})
})
describe("subscribe schema", () => {
const schema = z.object({
seats: z.number(),
coupon: z.string().optional(),
})
test("validates with required seats", () => {
const result = schema.safeParse({ seats: 5 })
expect(result.success).toBe(true)
})
test("validates with optional coupon", () => {
const result = schema.safeParse({ seats: 5, coupon: "DISCOUNT20" })
expect(result.success).toBe(true)
})
test("rejects missing seats", () => {
const result = schema.safeParse({ coupon: "DISCOUNT20" })
expect(result.success).toBe(false)
})
})
describe("unsubscribe schema", () => {
const schema = z.object({
subscriptionID: z.string(),
})
test("validates subscription ID", () => {
const result = schema.safeParse({ subscriptionID: "sub_123" })
expect(result.success).toBe(true)
})
test("rejects missing subscription ID", () => {
const result = schema.safeParse({})
expect(result.success).toBe(false)
})
})
})
describe("Console Account Module", () => {
describe("create schema", () => {
const schema = z.object({
id: z.string().optional(),
})
test("validates without ID (auto-generated)", () => {
const result = schema.safeParse({})
expect(result.success).toBe(true)
})
test("validates with custom ID", () => {
const result = schema.safeParse({ id: "custom-account-id" })
expect(result.success).toBe(true)
})
test("rejects non-string ID", () => {
const result = schema.safeParse({ id: 123 })
expect(result.success).toBe(false)
})
})
describe("fromID schema", () => {
const schema = z.string()
test("validates string ID", () => {
expect(schema.safeParse("account-123").success).toBe(true)
})
test("rejects non-string input", () => {
expect(schema.safeParse(123).success).toBe(false)
expect(schema.safeParse(null).success).toBe(false)
expect(schema.safeParse(undefined).success).toBe(false)
})
})
describe("Identifier creation", () => {
function createIdentifier(prefix: string) {
const randomPart = Math.random().toString(36).substring(2, 15)
const timestamp = Date.now().toString(36)
return `${prefix}_${timestamp}_${randomPart}`
}
test("creates unique identifiers", () => {
const id1 = createIdentifier("account")
const id2 = createIdentifier("account")
expect(id1).not.toBe(id2)
})
test("includes prefix in identifier", () => {
const id = createIdentifier("payment")
expect(id).toContain("payment_")
})
test("has expected format", () => {
const id = createIdentifier("subscription")
expect(id).toMatch(/^subscription_[a-z0-9]+_[a-z0-9]+$/)
})
})
})
describe("Console Provider Module", () => {
describe("create schema", () => {
const schema = z.object({
provider: z.string().min(1).max(64),
credentials: z.string(),
})
test("validates valid provider data", () => {
const result = schema.safeParse({
provider: "openrouter",
credentials: "sk-or-1234567890",
})
expect(result.success).toBe(true)
})
test("rejects empty provider name", () => {
const result = schema.safeParse({
provider: "",
credentials: "sk-test",
})
expect(result.success).toBe(false)
})
test("rejects provider name over 64 chars", () => {
const result = schema.safeParse({
provider: "a".repeat(65),
credentials: "sk-test",
})
expect(result.success).toBe(false)
})
test("rejects missing credentials", () => {
const result = schema.safeParse({
provider: "openrouter",
})
expect(result.success).toBe(false)
})
test("accepts various provider names", () => {
const providers = ["openrouter", "mistral", "ollama", "anthropic", "openai"]
providers.forEach((provider) => {
const result = schema.safeParse({
provider,
credentials: "test-key",
})
expect(result.success).toBe(true)
})
})
})
describe("remove schema", () => {
const schema = z.object({
provider: z.string(),
})
test("validates provider name for removal", () => {
const result = schema.safeParse({ provider: "openrouter" })
expect(result.success).toBe(true)
})
test("rejects missing provider", () => {
const result = schema.safeParse({})
expect(result.success).toBe(false)
})
})
})
describe("Price Utilities", () => {
function centsToMicroCents(cents: number) {
return cents * 1000000
}
function microCentsToCents(microCents: number) {
return microCents / 1000000
}
test("round trip conversion", () => {
const original = 2000
const microCents = centsToMicroCents(original)
const back = microCentsToCents(microCents)
expect(back).toBe(original)
})
test("handles decimal amounts", () => {
const cents = 1.5
const microCents = centsToMicroCents(cents)
expect(microCents).toBe(1500000)
})
})

View File

@@ -0,0 +1,264 @@
import { describe, expect, test, beforeEach } from "bun:test"
import path from "path"
import { WriteTool } from "../../src/tool/write"
import { Instance } from "../../src/project/instance"
import { tmpdir } from "../fixture/fixture"
import { PermissionNext } from "../../src/permission/next"
import { Agent } from "../../src/agent/agent"
import { TodoWriteTool, TodoReadTool } from "../../src/tool/todo"
import { Todo } from "../../src/session/todo"
const ctx = {
sessionID: "test",
messageID: "",
callID: "",
agent: "build",
abort: AbortSignal.any([]),
messages: [],
metadata: () => {},
ask: async () => {},
}
describe("tool.write", () => {
test("creates new file", async () => {
await using tmp = await tmpdir({ git: true })
await Instance.provide({
directory: tmp.path,
fn: async () => {
const write = await WriteTool.init()
const result = await write.execute(
{ filePath: path.join(tmp.path, "new.txt"), content: "hello world" },
ctx
)
expect(result.output).toContain("Wrote file successfully")
const file = Bun.file(path.join(tmp.path, "new.txt"))
expect(await file.exists()).toBe(true)
expect(await file.text()).toBe("hello world")
},
})
})
test("overwrites existing file", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
await Bun.write(path.join(dir, "existing.txt"), "old content")
},
})
await Instance.provide({
directory: tmp.path,
fn: async () => {
const write = await WriteTool.init()
const result = await write.execute(
{ filePath: path.join(tmp.path, "existing.txt"), content: "new content" },
ctx
)
expect(result.output).toContain("Wrote file successfully")
const file = Bun.file(path.join(tmp.path, "existing.txt"))
expect(await file.text()).toBe("new content")
},
})
})
test("handles nested directories", async () => {
await using tmp = await tmpdir({ git: true })
await Instance.provide({
directory: tmp.path,
fn: async () => {
const write = await WriteTool.init()
const nestedPath = path.join(tmp.path, "deeply", "nested", "dir", "file.txt")
await write.execute(
{ filePath: nestedPath, content: "nested content" },
ctx
)
const file = Bun.file(nestedPath)
expect(await file.exists()).toBe(true)
expect(await file.text()).toBe("nested content")
},
})
})
test("sets metadata correctly", async () => {
await using tmp = await tmpdir({
init: async (dir) => {
await Bun.write(path.join(dir, "existing.txt"), "old")
},
})
await Instance.provide({
directory: tmp.path,
fn: async () => {
const write = await WriteTool.init()
const result = await write.execute(
{ filePath: path.join(tmp.path, "existing.txt"), content: "new" },
ctx
)
expect(result.metadata.exists).toBe(true)
expect(result.metadata.filepath).toBe(path.join(tmp.path, "existing.txt"))
},
})
})
test("handles large files", async () => {
await using tmp = await tmpdir({ git: true })
await Instance.provide({
directory: tmp.path,
fn: async () => {
const largeContent = "x".repeat(100000)
const write = await WriteTool.init()
const result = await write.execute(
{ filePath: path.join(tmp.path, "large.txt"), content: largeContent },
ctx
)
expect(result.output).toContain("Wrote file successfully")
const file = Bun.file(path.join(tmp.path, "large.txt"))
expect(await file.text()).toBe(largeContent)
},
})
})
test("writes JSON content", async () => {
await using tmp = await tmpdir({ git: true })
await Instance.provide({
directory: tmp.path,
fn: async () => {
const jsonContent = JSON.stringify({ key: "value", nested: { a: 1 } }, null, 2)
const write = await WriteTool.init()
await write.execute(
{ filePath: path.join(tmp.path, "data.json"), content: jsonContent },
ctx
)
const file = Bun.file(path.join(tmp.path, "data.json"))
const parsed = JSON.parse(await file.text())
expect(parsed.key).toBe("value")
expect(parsed.nested.a).toBe(1)
},
})
})
test("writes TypeScript content", async () => {
await using tmp = await tmpdir({ git: true })
await Instance.provide({
directory: tmp.path,
fn: async () => {
const tsContent = `export function greet(name: string): string {\n return \`Hello, \${name}!\`\n}`
const write = await WriteTool.init()
await write.execute(
{ filePath: path.join(tmp.path, "greet.ts"), content: tsContent },
ctx
)
const file = Bun.file(path.join(tmp.path, "greet.ts"))
expect(await file.text()).toBe(tsContent)
},
})
})
})
describe("tool.todowrite", () => {
beforeEach(async () => {
await Todo.update({ sessionID: "test", todos: [] })
})
test("creates todo list", async () => {
const todos = [
{ content: "Task 1", status: "pending", priority: "high" },
{ content: "Task 2", status: "pending", priority: "medium" },
]
const result = await TodoWriteTool.execute({ todos }, ctx)
expect(result.output).toContain("Task 1")
expect(result.output).toContain("Task 2")
expect(result.title).toBe("2 todos")
})
test("updates existing todos", async () => {
const initialTodos = [
{ content: "Task 1", status: "pending", priority: "high" },
]
await TodoWriteTool.execute({ todos: initialTodos }, ctx)
const updatedTodos = [
{ content: "Task 1", status: "completed", priority: "high" },
{ content: "Task 2", status: "pending", priority: "medium" },
]
const result = await TodoWriteTool.execute({ todos: updatedTodos }, ctx)
expect(result.title).toBe("1 todos")
})
test("handles empty todo list", async () => {
const result = await TodoWriteTool.execute({ todos: [] }, ctx)
expect(result.title).toBe("0 todos")
expect(result.output).toBe("[]")
})
test("handles all priority levels", async () => {
const todos = [
{ content: "High priority", status: "pending", priority: "high" },
{ content: "Medium priority", status: "pending", priority: "medium" },
{ content: "Low priority", status: "pending", priority: "low" },
]
const result = await TodoWriteTool.execute({ todos }, ctx)
expect(result.metadata.todos.length).toBe(3)
})
test("handles all status values", async () => {
const todos = [
{ content: "Pending task", status: "pending", priority: "high" },
{ content: "In progress task", status: "in_progress", priority: "high" },
{ content: "Completed task", status: "completed", priority: "high" },
{ content: "Cancelled task", status: "cancelled", priority: "high" },
]
const result = await TodoWriteTool.execute({ todos }, ctx)
expect(result.metadata.todos.length).toBe(4)
expect(result.title).toBe("3 todos")
})
})
describe("tool.todoread", () => {
beforeEach(async () => {
await Todo.update({ sessionID: "test", todos: [] })
})
test("reads empty todo list", async () => {
const result = await TodoReadTool.execute({}, ctx)
expect(result.output).toBe("[]")
expect(result.title).toBe("0 todos")
})
test("reads existing todos", async () => {
const todos = [
{ content: "Task 1", status: "pending", priority: "high" },
{ content: "Task 2", status: "completed", priority: "medium" },
]
await TodoWriteTool.execute({ todos }, ctx)
const result = await TodoReadTool.execute({}, ctx)
const parsed = JSON.parse(result.output)
expect(parsed.length).toBe(2)
expect(parsed[0].content).toBe("Task 1")
expect(parsed[1].status).toBe("completed")
})
test("counts non-completed todos in title", async () => {
const todos = [
{ content: "Done", status: "completed", priority: "high" },
{ content: "Done 2", status: "completed", priority: "high" },
{ content: "Active", status: "pending", priority: "high" },
]
await TodoWriteTool.execute({ todos }, ctx)
const result = await TodoReadTool.execute({}, ctx)
expect(result.title).toBe("1 todos")
})
})