tractatus/tests/integration/api.health.test.js
TheFlow d95dc4663c feat(infra): semantic versioning and systemd service implementation
**Cache-Busting Improvements:**
- Switched from timestamp-based to semantic versioning (v1.0.2)
- Updated all HTML files: index.html, docs.html, leader.html
- CSS: tailwind.css?v=1.0.2
- JS: navbar.js, document-cards.js, docs-app.js v1.0.2
- Professional versioning approach for production stability

**systemd Service Implementation:**
- Created tractatus-dev.service for development environment
- Created tractatus-prod.service for production environment
- Added install-systemd.sh script for easy deployment
- Security hardening: NoNewPrivileges, PrivateTmp, ProtectSystem
- Resource limits: 1GB dev, 2GB prod memory limits
- Proper logging integration with journalctl
- Automatic restart on failure (RestartSec=10)

**Why systemd over pm2:**
1. Native Linux integration, no additional dependencies
2. Better OS-level security controls (ProtectSystem, ProtectHome)
3. Superior logging with journalctl integration
4. Standard across Linux distributions
5. More robust process management for production

**Usage:**
  # Development:
  sudo ./scripts/install-systemd.sh dev

  # Production:
  sudo ./scripts/install-systemd.sh prod

  # View logs:
  sudo journalctl -u tractatus -f

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-09 09:16:22 +13:00

94 lines
2.9 KiB
JavaScript

/**
* Integration Tests - Health Check and Basic Infrastructure
* Verifies server starts and basic endpoints respond
*/
const request = require('supertest');
const app = require('../../src/server');
describe('Health Check Integration Tests', () => {
describe('GET /health', () => {
test('should return healthy status', async () => {
const response = await request(app)
.get('/health')
.expect('Content-Type', /json/)
.expect(200);
expect(response.body).toHaveProperty('status', 'healthy');
expect(response.body).toHaveProperty('timestamp');
expect(response.body).toHaveProperty('uptime');
expect(response.body).toHaveProperty('environment');
expect(typeof response.body.uptime).toBe('number');
});
});
describe('GET /api', () => {
test('should return API documentation', async () => {
const response = await request(app)
.get('/api')
.expect('Content-Type', /json/)
.expect(200);
expect(response.body).toHaveProperty('name', 'Tractatus AI Safety Framework API');
expect(response.body).toHaveProperty('version');
expect(response.body).toHaveProperty('endpoints');
});
});
describe('GET /', () => {
test('should return homepage', async () => {
const response = await request(app)
.get('/')
.expect(200);
expect(response.text).toContain('Tractatus AI Safety Framework');
// Homepage serves HTML, not text with "Server Running"
expect(response.headers['content-type']).toMatch(/html/);
});
});
describe('404 Handler', () => {
test('should return 404 for non-existent routes', async () => {
const response = await request(app)
.get('/this-route-does-not-exist')
.expect(404);
expect(response.body).toHaveProperty('error');
});
});
describe('Security Headers', () => {
test('should include security headers', async () => {
const response = await request(app)
.get('/health');
// Helmet security headers
expect(response.headers).toHaveProperty('x-content-type-options', 'nosniff');
expect(response.headers).toHaveProperty('x-frame-options');
expect(response.headers).toHaveProperty('x-xss-protection');
});
});
describe('CORS', () => {
test('should handle CORS preflight', async () => {
const response = await request(app)
.options('/api/documents')
.set('Origin', 'http://localhost:3000')
.set('Access-Control-Request-Method', 'GET');
// Should allow CORS
expect([200, 204]).toContain(response.status);
});
});
describe('MongoDB Connection', () => {
test('should connect to database', async () => {
const response = await request(app)
.get('/api/documents?limit=1')
.expect(200);
// If we get a successful response, MongoDB is connected
expect(response.body).toHaveProperty('success');
});
});
});