Scheduler Testing Guide
Comprehensive guide for testing the NCP scheduler system.
Testing Strategy
1. Unit Tests (Fast, Isolated)
Test individual components in isolation:
- JobManager (CRUD operations)
- ExecutionRecorder (CSV + JSON storage)
- CronManager (validation only, not actual crontab)
- NaturalLanguageParser (schedule parsing)
- ToolValidator (validation logic)
2. Integration Tests (Moderate, Mocked)
Test component interactions with mocked dependencies:
- Job creation → Validation → Storage → Cron entry
- Execution flow → Recording → Cleanup
- CLI commands → Scheduler → Storage
3. E2E Tests (Slow, Real System)
Test actual system behavior (run manually or in isolated CI):
- Real crontab manipulation
- Actual tool execution
- Real MCP interactions
Running Tests
All Tests
npm testScheduler Tests Only
npm test -- test/schedulerSpecific Test File
npm test -- test/scheduler/job-manager.test.tsWatch Mode
npm test -- --watch test/schedulerTest Structure
test/scheduler/
├── test-helpers.ts # Shared utilities
├── job-manager.test.ts # JobManager unit tests
├── execution-recorder.test.ts # ExecutionRecorder unit tests
├── cron-manager.test.ts # CronManager unit tests
├── natural-language-parser.test.ts # Parser unit tests
├── tool-validator.test.ts # Validation unit tests
├── scheduler-integration.test.ts # Integration tests
└── e2e/ # End-to-end tests
├── real-cron.test.ts # Actual crontab tests
└── real-execution.test.ts # Actual tool execution testsUnit Testing
JobManager Tests
Tests CRUD operations on jobs:
describe('JobManager', () => {
it('should create a new job', () => {
const job = createMockJob();
jobManager.createJob(job);
const retrieved = jobManager.getJob(job.id);
expect(retrieved).toEqual(job);
});
it('should reject duplicate job IDs', () => {
const job = createMockJob();
jobManager.createJob(job);
expect(() => jobManager.createJob(job)).toThrow('already exists');
});
});Run:
npm test -- test/scheduler/job-manager.test.tsNaturalLanguageParser Tests
Tests schedule parsing:
describe('NaturalLanguageParser', () => {
it('should parse "every day at 9am"', () => {
const result = NaturalLanguageParser.parseSchedule('every day at 9am');
expect(result.success).toBe(true);
expect(result.cronExpression).toBe('0 9 * * *');
});
it('should parse "in 5 minutes" as one-time', () => {
const result = NaturalLanguageParser.parseSchedule('in 5 minutes');
expect(result.success).toBe(true);
expect(result.fireOnce).toBe(true);
});
});Run:
npm test -- test/scheduler/natural-language-parser.test.tsCronManager Tests
Tests cron expression validation (NOT actual crontab):
describe('CronManager', () => {
it('should validate correct cron expressions', () => {
const result = CronManager.validateCronExpression('0 9 * * *');
expect(result.valid).toBe(true);
});
it('should reject invalid expressions', () => {
const result = CronManager.validateCronExpression('60 * * * *');
expect(result.valid).toBe(false);
expect(result.error).toContain('minute');
});
});Run:
npm test -- test/scheduler/cron-manager.test.tsIntegration Testing
Tests component interactions with mocked dependencies:
describe('Scheduler Integration', () => {
it('should create job with validation', async () => {
// Mock file system
const testDir = createTestDirectory();
mockSchedulerEnvironment(testDir);
// Create scheduler
const scheduler = new Scheduler();
// Create job (validation happens automatically)
const job = await scheduler.createJob({
name: 'Test Job',
schedule: 'every day at 9am',
tool: 'test:tool',
parameters: {}
});
expect(job.id).toBeDefined();
expect(job.cronExpression).toBe('0 9 * * *');
// Cleanup
cleanupTestDirectory(testDir);
});
});Run:
npm test -- test/scheduler/scheduler-integration.test.tsManual Testing
1. Test Job Creation
# Create a test job
ncp schedule create scheduler:validate "in 2 minutes" \
--name "Test Validation Job" \
--params '{"tool": "schedule", "arguments": {"name": "test"}}' \
--fire-once
# Verify it was created
ncp schedule list
# Check crontab (Unix/Linux/macOS only)
crontab -l | grep NCPExpected Output:
# === NCP SCHEDULED JOBS - DO NOT EDIT MANUALLY ===
# NCP_JOB: <job-id>
42 14 20 1 * ncp _job-run <job-id>
# === END NCP SCHEDULED JOBS ===2. Test Job Execution
# Create a job that runs in 1 minute
ncp schedule create scheduler:validate "in 1 minute" \
--name "Quick Test" \
--params '{"tool": "schedule", "arguments": {}}' \
--fire-once
# Wait 1-2 minutes...
# Check execution history
ncp schedule executions --job-id "Quick Test"Expected Output:
✅ Quick Test
ID: exec-abc-123
Time: 1/20/2025, 2:42:00 PM
Duration: 234ms3. Test Validation
# This should FAIL validation (missing required param)
ncp schedule create scheduler:schedule "every day at 9am" \
--name "Bad Job" \
--params '{}'
# Expected error:
# ❌ Tool validation failed:
# Missing required parameter: name
# Missing required parameter: schedule
# Missing required parameter: tool
# Missing required parameter: parameters4. Test Natural Language Parsing
# Test various schedule formats
ncp schedule create scheduler:validate "every weekday at 2:30pm" \
--name "Weekday Test" \
--params '{"tool": "schedule", "arguments": {}}' \
--test-run
# Check the cron expression
ncp schedule get "Weekday Test"
# Should show: 30 14 * * 1-5End-to-End Testing
⚠️ WARNING: These tests modify your system crontab. Run in isolated environment!
Setup Test Environment
# Create isolated test user (Linux)
sudo useradd -m ncptest
sudo su - ncptest
# Or use Docker
docker run -it --rm node:18 bash
npm install -g ncp # Install NCPE2E Test 1: Simple Job
# Create a simple job
ncp schedule create scheduler:validate "*/5 * * * *" \
--name "Five Minute Test" \
--params '{"tool": "schedule", "arguments": {}}' \
--max-executions 3
# Wait 15 minutes for 3 executions
# Check executions
ncp schedule executions --job-id "Five Minute Test"
# Should show 3 successful executions
# Job should be marked as "completed"
ncp schedule get "Five Minute Test"E2E Test 2: Error Handling
# Create job with invalid tool (should fail validation)
ncp schedule create nonexistent:tool "every day at 9am" \
--name "Bad Tool" \
--params '{}'
# Should fail with validation errorE2E Test 3: Cleanup
# Create multiple jobs
for i in {1..5}; do
ncp schedule create scheduler:validate "every day at ${i}am" \
--name "Test Job $i" \
--params '{"tool": "schedule", "arguments": {}}'
done
# Generate some executions (run jobs manually)
for i in {1..5}; do
JOB_ID=$(ncp schedule list | grep "Test Job $i" | awk '{print $4}')
ncp _job-run $JOB_ID
done
# Run cleanup
ncp schedule cleanup --max-per-job 2
# Verify old executions were deleted
ncp schedule executionsTesting Validation Protocol
Test MCP-Native Validation
# The scheduler MCP implements tools/validate
# Test it through the MCP interface:
# 1. Via CLI (calls MCP internally)
ncp schedule create scheduler:schedule "every day" \
--name "Validation Test" \
--params '{"name": "test"}' # Missing required params
# Should show validation errors
# 2. Via run command (test validate tool directly)
ncp run scheduler:validate --params '{
"tool": "schedule",
"arguments": {
"name": "test",
"schedule": "invalid cron",
"tool": "filesystem:backup",
"parameters": {}
}
}'
# Should return validation errors in JSON formatCI/CD Testing
GitHub Actions Example
name: Scheduler Tests
on: [push, pull_request]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
# Skip Windows since cron not supported
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm test -- test/scheduler
- name: Run integration tests
run: npm test -- test/scheduler/scheduler-integration.test.ts
# E2E tests only on Linux (safe cron manipulation)
- name: Run E2E tests
if: matrix.os == 'ubuntu-latest'
run: npm test -- test/scheduler/e2eTest Coverage
Check Coverage
npm test -- --coverage test/schedulerTarget Coverage:
- JobManager: 90%+
- ExecutionRecorder: 85%+
- NaturalLanguageParser: 95%+
- CronManager (validation): 90%+
- ToolValidator: 85%+
- Scheduler: 80%+
Debugging Tests
Enable Debug Logging
# Set debug env var
export NCP_DEBUG=true
# Run tests
npm test -- test/scheduler/job-manager.test.ts
# Debug logs will show file paths, operations, etc.Inspect Test Artifacts
# Tests create temp directories, find them:
ls /tmp/ncp-scheduler-test-*
# Inspect test data
cat /tmp/ncp-scheduler-test-*/scheduler/jobs.json
cat /tmp/ncp-scheduler-test-*/scheduler/executions/summary.csvCommon Test Failures
1. "crontab command not found"
Cause: Testing on Windows or system without cron Solution: Tests should skip on Windows automatically
if (process.platform === 'win32') {
console.log('Skipping cron test on Windows');
return;
}2. "Permission denied" on crontab
Cause: User doesn't have crontab permissions Solution: Run in Docker or add user to cron group
sudo usermod -a -G cron $USER3. Test directories not cleaned up
Cause: Test interrupted before cleanup Solution: Manual cleanup
rm -rf /tmp/ncp-scheduler-test-*Best Practices
- Isolate Tests: Use temp directories, don't touch real crontab
- Mock External Deps: Mock MCPs, file system, cron when possible
- Test Edge Cases: Empty params, invalid cron, duplicate names
- Test Error Paths: Validation failures, missing files, bad permissions
- Clean Up: Always cleanup test artifacts in
afterEach - Platform Checks: Skip Windows-specific tests gracefully
- Time Independence: Don't depend on current time for assertions
Summary
Quick Test Commands
# All tests
npm test
# Unit tests only
npm test -- test/scheduler/*.test.ts
# Integration tests
npm test -- test/scheduler/*-integration.test.ts
# Watch mode for development
npm test -- --watch test/scheduler
# Coverage report
npm test -- --coverage test/schedulerManual Test Workflow
# 1. Create test job
ncp schedule create scheduler:validate "in 2 minutes" \
--name "Test" --params '{"tool":"schedule","arguments":{}}' --fire-once
# 2. Verify in crontab
crontab -l | grep NCP
# 3. Wait for execution
# 4. Check results
ncp schedule executions --job-id "Test"
# 5. Cleanup
ncp schedule delete "Test" -yRemember: Always test in isolated environments for E2E tests that touch system crontab!