session-manager-terminate-session.test.ts 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { beforeEach, describe, expect, it, vi } from "vitest";
  2. let redisClientRef: any;
  3. let pipelineRef: any;
  4. vi.mock("server-only", () => ({}));
  5. vi.mock("@/lib/logger", () => ({
  6. logger: {
  7. warn: vi.fn(),
  8. info: vi.fn(),
  9. error: vi.fn(),
  10. debug: vi.fn(),
  11. trace: vi.fn(),
  12. },
  13. }));
  14. vi.mock("@/lib/redis", () => ({
  15. getRedisClient: () => redisClientRef,
  16. }));
  17. describe("SessionManager.terminateSession", () => {
  18. beforeEach(() => {
  19. vi.resetAllMocks();
  20. vi.resetModules();
  21. pipelineRef = {
  22. del: vi.fn(() => pipelineRef),
  23. zrem: vi.fn(() => pipelineRef),
  24. exec: vi.fn(async () => [[null, 1]]),
  25. };
  26. redisClientRef = {
  27. status: "ready",
  28. get: vi.fn(async () => null),
  29. hget: vi.fn(async () => null),
  30. pipeline: vi.fn(() => pipelineRef),
  31. };
  32. });
  33. it("应同时从 global/key/user 的 active_sessions ZSET 中移除 sessionId(若可解析到 userId)", async () => {
  34. const sessionId = "sess_test";
  35. redisClientRef.get.mockImplementation(async (key: string) => {
  36. if (key === `session:${sessionId}:provider`) return "42";
  37. if (key === `session:${sessionId}:key`) return "7";
  38. return null;
  39. });
  40. redisClientRef.hget.mockImplementation(async (key: string, field: string) => {
  41. if (key === `session:${sessionId}:info` && field === "userId") return "123";
  42. return null;
  43. });
  44. const { getGlobalActiveSessionsKey, getKeyActiveSessionsKey, getUserActiveSessionsKey } =
  45. await import("@/lib/redis/active-session-keys");
  46. const { SessionManager } = await import("@/lib/session-manager");
  47. const ok = await SessionManager.terminateSession(sessionId);
  48. expect(ok).toBe(true);
  49. expect(redisClientRef.hget).toHaveBeenCalledWith(`session:${sessionId}:info`, "userId");
  50. expect(pipelineRef.zrem).toHaveBeenCalledWith(getGlobalActiveSessionsKey(), sessionId);
  51. expect(pipelineRef.zrem).toHaveBeenCalledWith("provider:42:active_sessions", sessionId);
  52. expect(pipelineRef.zrem).toHaveBeenCalledWith(getKeyActiveSessionsKey(7), sessionId);
  53. expect(pipelineRef.zrem).toHaveBeenCalledWith(getUserActiveSessionsKey(123), sessionId);
  54. });
  55. it("当 userId 不可用时,不应尝试 zrem user active_sessions key", async () => {
  56. const sessionId = "sess_test";
  57. redisClientRef.get.mockImplementation(async (key: string) => {
  58. if (key === `session:${sessionId}:provider`) return "42";
  59. if (key === `session:${sessionId}:key`) return "7";
  60. return null;
  61. });
  62. redisClientRef.hget.mockResolvedValue(null);
  63. const { getUserActiveSessionsKey } = await import("@/lib/redis/active-session-keys");
  64. const { SessionManager } = await import("@/lib/session-manager");
  65. const ok = await SessionManager.terminateSession(sessionId);
  66. expect(ok).toBe(true);
  67. expect(pipelineRef.zrem).not.toHaveBeenCalledWith(getUserActiveSessionsKey(123), sessionId);
  68. });
  69. });