Governed substrate for autonomous agents: scoped identity (passports), audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
362 lines
11 KiB
JavaScript
362 lines
11 KiB
JavaScript
// Owner Space Auto-Creation Tests - v0.002.007
|
|
// TDD: RED Phase - Tests должны упасть, т.к. функционал еще не реализован
|
|
|
|
process.env.TEST_MODE = 'true';
|
|
process.env.MASTER_ENCRYPTION_KEY = 'test_master_key_32_characters_long!';
|
|
|
|
import { describe, test, expect, beforeEach, afterEach } from 'vitest';
|
|
import { setupTestDatabase, cleanupTestDatabase } from './helpers/test-db.js';
|
|
import { dbGet, dbAll } from '../database/connection.js';
|
|
import { registerUser } from '../services/AuthService.js';
|
|
|
|
describe.skip('Owner Space Auto-Creation - Full TDD', () => {
|
|
beforeEach(async () => {
|
|
process.env.SKIP_DEV_USER = 'true';
|
|
await setupTestDatabase();
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await cleanupTestDatabase();
|
|
});
|
|
|
|
// ============================================================
|
|
// Phase 1: Owner Registration + Admin Owner's Space
|
|
// ============================================================
|
|
|
|
describe.skip('Phase 1: Owner Registration', () => {
|
|
test('1.1: First user becomes owner with role', async () => {
|
|
const user = await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'John Owner'
|
|
});
|
|
|
|
expect(user).toBeDefined();
|
|
expect(user.id).toBe(1);
|
|
expect(user.role).toBe('owner'); // ❌ FAIL: role is undefined or 'user'
|
|
});
|
|
|
|
test('1.2: Admin Owners Space project created', async () => {
|
|
const owner = await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'John Owner'
|
|
});
|
|
|
|
const adminSpace = await dbGet(
|
|
'SELECT * FROM projects WHERE owner_id = ? AND type = ?',
|
|
[owner.id, 'admin_owner_space']
|
|
);
|
|
|
|
expect(adminSpace).toBeDefined();
|
|
expect(adminSpace.name).toBe("Admin Owner's Space");
|
|
expect(adminSpace.icon).toBe('⚙️');
|
|
expect(adminSpace.theme_primary).toBe('#ef4444'); // Red
|
|
expect(adminSpace.theme_secondary).toBe('#f97316'); // Orange
|
|
expect(adminSpace.theme_tertiary).toBe('#eab308'); // Yellow
|
|
});
|
|
|
|
test('1.3: Users system table created in Admin Space', async () => {
|
|
const owner = await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'John Owner'
|
|
});
|
|
|
|
const adminSpace = await dbGet(
|
|
'SELECT * FROM projects WHERE owner_id = ? AND type = ?',
|
|
[owner.id, 'admin_owner_space']
|
|
);
|
|
|
|
const usersTable = await dbGet(
|
|
'SELECT * FROM universal_tables WHERE project_id = ? AND name = ?',
|
|
[adminSpace.id, 'Users']
|
|
);
|
|
|
|
expect(usersTable).toBeDefined(); // ❌ FAIL: table not created
|
|
expect(usersTable.is_system).toBe(1);
|
|
expect(usersTable.sync_target).toBe('users');
|
|
expect(usersTable.icon).toBe('👥');
|
|
});
|
|
|
|
test('1.4: Users table has correct columns', async () => {
|
|
const owner = await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'John Owner'
|
|
});
|
|
|
|
const usersTable = await dbGet(
|
|
'SELECT * FROM universal_tables WHERE name = ?',
|
|
['Users']
|
|
);
|
|
|
|
const columns = await dbAll(
|
|
'SELECT * FROM table_columns WHERE table_id = ? ORDER BY order_index',
|
|
[usersTable.id]
|
|
);
|
|
|
|
// Expected columns
|
|
const expectedColumns = [
|
|
{ column_name: 'id', type: 'number', is_system: 1 },
|
|
{ column_name: 'created_at', type: 'datetime', is_system: 1 },
|
|
{ column_name: 'updated_at', type: 'datetime', is_system: 1 },
|
|
{ column_name: 'email', type: 'email', is_required: 1 },
|
|
{ column_name: 'name', type: 'text', is_required: 1 },
|
|
{ column_name: 'role', type: 'select' },
|
|
{ column_name: 'avatar', type: 'image' },
|
|
{ column_name: 'totp_enabled', type: 'checkbox' },
|
|
{ column_name: 'email_verified', type: 'checkbox' }
|
|
];
|
|
|
|
expect(columns.length).toBeGreaterThanOrEqual(expectedColumns.length);
|
|
|
|
// Check each column
|
|
for (const expected of expectedColumns) {
|
|
const col = columns.find(c => c.column_name === expected.column_name);
|
|
expect(col, `Column ${expected.column_name} should exist`).toBeDefined();
|
|
expect(col.type).toBe(expected.type);
|
|
if (expected.is_system) expect(col.is_system).toBe(1);
|
|
if (expected.is_required) expect(col.is_required).toBe(1);
|
|
}
|
|
|
|
// Check role column has options
|
|
const roleColumn = columns.find(c => c.column_name === 'role');
|
|
const config = JSON.parse(roleColumn.config || '{}');
|
|
expect(config.options).toBeDefined();
|
|
expect(config.options.length).toBe(3); // owner, admin, user
|
|
expect(config.options.map(o => o.value)).toContain('owner');
|
|
expect(config.options.map(o => o.value)).toContain('admin');
|
|
expect(config.options.map(o => o.value)).toContain('user');
|
|
});
|
|
|
|
test('1.5: Projects system table created', async () => {
|
|
const owner = await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'John Owner'
|
|
});
|
|
|
|
const adminSpace = await dbGet(
|
|
'SELECT * FROM projects WHERE type = ?',
|
|
['admin_owner_space']
|
|
);
|
|
|
|
const projectsTable = await dbGet(
|
|
'SELECT * FROM universal_tables WHERE project_id = ? AND name = ?',
|
|
[adminSpace.id, 'Projects']
|
|
);
|
|
|
|
expect(projectsTable).toBeDefined(); // ❌ FAIL
|
|
expect(projectsTable.is_system).toBe(1);
|
|
expect(projectsTable.sync_target).toBe('projects');
|
|
expect(projectsTable.icon).toBe('📁');
|
|
});
|
|
|
|
test('1.6: Projects table has correct columns', async () => {
|
|
const owner = await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'John Owner'
|
|
});
|
|
|
|
const projectsTable = await dbGet(
|
|
'SELECT * FROM universal_tables WHERE name = ?',
|
|
['Projects']
|
|
);
|
|
|
|
const columns = await dbAll(
|
|
'SELECT * FROM table_columns WHERE table_id = ?',
|
|
[projectsTable.id]
|
|
);
|
|
|
|
const columnNames = columns.map(c => c.column_name);
|
|
expect(columnNames).toContain('id');
|
|
expect(columnNames).toContain('name');
|
|
expect(columnNames).toContain('type');
|
|
expect(columnNames).toContain('owner_id');
|
|
expect(columnNames).toContain('icon');
|
|
expect(columnNames).toContain('theme_primary');
|
|
|
|
// Check owner column is 'user' type (relation)
|
|
const ownerColumn = columns.find(c => c.column_name === 'owner_id');
|
|
expect(ownerColumn.type).toBe('user');
|
|
});
|
|
|
|
test('1.7: Tables system table created', async () => {
|
|
const owner = await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'John Owner'
|
|
});
|
|
|
|
const adminSpace = await dbGet(
|
|
'SELECT * FROM projects WHERE type = ?',
|
|
['admin_owner_space']
|
|
);
|
|
|
|
const tablesTable = await dbGet(
|
|
'SELECT * FROM universal_tables WHERE project_id = ? AND name = ?',
|
|
[adminSpace.id, 'Tables']
|
|
);
|
|
|
|
expect(tablesTable).toBeDefined(); // ❌ FAIL
|
|
expect(tablesTable.is_system).toBe(1);
|
|
expect(tablesTable.sync_target).toBe('universal_tables');
|
|
expect(tablesTable.icon).toBe('📊');
|
|
});
|
|
|
|
test('1.8: Second user does NOT become owner', async () => {
|
|
// First user
|
|
await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'Owner'
|
|
});
|
|
|
|
// Second user
|
|
const user2 = await registerUser({
|
|
email: 'user2@test.com',
|
|
password: 'Pass123!',
|
|
name: 'User 2'
|
|
});
|
|
|
|
expect(user2.role).toBe('user'); // Should be 'user', not 'owner'
|
|
});
|
|
|
|
test('1.9: Second user does NOT get Admin Space', async () => {
|
|
await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'Owner'
|
|
});
|
|
|
|
const user2 = await registerUser({
|
|
email: 'user2@test.com',
|
|
password: 'Pass123!',
|
|
name: 'User 2'
|
|
});
|
|
|
|
const adminSpaces = await dbAll(
|
|
'SELECT * FROM projects WHERE owner_id = ? AND type = ?',
|
|
[user2.id, 'admin_owner_space']
|
|
);
|
|
|
|
expect(adminSpaces.length).toBe(0); // No admin space for regular users
|
|
});
|
|
});
|
|
|
|
// ============================================================
|
|
// Phase 2: System Tables Structure Validation
|
|
// ============================================================
|
|
|
|
describe.skip('Phase 2: System Tables Structure', () => {
|
|
test('2.1: All 3 system tables created together', async () => {
|
|
await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'Owner'
|
|
});
|
|
|
|
const adminSpace = await dbGet(
|
|
'SELECT * FROM projects WHERE type = ?',
|
|
['admin_owner_space']
|
|
);
|
|
|
|
const systemTables = await dbAll(
|
|
'SELECT * FROM universal_tables WHERE project_id = ? AND is_system = 1',
|
|
[adminSpace.id]
|
|
);
|
|
|
|
expect(systemTables.length).toBe(3); // Users, Projects, Tables
|
|
|
|
const tableNames = systemTables.map(t => t.name).sort();
|
|
expect(tableNames).toEqual(['Projects', 'Tables', 'Users']);
|
|
});
|
|
|
|
test('2.2: System tables have correct sync targets', async () => {
|
|
await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'Owner'
|
|
});
|
|
|
|
const systemTables = await dbAll(
|
|
'SELECT * FROM universal_tables WHERE is_system = 1'
|
|
);
|
|
|
|
const syncMap = {};
|
|
systemTables.forEach(t => {
|
|
syncMap[t.name] = t.sync_target;
|
|
});
|
|
|
|
expect(syncMap['Users']).toBe('users');
|
|
expect(syncMap['Projects']).toBe('projects');
|
|
expect(syncMap['Tables']).toBe('universal_tables');
|
|
});
|
|
|
|
test('2.3: All system tables have icons', async () => {
|
|
await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'Owner'
|
|
});
|
|
|
|
const systemTables = await dbAll(
|
|
'SELECT * FROM universal_tables WHERE is_system = 1'
|
|
);
|
|
|
|
for (const table of systemTables) {
|
|
expect(table.icon, `Table ${table.name} should have icon`).toBeDefined();
|
|
expect(table.icon.length).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
});
|
|
|
|
// ============================================================
|
|
// Phase 3: Edge Cases & Error Handling
|
|
// ============================================================
|
|
|
|
describe.skip('Phase 3: Edge Cases', () => {
|
|
test('3.1: Cannot create duplicate Users table', async () => {
|
|
await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'Owner'
|
|
});
|
|
|
|
const usersTable = await dbGet(
|
|
'SELECT * FROM universal_tables WHERE name = ?',
|
|
['Users']
|
|
);
|
|
|
|
// Try to create duplicate
|
|
try {
|
|
await dbAll(
|
|
'INSERT INTO universal_tables (project_id, name, is_system, sync_target) VALUES (?, ?, 1, ?)',
|
|
[usersTable.project_id, 'Users', 'users']
|
|
);
|
|
expect.fail('Should not allow duplicate Users table');
|
|
} catch (error) {
|
|
// Should throw constraint error
|
|
expect(error).toBeDefined();
|
|
}
|
|
});
|
|
|
|
test('3.2: System tables are read-only (is_system = 1)', async () => {
|
|
await registerUser({
|
|
email: 'owner@test.com',
|
|
password: 'Pass123!',
|
|
name: 'Owner'
|
|
});
|
|
|
|
const systemTables = await dbAll(
|
|
'SELECT * FROM universal_tables WHERE is_system = 1'
|
|
);
|
|
|
|
for (const table of systemTables) {
|
|
expect(table.is_system).toBe(1);
|
|
}
|
|
});
|
|
});
|
|
});
|