symbolRegistry.test.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { describe, it, expect, vi } from "vitest";
  2. import { SymbolRegistry } from "../packages/registry/src/symbolRegistry";
  3. import type { SymbolConfig, SymbolRuntimeState } from "../packages/registry/src/types";
  4. function createConfig(overrides: Partial<SymbolConfig> = {}): SymbolConfig {
  5. return {
  6. symbol: overrides.symbol ?? "BTC",
  7. maxNotional: overrides.maxNotional ?? 100_000,
  8. maxBase: overrides.maxBase ?? 1,
  9. enabled: overrides.enabled,
  10. tags: overrides.tags,
  11. metadata: overrides.metadata
  12. };
  13. }
  14. function createState(overrides: Partial<SymbolRuntimeState> = {}): SymbolRuntimeState {
  15. return {
  16. config: overrides.config ?? createConfig({ symbol: "BTC" }),
  17. status: overrides.status ?? "inactive",
  18. updatedAt: overrides.updatedAt ?? Date.now(),
  19. reason: overrides.reason,
  20. allocation: overrides.allocation,
  21. score: overrides.score
  22. };
  23. }
  24. describe("SymbolRegistry", () => {
  25. it("registers symbols and emits lifecycle events", () => {
  26. const registry = new SymbolRegistry();
  27. const onRegister = vi.fn();
  28. registry.on("registered", onRegister);
  29. const state = registry.register(createConfig({ symbol: "ETH" }));
  30. expect(state.status).toBe("inactive");
  31. expect(registry.get("ETH")).toBe(state);
  32. expect(onRegister).toHaveBeenCalledTimes(1);
  33. expect(onRegister).toHaveBeenCalledWith(state);
  34. });
  35. it("applies enabled=false as disabled status", () => {
  36. const registry = new SymbolRegistry();
  37. const state = registry.register(createConfig({ symbol: "SOL", enabled: false }));
  38. expect(state.status).toBe("disabled");
  39. });
  40. it("updates configuration and tracks allocation/score", () => {
  41. const registry = new SymbolRegistry();
  42. registry.register(createConfig({ symbol: "BTC" }));
  43. const updated = registry.updateConfig("BTC", { maxNotional: 200_000 });
  44. expect(updated.config.maxNotional).toBe(200_000);
  45. const allocation = { notionalLimit: 50_000, baseLimit: 0.5 };
  46. const scored = registry.setAllocation("BTC", allocation);
  47. expect(scored.allocation).toEqual(allocation);
  48. registry.setScore("BTC", 0.8);
  49. expect(registry.get("BTC")?.score).toBeCloseTo(0.8);
  50. });
  51. it("changes status and emits statusChanged events", () => {
  52. const registry = new SymbolRegistry();
  53. const onStatus = vi.fn();
  54. registry.on("statusChanged", onStatus);
  55. registry.register(createConfig({ symbol: "BTC" }));
  56. const activated = registry.activate("BTC");
  57. expect(activated.status).toBe("active");
  58. registry.pause("BTC", "volatility");
  59. expect(registry.get("BTC")?.status).toBe("paused");
  60. expect(registry.get("BTC")?.reason).toBe("volatility");
  61. registry.disable("BTC", "maintenance");
  62. expect(registry.get("BTC")?.status).toBe("disabled");
  63. expect(onStatus).toHaveBeenCalledTimes(3);
  64. });
  65. it("lists states by status and removes symbols", () => {
  66. const registry = new SymbolRegistry();
  67. registry.register(createConfig({ symbol: "BTC" }));
  68. registry.register(createConfig({ symbol: "ETH" }));
  69. registry.activate("BTC");
  70. const active = registry.list("active");
  71. expect(active).toHaveLength(1);
  72. expect(active[0].config.symbol).toBe("BTC");
  73. const inactive = registry.list("inactive");
  74. expect(inactive).toHaveLength(1);
  75. expect(inactive[0].config.symbol).toBe("ETH");
  76. const onRemoved = vi.fn();
  77. registry.on("removed", onRemoved);
  78. registry.remove("ETH");
  79. expect(registry.get("ETH")).toBeUndefined();
  80. expect(onRemoved).toHaveBeenCalledWith({ symbol: "ETH" });
  81. });
  82. });