health.test.ts101 lines · main
1/**
2 * /info + /ready contract tests for apps/api — pin the readiness gate
3 * logic so the matrix of (configured? × reachable?) stays testable
4 * without standing up postgres / redis. Build-identity resolution is
5 * exercised by packages/shared/src/build-identity.test.ts since the
6 * resolver lives there now.
7 */
8
9import { describe, expect, test } from 'bun:test';
10
11describe('/ready check states', () => {
12 // Mirrors the ready endpoint's check projection. Decoupling the
13 // pure logic here makes the matrix of (configured? × reachable?)
14 // testable without standing up postgres / redis.
15 function checkState(args: {
16 configured: boolean;
17 reachable: boolean;
18 }): 'ok' | 'unreachable' | 'not_configured' {
19 if (!args.configured) return 'not_configured';
20 return args.reachable ? 'ok' : 'unreachable';
21 }
22
23 test('configured + reachable → ok', () => {
24 expect(checkState({ configured: true, reachable: true })).toBe('ok');
25 });
26
27 test('configured + unreachable → unreachable', () => {
28 expect(checkState({ configured: true, reachable: false })).toBe('unreachable');
29 });
30
31 test('not configured → not_configured regardless of reachable', () => {
32 expect(checkState({ configured: false, reachable: false })).toBe('not_configured');
33 expect(checkState({ configured: false, reachable: true })).toBe('not_configured');
34 });
35});
36
37describe('redis-required readiness gate', () => {
38 // Redis is required when configured (logs streaming + rate-limit
39 // hard-depend on it) but optional in dev mode. The /ready endpoint
40 // 503s only when configured-AND-unreachable; an unconfigured deploy
41 // ack 200 to let dev workflows keep moving.
42 function isReady(args: {
43 controlOk: boolean;
44 dataOk: boolean;
45 runtimeOk: boolean;
46 redisConfigured: boolean;
47 redisOk: boolean;
48 }): boolean {
49 const required =
50 args.controlOk && args.dataOk && args.runtimeOk && (!args.redisConfigured || args.redisOk);
51 return required;
52 }
53
54 test('all healthy + redis configured ok → ready', () => {
55 expect(
56 isReady({
57 controlOk: true,
58 dataOk: true,
59 runtimeOk: true,
60 redisConfigured: true,
61 redisOk: true,
62 }),
63 ).toBe(true);
64 });
65
66 test('redis unconfigured + everything else ok → ready (dev mode)', () => {
67 expect(
68 isReady({
69 controlOk: true,
70 dataOk: true,
71 runtimeOk: true,
72 redisConfigured: false,
73 redisOk: false,
74 }),
75 ).toBe(true);
76 });
77
78 test('redis configured + unreachable → NOT ready', () => {
79 expect(
80 isReady({
81 controlOk: true,
82 dataOk: true,
83 runtimeOk: true,
84 redisConfigured: true,
85 redisOk: false,
86 }),
87 ).toBe(false);
88 });
89
90 test('control plane down → NOT ready regardless of redis', () => {
91 expect(
92 isReady({
93 controlOk: false,
94 dataOk: true,
95 runtimeOk: true,
96 redisConfigured: false,
97 redisOk: false,
98 }),
99 ).toBe(false);
100 });
101});