keys-limit-validation.test.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { beforeEach, describe, expect, it, vi } from "vitest";
  2. const getSessionMock = vi.fn();
  3. vi.mock("@/lib/auth", () => ({
  4. getSession: getSessionMock,
  5. }));
  6. vi.mock("next/cache", () => ({
  7. revalidatePath: vi.fn(),
  8. }));
  9. const getTranslationsMock = vi.fn(async () => (key: string) => key);
  10. vi.mock("next-intl/server", () => ({
  11. getTranslations: getTranslationsMock,
  12. }));
  13. const createKeyMock = vi.fn(async () => ({}));
  14. const findActiveKeyByUserIdAndNameMock = vi.fn(async () => null);
  15. const findKeyByIdMock = vi.fn();
  16. const findKeyListMock = vi.fn(async () => []);
  17. const updateKeyMock = vi.fn(async () => ({}));
  18. vi.mock("@/repository/key", () => ({
  19. countActiveKeysByUser: vi.fn(async () => 1),
  20. createKey: createKeyMock,
  21. deleteKey: vi.fn(async () => true),
  22. findActiveKeyByUserIdAndName: findActiveKeyByUserIdAndNameMock,
  23. findKeyById: findKeyByIdMock,
  24. findKeyList: findKeyListMock,
  25. findKeysWithStatistics: vi.fn(async () => []),
  26. updateKey: updateKeyMock,
  27. }));
  28. const findUserByIdMock = vi.fn();
  29. vi.mock("@/repository/user", async (importOriginal) => {
  30. const actual = await importOriginal<typeof import("@/repository/user")>();
  31. return {
  32. ...actual,
  33. findUserById: findUserByIdMock,
  34. };
  35. });
  36. const syncUserProviderGroupFromKeysMock = vi.fn(async () => undefined);
  37. vi.mock("@/actions/users", () => ({
  38. syncUserProviderGroupFromKeys: syncUserProviderGroupFromKeysMock,
  39. }));
  40. describe("keys limit validation", () => {
  41. let baseUser: Record<string, unknown>;
  42. beforeEach(() => {
  43. vi.clearAllMocks();
  44. getSessionMock.mockResolvedValue({ user: { id: 1, role: "admin" } });
  45. baseUser = {
  46. id: 10,
  47. name: "u",
  48. description: "",
  49. role: "user",
  50. rpm: null,
  51. dailyQuota: null,
  52. providerGroup: "default",
  53. tags: [],
  54. limit5hUsd: null,
  55. dailyResetMode: "fixed",
  56. dailyResetTime: "00:00",
  57. limitWeeklyUsd: null,
  58. limitMonthlyUsd: null,
  59. limitTotalUsd: null,
  60. limitConcurrentSessions: 2,
  61. isEnabled: true,
  62. expiresAt: null,
  63. allowedClients: [],
  64. allowedModels: [],
  65. createdAt: new Date(),
  66. updatedAt: new Date(),
  67. deletedAt: null,
  68. };
  69. findUserByIdMock.mockResolvedValue(baseUser);
  70. findKeyByIdMock.mockResolvedValue({
  71. id: 1,
  72. userId: 10,
  73. key: "sk-test",
  74. name: "k",
  75. isEnabled: true,
  76. expiresAt: null,
  77. canLoginWebUi: true,
  78. limit5hUsd: null,
  79. limitDailyUsd: null,
  80. dailyResetMode: "fixed",
  81. dailyResetTime: "00:00",
  82. limitWeeklyUsd: null,
  83. limitMonthlyUsd: null,
  84. limitTotalUsd: null,
  85. limitConcurrentSessions: 0,
  86. providerGroup: "default",
  87. cacheTtlPreference: null,
  88. createdAt: new Date(),
  89. updatedAt: new Date(),
  90. deletedAt: null,
  91. });
  92. });
  93. it("addKey:key 并发超过用户并发时应拦截", async () => {
  94. const { addKey } = await import("@/actions/keys");
  95. const result = await addKey({
  96. userId: 10,
  97. name: "k1",
  98. limitConcurrentSessions: 3,
  99. providerGroup: "default",
  100. });
  101. expect(result.ok).toBe(false);
  102. if (!result.ok) {
  103. expect(result.error).toBe("KEY_LIMIT_CONCURRENT_EXCEEDS_USER_LIMIT");
  104. }
  105. expect(createKeyMock).not.toHaveBeenCalled();
  106. });
  107. it("addKey:用户并发为 0 时不应限制 key 并发", async () => {
  108. const { addKey } = await import("@/actions/keys");
  109. findUserByIdMock.mockResolvedValueOnce({ ...baseUser, limitConcurrentSessions: 0 });
  110. const result = await addKey({
  111. userId: 10,
  112. name: "k1",
  113. limitConcurrentSessions: 3,
  114. providerGroup: "default",
  115. });
  116. expect(result.ok).toBe(true);
  117. expect(createKeyMock).toHaveBeenCalledTimes(1);
  118. });
  119. it("editKey:key 并发超过用户并发时应拦截", async () => {
  120. const { editKey } = await import("@/actions/keys");
  121. const result = await editKey(1, {
  122. name: "k1",
  123. providerGroup: "default",
  124. limitConcurrentSessions: 3,
  125. });
  126. expect(result.ok).toBe(false);
  127. if (!result.ok) {
  128. expect(result.error).toBe("KEY_LIMIT_CONCURRENT_EXCEEDS_USER_LIMIT");
  129. }
  130. expect(updateKeyMock).not.toHaveBeenCalled();
  131. });
  132. });