release(main): 同步 dev 最新候选改动
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (push) Has been cancelled
Client Quality Gates / Shared client and Web (push) Has been cancelled
Client Quality Gates / macOS Desktop (push) Has been cancelled
Client Quality Gates / Shared client and Web (pull_request) Has been cancelled
Client Quality Gates / macOS Desktop (pull_request) Has been cancelled
Storage Persistence Guard / storage-persistence-audit (pull_request) Has been cancelled
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { UserLoginActivity } from "../../types/api";
|
||||
import { activitySourceKey, groupLoginActivitiesBySource } from "./loginActivitySources";
|
||||
|
||||
const activity = (overrides: Partial<UserLoginActivity>): UserLoginActivity => ({
|
||||
id: "session-1",
|
||||
client_type: "web",
|
||||
client_platform: "macos",
|
||||
client_version: "0.1.0",
|
||||
login_ip: "192.168.97.1",
|
||||
login_at: "2026-07-16T02:23:04Z",
|
||||
last_seen_at: "2026-07-16T03:08:32Z",
|
||||
activity_status: "ENDED",
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe("login activity sources", () => {
|
||||
it("uses only client type and a recorded IP as the source identity", () => {
|
||||
expect(activitySourceKey(activity({ client_platform: "windows", client_source: "installer" }))).toBe(
|
||||
"web|192.168.97.1",
|
||||
);
|
||||
expect(activitySourceKey(activity({ id: "legacy", login_ip: null }))).toBe("session:legacy");
|
||||
});
|
||||
|
||||
it("merges online and historical sessions from the same client and IP", () => {
|
||||
const rows = groupLoginActivitiesBySource(
|
||||
[
|
||||
activity({
|
||||
id: "current",
|
||||
login_at: "2026-07-16T07:22:42Z",
|
||||
last_seen_at: "2026-07-16T07:53:00Z",
|
||||
activity_status: "ONLINE",
|
||||
ended_at: null,
|
||||
}),
|
||||
activity({ id: "history", ended_at: "2026-07-16T03:08:32Z" }),
|
||||
activity({
|
||||
id: "desktop",
|
||||
client_type: "desktop",
|
||||
login_at: "2026-07-15T08:42:02Z",
|
||||
last_seen_at: "2026-07-16T07:53:42Z",
|
||||
activity_status: "ONLINE",
|
||||
ended_at: null,
|
||||
}),
|
||||
],
|
||||
(item) => item.activity_status!,
|
||||
);
|
||||
|
||||
expect(rows).toHaveLength(2);
|
||||
expect(rows[0]).toMatchObject({ id: "desktop", grouped_count: 1, activity_status: "ONLINE" });
|
||||
expect(rows[1]).toMatchObject({
|
||||
id: "current",
|
||||
grouped_count: 2,
|
||||
login_at: "2026-07-16T02:23:04Z",
|
||||
last_seen_at: "2026-07-16T07:53:00Z",
|
||||
activity_status: "ONLINE",
|
||||
ended_at: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not merge sessions whose IP was not recorded", () => {
|
||||
const rows = groupLoginActivitiesBySource(
|
||||
[activity({ id: "legacy-1", login_ip: null }), activity({ id: "legacy-2", login_ip: null })],
|
||||
(item) => item.activity_status!,
|
||||
);
|
||||
|
||||
expect(rows).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user