- Gate both Redis ingestion paths (canonical + legacy) behind separate default-off flags (GROW_EVENTS_REDIS_ENABLED, LEGACY_SERVICE_REDIS_ENABLED). The redis module is never imported when both flags are off. - Sever legacy URL cascade: interview/roleplay/resume/courses Redis URLs resolve ONLY from their own explicit env vars, never from REDIS_URL or GROW_EVENTS_REDIS_URL. - Export resolveRedisConfig() pure resolver for testability. - Fix onboarding signal ID from 'onboarding.completed_baseline' to 'onboarding.completed' (registry-valid in all v2 formula JSONs). - Ensure interview/roleplay completed events emit at least a single completion signal when session_count/scenario_count is absent (default 1). - Extract computeStreakFromDays() into streak-utils.ts (pure, no DB dep) with defensive dedup so duplicate days never inflate streaks. - Add focused tests: redis-gating, signal-registry membership, count fallback, streak policy (current/longest/duplicate/gap/recovery/7-day), service-ingest projector behavior. - typecheck: 80 pre-existing errors unchanged, 0 new.
113 lines
3.6 KiB
TypeScript
113 lines
3.6 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { resolveRedisConfig } from "../src/config.js";
|
|
|
|
/**
|
|
* Test: Redis ingestion consumers are default-off and do not load the Redis
|
|
* module unless an explicit opt-in flag is set. Legacy URLs must not inherit
|
|
* from the generic REDIS_URL.
|
|
*
|
|
* Uses the pure resolveRedisConfig resolver with synthetic env objects — no
|
|
* module-cache hacks needed.
|
|
*/
|
|
|
|
// ── 1. Default-off: no Redis flags set ──────────────────────────────────────
|
|
{
|
|
const rc = resolveRedisConfig({});
|
|
|
|
assert.equal(
|
|
rc.growEventsRedisEnabled,
|
|
false,
|
|
"GROW_EVENTS_REDIS_ENABLED must default to false",
|
|
);
|
|
assert.equal(
|
|
rc.legacyServiceRedisEnabled,
|
|
false,
|
|
"LEGACY_SERVICE_REDIS_ENABLED must default to false",
|
|
);
|
|
}
|
|
|
|
// ── 2. Legacy URLs must NOT inherit from generic REDIS_URL ──────────────────
|
|
{
|
|
// Set ONLY the generic REDIS_URL — legacy URLs must not pick it up.
|
|
const rc = resolveRedisConfig({ REDIS_URL: "redis://legacy-generic:6379" });
|
|
|
|
assert.equal(
|
|
rc.interviewRedisUrl,
|
|
"",
|
|
"interviewRedisUrl must NOT inherit from generic REDIS_URL",
|
|
);
|
|
assert.equal(
|
|
rc.roleplayRedisUrl,
|
|
"",
|
|
"roleplayRedisUrl must NOT inherit from generic REDIS_URL",
|
|
);
|
|
assert.equal(
|
|
rc.resumeRedisUrl,
|
|
"",
|
|
"resumeRedisUrl must NOT inherit from generic REDIS_URL",
|
|
);
|
|
assert.equal(
|
|
rc.coursesRedisUrl,
|
|
"",
|
|
"coursesRedisUrl must NOT inherit from generic REDIS_URL",
|
|
);
|
|
}
|
|
|
|
// ── 3. Legacy URLs must NOT inherit from GROW_EVENTS_REDIS_URL ───────────────
|
|
{
|
|
const rc = resolveRedisConfig({ GROW_EVENTS_REDIS_URL: "redis://canonical:6379" });
|
|
|
|
assert.equal(
|
|
rc.interviewRedisUrl,
|
|
"",
|
|
"interviewRedisUrl must NOT inherit from GROW_EVENTS_REDIS_URL",
|
|
);
|
|
assert.equal(rc.growEventsRedisUrl, "redis://canonical:6379", "canonical URL resolves from its own var");
|
|
}
|
|
|
|
// ── 4. Explicit opt-in flags are respected ──────────────────────────────────
|
|
{
|
|
const rc = resolveRedisConfig({ GROW_EVENTS_REDIS_ENABLED: "true" });
|
|
|
|
assert.equal(
|
|
rc.growEventsRedisEnabled,
|
|
true,
|
|
"GROW_EVENTS_REDIS_ENABLED=true must be respected",
|
|
);
|
|
assert.equal(
|
|
rc.legacyServiceRedisEnabled,
|
|
false,
|
|
"legacy must stay off when only canonical flag is set",
|
|
);
|
|
}
|
|
|
|
// ── 5. Legacy opt-in flag works independently ───────────────────────────────
|
|
{
|
|
const rc = resolveRedisConfig({
|
|
LEGACY_SERVICE_REDIS_ENABLED: "true",
|
|
INTERVIEW_REDIS_URL: "redis://interview:6379",
|
|
});
|
|
|
|
assert.equal(rc.legacyServiceRedisEnabled, true, "LEGACY_SERVICE_REDIS_ENABLED=true must be respected");
|
|
assert.equal(rc.growEventsRedisEnabled, false, "canonical must stay off when only legacy flag is set");
|
|
assert.equal(rc.interviewRedisUrl, "redis://interview:6379", "explicit interview URL resolves");
|
|
}
|
|
|
|
// ── 6. Explicit legacy URLs resolve from their own vars ──────────────────────
|
|
{
|
|
const rc = resolveRedisConfig({
|
|
INTERVIEW_REDIS_URL: "redis://i:6379",
|
|
ROLEPLAY_REDIS_URL: "redis://r:6379",
|
|
RESUME_REDIS_URL: "redis://re:6379",
|
|
COURSES_REDIS_URL: "redis://c:6379",
|
|
});
|
|
|
|
assert.equal(rc.interviewRedisUrl, "redis://i:6379");
|
|
assert.equal(rc.roleplayRedisUrl, "redis://r:6379");
|
|
assert.equal(rc.resumeRedisUrl, "redis://re:6379");
|
|
assert.equal(rc.coursesRedisUrl, "redis://c:6379");
|
|
}
|
|
|
|
console.log("redis-gating tests passed");
|
|
process.exit(0);
|