@queryleaf/postgres-server
Version:
PostgreSQL wire-compatible server for QueryLeaf
182 lines (157 loc) • 7.31 kB
text/typescript
import { GenericContainer, StartedTestContainer } from 'testcontainers';
import { MongoClient, Db, ObjectId } from 'mongodb';
import debug from 'debug';
const log = debug('queryleaf:test:mongodb');
/**
* Creates and manages a MongoDB container for testing
*/
export class MongoTestContainer {
private container: StartedTestContainer | null = null;
private client: MongoClient | null = null;
private db: Db | null = null;
private connectionString: string = '';
/**
* Start a MongoDB container
*/
async start(): Promise<string> {
this.container = await new GenericContainer('mongo:6.0')
.withExposedPorts(27017)
.start();
const host = this.container.getHost();
const port = this.container.getMappedPort(27017);
this.connectionString = `mongodb://${host}:${port}`;
this.client = new MongoClient(this.connectionString);
await this.client.connect();
return this.connectionString;
}
/**
* Get the MongoDB connection string
*/
getConnectionString(): string {
if (!this.connectionString) {
throw new Error('MongoDB container not started');
}
return this.connectionString;
}
/**
* Get the MongoDB client
*/
getClient(): MongoClient {
if (!this.client) {
throw new Error('MongoDB container not started');
}
return this.client;
}
/**
* Get a MongoDB database
* @param dbName Database name
*/
getDatabase(dbName: string): Db {
if (!this.client) {
throw new Error('MongoDB container not started');
}
this.db = this.client.db(dbName);
return this.db;
}
/**
* Stop the MongoDB container
*/
async stop(): Promise<void> {
// Make sure to properly close all connections
if (this.client) {
try {
log('Closing MongoDB client connection...');
await this.client.close(true); // Force close all connections
this.client = null;
} catch (err) {
log('Error closing MongoDB client:', err);
}
}
// Stop the container
if (this.container) {
try {
log('Stopping MongoDB container...');
await this.container.stop();
this.container = null;
} catch (err) {
log('Error stopping container:', err);
}
}
log('MongoDB cleanup complete');
}
}
/**
* Test fixture data
*/
export const testUsers = [
{ _id: new ObjectId("000000000000000000000001"), name: 'John Doe', age: 25, email: 'john@example.com', active: true },
{ _id: new ObjectId("000000000000000000000002"), name: 'Jane Smith', age: 30, email: 'jane@example.com', active: true },
{ _id: new ObjectId("000000000000000000000003"), name: 'Bob Johnson', age: 18, email: 'bob@example.com', active: false },
{ _id: new ObjectId("000000000000000000000004"), name: 'Alice Brown', age: 35, email: 'alice@example.com', active: true },
{ _id: new ObjectId("000000000000000000000005"), name: 'Charlie Davis', age: 17, email: 'charlie@example.com', active: false },
];
export const testProducts = [
{ _id: new ObjectId("100000000000000000000001"), name: 'Laptop', price: 1200, category: 'Electronics', inStock: true },
{ _id: new ObjectId("100000000000000000000002"), name: 'Smartphone', price: 800, category: 'Electronics', inStock: true },
{ _id: new ObjectId("100000000000000000000003"), name: 'Headphones', price: 150, category: 'Electronics', inStock: false },
{ _id: new ObjectId("100000000000000000000004"), name: 'Chair', price: 250, category: 'Furniture', inStock: true },
{ _id: new ObjectId("100000000000000000000005"), name: 'Table', price: 450, category: 'Furniture', inStock: true },
];
export const testOrders = [
{ _id: new ObjectId("200000000000000000000001"), userId: new ObjectId("000000000000000000000001"), productIds: [new ObjectId("100000000000000000000001"), new ObjectId("100000000000000000000003")], totalAmount: 1350, status: 'Completed', date: new Date('2023-01-01') },
{ _id: new ObjectId("200000000000000000000002"), userId: new ObjectId("000000000000000000000002"), productIds: [new ObjectId("100000000000000000000002"), new ObjectId("100000000000000000000005")], totalAmount: 1250, status: 'Completed', date: new Date('2023-02-15') },
{ _id: new ObjectId("200000000000000000000003"), userId: new ObjectId("000000000000000000000003"), productIds: [new ObjectId("100000000000000000000004")], totalAmount: 250, status: 'Processing', date: new Date('2023-03-10') },
{ _id: new ObjectId("200000000000000000000004"), userId: new ObjectId("000000000000000000000001"), productIds: [new ObjectId("100000000000000000000005"), new ObjectId("100000000000000000000003")], totalAmount: 600, status: 'Completed', date: new Date('2023-04-05') },
{ _id: new ObjectId("200000000000000000000005"), userId: new ObjectId("000000000000000000000004"), productIds: [new ObjectId("100000000000000000000001"), new ObjectId("100000000000000000000002")], totalAmount: 2000, status: 'Delivered', date: new Date('2023-05-20') },
];
// Add nested document data for testing nested field access
export const testDocuments = [
{
_id: new ObjectId("300000000000000000000001"),
title: 'Document 1',
metadata: { author: 'John', tags: ['tag1', 'tag2'], views: 100 },
comments: [
{ user: 'Alice', text: 'Great document!', likes: 5 },
{ user: 'Bob', text: 'Very helpful', likes: 3 }
]
},
{
_id: new ObjectId("300000000000000000000002"),
title: 'Document 2',
metadata: { author: 'Jane', tags: ['tag3', 'tag4'], views: 200 },
comments: [
{ user: 'Charlie', text: 'Needs improvement', likes: 1 },
{ user: 'David', text: 'Excellent work', likes: 7 }
]
}
];
/**
* Load test fixture data into MongoDB
* @param db MongoDB database
*/
export async function loadFixtures(db: Db): Promise<void> {
log('Loading test fixtures into MongoDB...');
log('Clearing existing data...');
await db.collection('users').deleteMany({});
await db.collection('products').deleteMany({});
await db.collection('orders').deleteMany({});
await db.collection('documents').deleteMany({});
log('Inserting users fixture data...');
const userResult = await db.collection('users').insertMany(testUsers);
log(`Inserted ${userResult.insertedCount} users`);
log('Inserting products fixture data...');
const productResult = await db.collection('products').insertMany(testProducts);
log(`Inserted ${productResult.insertedCount} products`);
log('Inserting orders fixture data...');
const orderResult = await db.collection('orders').insertMany(testOrders);
log(`Inserted ${orderResult.insertedCount} orders`);
log('Inserting documents fixture data...');
const documentResult = await db.collection('documents').insertMany(testDocuments);
log(`Inserted ${documentResult.insertedCount} documents`);
// Verify the data is loaded
const userCount = await db.collection('users').countDocuments();
const productCount = await db.collection('products').countDocuments();
const orderCount = await db.collection('orders').countDocuments();
const documentCount = await db.collection('documents').countDocuments();
log(`Fixture data loaded: ${userCount} users, ${productCount} products, ${orderCount} orders, ${documentCount} documents`);
}