mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-03 00:58:24 +00:00
refactor: deduplicate push test fixtures
This commit is contained in:
@@ -21,6 +21,8 @@ vi.mock("../../infra/push-apns.js", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
type ApnsPushResult,
|
||||||
|
type ApnsRegistration,
|
||||||
clearApnsRegistrationIfCurrent,
|
clearApnsRegistrationIfCurrent,
|
||||||
loadApnsRegistration,
|
loadApnsRegistration,
|
||||||
normalizeApnsEnvironment,
|
normalizeApnsEnvironment,
|
||||||
@@ -32,6 +34,63 @@ import {
|
|||||||
|
|
||||||
type RespondCall = [boolean, unknown?, { code: number; message: string }?];
|
type RespondCall = [boolean, unknown?, { code: number; message: string }?];
|
||||||
|
|
||||||
|
const DEFAULT_DIRECT_REGISTRATION = {
|
||||||
|
nodeId: "ios-node-1",
|
||||||
|
transport: "direct",
|
||||||
|
token: "abcd",
|
||||||
|
topic: "ai.openclaw.ios",
|
||||||
|
environment: "sandbox",
|
||||||
|
updatedAtMs: 1,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const DEFAULT_RELAY_REGISTRATION = {
|
||||||
|
nodeId: "ios-node-1",
|
||||||
|
transport: "relay",
|
||||||
|
relayHandle: "relay-handle-123",
|
||||||
|
sendGrant: "send-grant-123",
|
||||||
|
installationId: "install-123",
|
||||||
|
topic: "ai.openclaw.ios",
|
||||||
|
environment: "production",
|
||||||
|
distribution: "official",
|
||||||
|
updatedAtMs: 1,
|
||||||
|
tokenDebugSuffix: "abcd1234",
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
function directRegistration(
|
||||||
|
overrides: Partial<Extract<ApnsRegistration, { transport: "direct" }>> = {},
|
||||||
|
): Extract<ApnsRegistration, { transport: "direct" }> {
|
||||||
|
return { ...DEFAULT_DIRECT_REGISTRATION, ...overrides };
|
||||||
|
}
|
||||||
|
|
||||||
|
function relayRegistration(
|
||||||
|
overrides: Partial<Extract<ApnsRegistration, { transport: "relay" }>> = {},
|
||||||
|
): Extract<ApnsRegistration, { transport: "relay" }> {
|
||||||
|
return { ...DEFAULT_RELAY_REGISTRATION, ...overrides };
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockDirectAuth() {
|
||||||
|
vi.mocked(resolveApnsAuthConfigFromEnv).mockResolvedValue({
|
||||||
|
ok: true,
|
||||||
|
value: {
|
||||||
|
teamId: "TEAM123",
|
||||||
|
keyId: "KEY123",
|
||||||
|
privateKey: "-----BEGIN PRIVATE KEY-----\nabc\n-----END PRIVATE KEY-----", // pragma: allowlist secret
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function apnsResult(overrides: Partial<ApnsPushResult>): ApnsPushResult {
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
tokenSuffix: "1234abcd",
|
||||||
|
topic: "ai.openclaw.ios",
|
||||||
|
environment: "sandbox",
|
||||||
|
transport: "direct",
|
||||||
|
...overrides,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function createInvokeParams(params: Record<string, unknown>) {
|
function createInvokeParams(params: Record<string, unknown>) {
|
||||||
const respond = vi.fn();
|
const respond = vi.fn();
|
||||||
return {
|
return {
|
||||||
@@ -85,31 +144,10 @@ describe("push.test handler", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("sends push test when registration and auth are available", async () => {
|
it("sends push test when registration and auth are available", async () => {
|
||||||
vi.mocked(loadApnsRegistration).mockResolvedValue({
|
vi.mocked(loadApnsRegistration).mockResolvedValue(directRegistration());
|
||||||
nodeId: "ios-node-1",
|
mockDirectAuth();
|
||||||
transport: "direct",
|
|
||||||
token: "abcd",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "sandbox",
|
|
||||||
updatedAtMs: 1,
|
|
||||||
});
|
|
||||||
vi.mocked(resolveApnsAuthConfigFromEnv).mockResolvedValue({
|
|
||||||
ok: true,
|
|
||||||
value: {
|
|
||||||
teamId: "TEAM123",
|
|
||||||
keyId: "KEY123",
|
|
||||||
privateKey: "-----BEGIN PRIVATE KEY-----\nabc\n-----END PRIVATE KEY-----", // pragma: allowlist secret
|
|
||||||
},
|
|
||||||
});
|
|
||||||
vi.mocked(normalizeApnsEnvironment).mockReturnValue(null);
|
vi.mocked(normalizeApnsEnvironment).mockReturnValue(null);
|
||||||
vi.mocked(sendApnsAlert).mockResolvedValue({
|
vi.mocked(sendApnsAlert).mockResolvedValue(apnsResult({}));
|
||||||
ok: true,
|
|
||||||
status: 200,
|
|
||||||
tokenSuffix: "1234abcd",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "sandbox",
|
|
||||||
transport: "direct",
|
|
||||||
});
|
|
||||||
|
|
||||||
const { respond, invoke } = createInvokeParams({
|
const { respond, invoke } = createInvokeParams({
|
||||||
nodeId: "ios-node-1",
|
nodeId: "ios-node-1",
|
||||||
@@ -137,18 +175,9 @@ describe("push.test handler", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
vi.mocked(loadApnsRegistration).mockResolvedValue({
|
vi.mocked(loadApnsRegistration).mockResolvedValue(
|
||||||
nodeId: "ios-node-1",
|
relayRegistration({ installationId: "install-1" }),
|
||||||
transport: "relay",
|
);
|
||||||
relayHandle: "relay-handle-123",
|
|
||||||
sendGrant: "send-grant-123",
|
|
||||||
installationId: "install-1",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "production",
|
|
||||||
distribution: "official",
|
|
||||||
updatedAtMs: 1,
|
|
||||||
tokenDebugSuffix: "abcd1234",
|
|
||||||
});
|
|
||||||
vi.mocked(resolveApnsRelayConfigFromEnv).mockReturnValue({
|
vi.mocked(resolveApnsRelayConfigFromEnv).mockReturnValue({
|
||||||
ok: true,
|
ok: true,
|
||||||
value: {
|
value: {
|
||||||
@@ -157,14 +186,13 @@ describe("push.test handler", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
vi.mocked(normalizeApnsEnvironment).mockReturnValue(null);
|
vi.mocked(normalizeApnsEnvironment).mockReturnValue(null);
|
||||||
vi.mocked(sendApnsAlert).mockResolvedValue({
|
vi.mocked(sendApnsAlert).mockResolvedValue(
|
||||||
ok: true,
|
apnsResult({
|
||||||
status: 200,
|
tokenSuffix: "abcd1234",
|
||||||
tokenSuffix: "abcd1234",
|
environment: "production",
|
||||||
topic: "ai.openclaw.ios",
|
transport: "relay",
|
||||||
environment: "production",
|
}),
|
||||||
transport: "relay",
|
);
|
||||||
});
|
|
||||||
|
|
||||||
const { respond, invoke } = createInvokeParams({
|
const { respond, invoke } = createInvokeParams({
|
||||||
nodeId: "ios-node-1",
|
nodeId: "ios-node-1",
|
||||||
@@ -192,32 +220,17 @@ describe("push.test handler", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("clears stale registrations after invalid token push-test failures", async () => {
|
it("clears stale registrations after invalid token push-test failures", async () => {
|
||||||
vi.mocked(loadApnsRegistration).mockResolvedValue({
|
const registration = directRegistration();
|
||||||
nodeId: "ios-node-1",
|
vi.mocked(loadApnsRegistration).mockResolvedValue(registration);
|
||||||
transport: "direct",
|
mockDirectAuth();
|
||||||
token: "abcd",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "sandbox",
|
|
||||||
updatedAtMs: 1,
|
|
||||||
});
|
|
||||||
vi.mocked(resolveApnsAuthConfigFromEnv).mockResolvedValue({
|
|
||||||
ok: true,
|
|
||||||
value: {
|
|
||||||
teamId: "TEAM123",
|
|
||||||
keyId: "KEY123",
|
|
||||||
privateKey: "-----BEGIN PRIVATE KEY-----\nabc\n-----END PRIVATE KEY-----", // pragma: allowlist secret
|
|
||||||
},
|
|
||||||
});
|
|
||||||
vi.mocked(normalizeApnsEnvironment).mockReturnValue(null);
|
vi.mocked(normalizeApnsEnvironment).mockReturnValue(null);
|
||||||
vi.mocked(sendApnsAlert).mockResolvedValue({
|
vi.mocked(sendApnsAlert).mockResolvedValue(
|
||||||
ok: false,
|
apnsResult({
|
||||||
status: 400,
|
ok: false,
|
||||||
reason: "BadDeviceToken",
|
status: 400,
|
||||||
tokenSuffix: "1234abcd",
|
reason: "BadDeviceToken",
|
||||||
topic: "ai.openclaw.ios",
|
}),
|
||||||
environment: "sandbox",
|
);
|
||||||
transport: "direct",
|
|
||||||
});
|
|
||||||
vi.mocked(shouldClearStoredApnsRegistration).mockReturnValue(true);
|
vi.mocked(shouldClearStoredApnsRegistration).mockReturnValue(true);
|
||||||
|
|
||||||
const { invoke } = createInvokeParams({
|
const { invoke } = createInvokeParams({
|
||||||
@@ -229,30 +242,13 @@ describe("push.test handler", () => {
|
|||||||
|
|
||||||
expect(clearApnsRegistrationIfCurrent).toHaveBeenCalledWith({
|
expect(clearApnsRegistrationIfCurrent).toHaveBeenCalledWith({
|
||||||
nodeId: "ios-node-1",
|
nodeId: "ios-node-1",
|
||||||
registration: {
|
registration,
|
||||||
nodeId: "ios-node-1",
|
|
||||||
transport: "direct",
|
|
||||||
token: "abcd",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "sandbox",
|
|
||||||
updatedAtMs: 1,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not clear relay registrations after invalidation-shaped failures", async () => {
|
it("does not clear relay registrations after invalidation-shaped failures", async () => {
|
||||||
vi.mocked(loadApnsRegistration).mockResolvedValue({
|
const registration = relayRegistration();
|
||||||
nodeId: "ios-node-1",
|
vi.mocked(loadApnsRegistration).mockResolvedValue(registration);
|
||||||
transport: "relay",
|
|
||||||
relayHandle: "relay-handle-123",
|
|
||||||
sendGrant: "send-grant-123",
|
|
||||||
installationId: "install-123",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "production",
|
|
||||||
distribution: "official",
|
|
||||||
updatedAtMs: 1,
|
|
||||||
tokenDebugSuffix: "abcd1234",
|
|
||||||
});
|
|
||||||
vi.mocked(resolveApnsRelayConfigFromEnv).mockReturnValue({
|
vi.mocked(resolveApnsRelayConfigFromEnv).mockReturnValue({
|
||||||
ok: true,
|
ok: true,
|
||||||
value: {
|
value: {
|
||||||
@@ -261,15 +257,15 @@ describe("push.test handler", () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
vi.mocked(normalizeApnsEnvironment).mockReturnValue(null);
|
vi.mocked(normalizeApnsEnvironment).mockReturnValue(null);
|
||||||
vi.mocked(sendApnsAlert).mockResolvedValue({
|
const result = apnsResult({
|
||||||
ok: false,
|
ok: false,
|
||||||
status: 410,
|
status: 410,
|
||||||
reason: "Unregistered",
|
reason: "Unregistered",
|
||||||
tokenSuffix: "abcd1234",
|
tokenSuffix: "abcd1234",
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "production",
|
environment: "production",
|
||||||
transport: "relay",
|
transport: "relay",
|
||||||
});
|
});
|
||||||
|
vi.mocked(sendApnsAlert).mockResolvedValue(result);
|
||||||
vi.mocked(shouldClearStoredApnsRegistration).mockReturnValue(false);
|
vi.mocked(shouldClearStoredApnsRegistration).mockReturnValue(false);
|
||||||
|
|
||||||
const { invoke } = createInvokeParams({
|
const { invoke } = createInvokeParams({
|
||||||
@@ -280,59 +276,25 @@ describe("push.test handler", () => {
|
|||||||
await invoke();
|
await invoke();
|
||||||
|
|
||||||
expect(shouldClearStoredApnsRegistration).toHaveBeenCalledWith({
|
expect(shouldClearStoredApnsRegistration).toHaveBeenCalledWith({
|
||||||
registration: {
|
registration,
|
||||||
nodeId: "ios-node-1",
|
result,
|
||||||
transport: "relay",
|
|
||||||
relayHandle: "relay-handle-123",
|
|
||||||
sendGrant: "send-grant-123",
|
|
||||||
installationId: "install-123",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "production",
|
|
||||||
distribution: "official",
|
|
||||||
updatedAtMs: 1,
|
|
||||||
tokenDebugSuffix: "abcd1234",
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
ok: false,
|
|
||||||
status: 410,
|
|
||||||
reason: "Unregistered",
|
|
||||||
tokenSuffix: "abcd1234",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "production",
|
|
||||||
transport: "relay",
|
|
||||||
},
|
|
||||||
overrideEnvironment: null,
|
overrideEnvironment: null,
|
||||||
});
|
});
|
||||||
expect(clearApnsRegistrationIfCurrent).not.toHaveBeenCalled();
|
expect(clearApnsRegistrationIfCurrent).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not clear direct registrations when push.test overrides the environment", async () => {
|
it("does not clear direct registrations when push.test overrides the environment", async () => {
|
||||||
vi.mocked(loadApnsRegistration).mockResolvedValue({
|
const registration = directRegistration();
|
||||||
nodeId: "ios-node-1",
|
vi.mocked(loadApnsRegistration).mockResolvedValue(registration);
|
||||||
transport: "direct",
|
mockDirectAuth();
|
||||||
token: "abcd",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "sandbox",
|
|
||||||
updatedAtMs: 1,
|
|
||||||
});
|
|
||||||
vi.mocked(resolveApnsAuthConfigFromEnv).mockResolvedValue({
|
|
||||||
ok: true,
|
|
||||||
value: {
|
|
||||||
teamId: "TEAM123",
|
|
||||||
keyId: "KEY123",
|
|
||||||
privateKey: "-----BEGIN PRIVATE KEY-----\nabc\n-----END PRIVATE KEY-----", // pragma: allowlist secret
|
|
||||||
},
|
|
||||||
});
|
|
||||||
vi.mocked(normalizeApnsEnvironment).mockReturnValue("production");
|
vi.mocked(normalizeApnsEnvironment).mockReturnValue("production");
|
||||||
vi.mocked(sendApnsAlert).mockResolvedValue({
|
const result = apnsResult({
|
||||||
ok: false,
|
ok: false,
|
||||||
status: 400,
|
status: 400,
|
||||||
reason: "BadDeviceToken",
|
reason: "BadDeviceToken",
|
||||||
tokenSuffix: "1234abcd",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "production",
|
environment: "production",
|
||||||
transport: "direct",
|
|
||||||
});
|
});
|
||||||
|
vi.mocked(sendApnsAlert).mockResolvedValue(result);
|
||||||
vi.mocked(shouldClearStoredApnsRegistration).mockReturnValue(false);
|
vi.mocked(shouldClearStoredApnsRegistration).mockReturnValue(false);
|
||||||
|
|
||||||
const { invoke } = createInvokeParams({
|
const { invoke } = createInvokeParams({
|
||||||
@@ -344,23 +306,8 @@ describe("push.test handler", () => {
|
|||||||
await invoke();
|
await invoke();
|
||||||
|
|
||||||
expect(shouldClearStoredApnsRegistration).toHaveBeenCalledWith({
|
expect(shouldClearStoredApnsRegistration).toHaveBeenCalledWith({
|
||||||
registration: {
|
registration,
|
||||||
nodeId: "ios-node-1",
|
result,
|
||||||
transport: "direct",
|
|
||||||
token: "abcd",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "sandbox",
|
|
||||||
updatedAtMs: 1,
|
|
||||||
},
|
|
||||||
result: {
|
|
||||||
ok: false,
|
|
||||||
status: 400,
|
|
||||||
reason: "BadDeviceToken",
|
|
||||||
tokenSuffix: "1234abcd",
|
|
||||||
topic: "ai.openclaw.ios",
|
|
||||||
environment: "production",
|
|
||||||
transport: "direct",
|
|
||||||
},
|
|
||||||
overrideEnvironment: "production",
|
overrideEnvironment: "production",
|
||||||
});
|
});
|
||||||
expect(clearApnsRegistrationIfCurrent).not.toHaveBeenCalled();
|
expect(clearApnsRegistrationIfCurrent).not.toHaveBeenCalled();
|
||||||
|
|||||||
Reference in New Issue
Block a user