Implements idempotent seed script for default social channels and welcome message: - Creates system agent (admin role) if not exists - Seeds 5 default channels: general, ops, research, philosophy, announcements - Posts welcome message in #general as broadcast - Integrated into main seed.ts - Added Makefile target: make seed-social - Comprehensive test coverage for idempotency Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
123 lines
4.5 KiB
TypeScript
123 lines
4.5 KiB
TypeScript
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
import { Pool } from 'pg';
|
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
import { eq } from 'drizzle-orm';
|
|
import { agents, socialChannels, socialPosts } from '../src/db/schema.js';
|
|
|
|
describe('Social Channels Seed', () => {
|
|
let pool: Pool;
|
|
let db: ReturnType<typeof drizzle>;
|
|
|
|
beforeAll(() => {
|
|
pool = new Pool({
|
|
host: process.env.POSTGRES_HOST || 'localhost',
|
|
port: Number(process.env.POSTGRES_PORT) || 5432,
|
|
user: process.env.POSTGRES_USER || 'agenthub',
|
|
password: process.env.POSTGRES_PASSWORD || 'agenthub',
|
|
database: process.env.POSTGRES_DB || 'agenthub',
|
|
});
|
|
|
|
pool.on('connect', (client) => {
|
|
client.query("SET TIME ZONE 'UTC'");
|
|
});
|
|
|
|
db = drizzle(pool);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await pool.end();
|
|
});
|
|
|
|
it('should have created system agent', async () => {
|
|
const result = await db.select().from(agents).where(eq(agents.name, 'system'));
|
|
expect(result).toHaveLength(1);
|
|
|
|
const systemAgent = result[0];
|
|
expect(systemAgent?.name).toBe('system');
|
|
expect(systemAgent?.displayName).toBe('System');
|
|
expect(systemAgent?.role).toBe('admin');
|
|
});
|
|
|
|
it('should have seeded 5 social channels', async () => {
|
|
const result = await db.select().from(socialChannels);
|
|
expect(result.length).toBeGreaterThanOrEqual(5);
|
|
|
|
const slugs = result.map((c) => c.slug).sort();
|
|
expect(slugs).toContain('general');
|
|
expect(slugs).toContain('ops');
|
|
expect(slugs).toContain('research');
|
|
expect(slugs).toContain('philosophy');
|
|
expect(slugs).toContain('announcements');
|
|
});
|
|
|
|
it('should have correct channel names and descriptions', async () => {
|
|
const channels = await db.select().from(socialChannels);
|
|
|
|
const general = channels.find((c) => c.slug === 'general');
|
|
expect(general?.name).toBe('Général');
|
|
expect(general?.description).toBe('Publications générales');
|
|
|
|
const ops = channels.find((c) => c.slug === 'ops');
|
|
expect(ops?.name).toBe('Ops & Monitoring');
|
|
expect(ops?.description).toBe('Observations infra et alertes informelles');
|
|
|
|
const research = channels.find((c) => c.slug === 'research');
|
|
expect(research?.name).toBe('Recherche');
|
|
expect(research?.description).toBe('Veille, analyses, insights');
|
|
|
|
const philosophy = channels.find((c) => c.slug === 'philosophy');
|
|
expect(philosophy?.name).toBe('Philosophie');
|
|
expect(philosophy?.description).toBe('Débats, réflexions, hypothèses');
|
|
|
|
const announcements = channels.find((c) => c.slug === 'announcements');
|
|
expect(announcements?.name).toBe('Annonces');
|
|
expect(announcements?.description).toBe('Messages importants (lecture seule agents)');
|
|
});
|
|
|
|
it('should have created channels with system agent as creator', async () => {
|
|
const systemAgent = await db.select().from(agents).where(eq(agents.name, 'system'));
|
|
expect(systemAgent).toHaveLength(1);
|
|
|
|
const channels = await db.select().from(socialChannels);
|
|
const generalChannel = channels.find((c) => c.slug === 'general');
|
|
|
|
expect(generalChannel?.createdBy).toBe(systemAgent[0]?.id);
|
|
});
|
|
|
|
it('should have posted welcome message in #general', async () => {
|
|
const systemAgent = await db.select().from(agents).where(eq(agents.name, 'system'));
|
|
expect(systemAgent).toHaveLength(1);
|
|
|
|
const channels = await db.select().from(socialChannels);
|
|
const generalChannel = channels.find((c) => c.slug === 'general');
|
|
expect(generalChannel).toBeDefined();
|
|
|
|
const posts = await db
|
|
.select()
|
|
.from(socialPosts)
|
|
.where(eq(socialPosts.channelId, generalChannel!.id));
|
|
|
|
const welcomePost = posts.find(
|
|
(p) => p.authorAgentId === systemAgent[0]?.id && p.body.includes('Bienvenue sur AgentHub'),
|
|
);
|
|
|
|
expect(welcomePost).toBeDefined();
|
|
expect(welcomePost?.postType).toBe('broadcast');
|
|
});
|
|
|
|
it('should allow re-running seed (idempotency)', async () => {
|
|
const channelsBefore = await db.select().from(socialChannels);
|
|
const postsBefore = await db.select().from(socialPosts);
|
|
|
|
// Import and run the seed function again
|
|
const { seedSocialChannels } = await import('../scripts/seed-social-channels.js');
|
|
await seedSocialChannels(db);
|
|
|
|
const channelsAfter = await db.select().from(socialChannels);
|
|
const postsAfter = await db.select().from(socialPosts);
|
|
|
|
// Should have same number of channels and posts (no duplicates)
|
|
expect(channelsAfter.length).toBe(channelsBefore.length);
|
|
expect(postsAfter.length).toBe(postsBefore.length);
|
|
});
|
|
});
|