Skip to content

copperbox/mock-services-simulator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mock-services-simulator

A single unified Express service that simulates a configurable number of virtual microservices with real dependency health monitoring, powered by proactive-deps.

Created for testing aspects of Depsera.

Quick Start

npm install
npm start

The server starts on port 5000 (default). Visit http://localhost:5000/ for a full service index.

How It Works

Instead of running separate processes, the server generates a dependency tree of virtual services organized into 4 architectural layers:

Layer Category Pool Size Examples
0 data 18 user-db, order-db, session-cache, event-store, search-index, message-queue
1 domain 18 auth-svc, payment-svc, shipping-svc, fraud-detection-svc, loyalty-svc
2 api 18 catalog-api, checkout-api, analytics-api, webhook-api, marketplace-api
3 gateway 12 public-gateway, mobile-gateway, graphql-gateway, streaming-gateway

Each layer has a pool of distinct, realistic service names with unique descriptions. Services are drawn from the pool in order; numeric suffixes are only appended if SERVICE_COUNT exceeds the total pool capacity (~66 services). Each virtual service gets its own Express router and DependencyMonitor instance. Services in higher layers depend on services in lower layers, with health checks flowing through HTTP just like real microservices.

Teams

Services are grouped into teams to model a realistic multi-team organization. The global service tree is generated first, then services are distributed across teams using deterministic round-robin. Cross-team dependencies are naturally preserved since the tree is built before partitioning.

Team names come from a fixed pool: platform, commerce, data-eng, infra, mobile, partner, growth, internal. If TEAM_COUNT exceeds the pool size, overflow names get numeric suffixes (e.g. platform-2).

Configuration

Env Var Default Purpose
PORT 5000 Server port
SERVICE_COUNT 8 Number of virtual services to generate
TEAM_COUNT 1 Number of teams to distribute services across
BASE_URL http://localhost:<PORT> Base URL used in manifests and health check URLs
CHECK_INTERVAL_MS 15000 Monitor check interval
CACHE_DURATION_MS 60000 Monitor cache duration
REFRESH_THRESHOLD_MS 5000 Monitor refresh threshold
OTLP_PUSH_URL (disabled) Depsera OTLP endpoint URL (e.g. https://app.depsera.com/v1/metrics). Pusher only activates when both URL and API key are set.
OTLP_API_KEY (disabled) Bearer token for OTLP endpoint (e.g. dps_abc123).
OTLP_PUSH_INTERVAL_MS 30000 How often to push metrics to the OTLP endpoint (ms).

Example with custom config:

SERVICE_COUNT=12 TEAM_COUNT=3 PORT=3000 npm start

Endpoints

Global

Route Description
GET / Root index with all teams, services, and routes

Per Team

Route Description
GET /<team>/manifest Depsera-compatible manifest JSON for this team (reflects any active drift mutations)
GET /<team>/manifest/baseline Original unmodified manifest
GET /<team>/manifest/overlay Debug: current drift overlay state
POST /<team>/manifest/reset Reset manifest back to baseline

Per Virtual Service (/<team>/<service-key>/)

Route Description
GET /<team>/<key>/check Health check — returns 200 or 500 if failure inserted
GET /<team>/<key>/health Dependency health statuses from this service's monitor
GET /<team>/<key>/insert-failure Toggle simulated failure on this service's /check. Add ?cascade=true to propagate to all downstream dependants.
GET /<team>/<key>/metrics Prometheus-format metrics

Simulating Failures

Single service:

  1. GET /platform/user-db/insert-failure — toggles user-db to return 500 on /check
  2. GET /platform/auth-svc/health — shows user-db dependency as CRITICAL (if auth-svc depends on user-db)
  3. GET /platform/user-db/insert-failure — toggle back to healthy

Cascade failure (?cascade=true):

  1. GET /platform/user-db/insert-failure?cascade=true — fails user-db AND all services that depend on it (directly or transitively)
  2. Every downstream dependant's /check now returns 500
  3. GET /platform/user-db/insert-failure?cascade=true — toggle back, clearing failure on all affected services

The response includes the full list of affected services:

{
  "service": "user-db",
  "failureInserted": true,
  "cascade": true,
  "affected": ["user-db", "auth-svc", "user-api"]
}

Failures also propagate naturally through the dependency graph via the health monitors, including across team boundaries.

OTLP Metrics Push

Optionally push dependency health metrics to a Depsera-compatible OTLP endpoint. When both OTLP_PUSH_URL and OTLP_API_KEY are set, the server periodically collects dependency status data from all virtual services and POSTs it as OTLP JSON to the configured /v1/metrics endpoint.

OTLP_PUSH_URL=https://app.depsera.com/v1/metrics \
OTLP_API_KEY=dps_abc123 \
OTLP_PUSH_INTERVAL_MS=15000 \
npm start

Each virtual service becomes a separate OTLP resource (identified by service.name, service.namespace, service.instance.id). Its dependency health statuses are pushed as gauge metrics:

Metric Source Type
dependency.health.status Status code (0=OK, 1=CRITICAL, 2=WARNING) int
dependency.health.healthy Healthy flag (1=true, 0=false) int
dependency.health.latency Check latency in ms double
dependency.health.code Status code int
dependency.health.check_skipped Skipped flag int

Each data point carries label attributes: dependency.name, dependency.type, dependency.impact, dependency.description, dependency.error_message.

These metric and attribute names match Depsera's default OTLP mappings, so no custom schema_config is needed on the Depsera side.

Manifest Drift Testing

Each team's manifest supports dynamic mutation to test Depsera's sync drift policies (on_field_drift, on_removal, on_alias_removal, on_override_removal, on_association_removal). Mutations only affect the manifest — the underlying virtual services keep running.

Drift Mutation Endpoints

All endpoints are relative to /<team>/manifest:

Method Path Drift Scenario
POST /services/:key/override Field drift — body: { "field": "name", "value": "New Name" }
DELETE /services/:key Service removal
POST /services Service addition — body: full service object
DELETE /associations/:serviceKey/:linkedTeam/:linkedKey Association removal
POST /associations Association addition — body: full association object
DELETE /aliases/:alias Alias removal
POST /aliases Alias addition — body: { "alias": "...", "canonical_name": "..." }
DELETE /canonical-overrides/:canonicalName Override removal
POST /canonical-overrides Override addition — body: full override object

Example: Testing Field Drift

# 1. Override a service name
curl -X POST http://localhost:5000/platform/manifest/services/auth-svc/override \
  -H 'Content-Type: application/json' \
  -d '{"field":"name","value":"Renamed Auth"}'

# 2. Verify the manifest shows the drifted value
curl http://localhost:5000/platform/manifest

# 3. Reset back to baseline
curl -X POST http://localhost:5000/platform/manifest/reset

# 4. Verify manifest is back to original
curl http://localhost:5000/platform/manifest

Example: Testing Service Removal

# Remove a service from the manifest (service itself keeps running)
curl -X DELETE http://localhost:5000/platform/manifest/services/auth-svc

# Verify it's gone from the manifest
curl http://localhost:5000/platform/manifest

# The service is still reachable
curl http://localhost:5000/platform/auth-svc/check

Manifest Schema

Each team's /<team>/manifest endpoint returns a JSON manifest conforming to the Depsera manifest schema. The manifest includes:

  • services — all virtual services belonging to this team with key, name, health_endpoint, description, metrics_endpoint, and poll_interval_ms
  • associations — dependency relationships using linked_service_key in namespaced team_key/service_key format to unambiguously reference the target service across teams
  • aliases — short names for services (e.g. authauth-svc), auto-generated from category suffixes (-svc, -api, -db, etc.)
  • canonical_overrides — contact and impact overrides for key services, auto-generated for the highest-layer service per team (and a second domain-layer service if the team has 4+ services)

For example, if auth-svc on the commerce team depends on user-db on the platform team:

{
  "service_key": "auth-svc",
  "dependency_name": "user-db",
  "linked_service_key": "platform/user-db",
  "association_type": "database"
}

Association types are inferred from the dependency's service key:

Dependency pattern association_type
*-db, *-store, *-index database
*-cache cache
*-queue message_queue
Everything else api_call

Frontend Dashboard

A React dashboard lives in web/ for visualizing the service graph, monitoring health, toggling failures, and testing manifest drift through a UI.

Running the Dashboard

# Terminal 1: start the backend
npm start

# Terminal 2: start the frontend dev server
cd web
npm install
npm run dev

Visit http://localhost:5173/ to see the dashboard. The Vite dev server proxies API requests to the backend on port 5000.

Dashboard Pages

Route Page Description
/ Overview Stats bar, team cards grid
/teams/:team Team Detail Service table, SVG dependency graph, failure toggles
/teams/:team/services/:key Service Detail Dependency health statuses (15s auto-refresh), failure simulation controls
/teams/:team/manifest Manifest & Drift Tabbed manifest viewer, baseline diff, drift mutation forms, overlay inspector

Frontend Tech Stack

  • Vite + React 19 + TypeScript
  • Tailwind CSS v4
  • React Router v7
  • TanStack React Query v5
  • Vitest + React Testing Library

Development

# Backend
npm run typecheck   # TypeScript compilation check
npm test            # Run Jest tests

# Frontend
cd web
npm run build       # Production build
npm test            # Run Vitest tests
npm run dev         # Dev server with HMR

Project Structure

multi-api/
├── src/
│   ├── index.ts              # Express app bootstrap
│   ├── config.ts             # Env-based configuration
│   ├── tree-generator.ts     # Algorithmic service tree generation
│   ├── team-assigner.ts      # Assigns services to teams via round-robin
│   ├── virtual-service.ts    # Factory: Router + DependencyMonitor per service
│   ├── manifest.ts           # Builds per-team manifest JSON (with aliases & overrides)
│   ├── manifest-state.ts     # Mutable overlay on baseline manifest for drift testing
│   ├── manifest-router.ts    # Express router for manifest drift mutation endpoints
│   └── otlp-pusher.ts        # Optional OTLP metrics push to Depsera
├── tests/
│   ├── tree-generator.test.ts
│   ├── team-assigner.test.ts
│   ├── virtual-service.test.ts
│   ├── manifest.test.ts
│   ├── manifest-state.test.ts
│   ├── manifest-router.test.ts
│   └── otlp-pusher.test.ts
├── web/                       # Frontend dashboard
│   ├── src/
│   │   ├── api/client.ts     # Typed fetch wrapper for all backend endpoints
│   │   ├── types/            # TypeScript types mirroring backend responses
│   │   ├── hooks/            # React Query hooks (root data, health, manifest)
│   │   ├── lib/              # Utilities (cn, manifest diff)
│   │   ├── components/
│   │   │   ├── layout/       # Sidebar, PageShell, StatusBadge
│   │   │   ├── overview/     # StatsBar, TeamCard, OverviewPage
│   │   │   ├── team/         # ServiceRow, DependencyGraph, TeamDetailPage
│   │   │   ├── service/      # HealthStatusList, FailureControls, ServiceDetailPage
│   │   │   └── manifest/     # ManifestViewer, ManifestDiff, DriftControls, forms
│   │   └── tests/            # Component tests with Vitest
│   ├── package.json
│   └── vite.config.ts
├── package.json
├── tsconfig.json
└── jest.config.ts

About

A project for simulating multiple tiers of dependent services and teams for use testing and developing Depsera.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages