rwadurian/backend/services/presence-service/test/unit/domain/services/online-detection.service.sp...

121 lines
4.5 KiB
TypeScript

import { OnlineDetectionService } from '../../../../src/domain/services/online-detection.service';
import { TimeWindow } from '../../../../src/domain/value-objects/time-window.vo';
describe('OnlineDetectionService', () => {
let service: OnlineDetectionService;
beforeEach(() => {
service = new OnlineDetectionService();
});
describe('isOnline', () => {
it('should return true for recent heartbeat', () => {
const now = new Date();
const recentTimestamp = Math.floor(now.getTime() / 1000) - 60; // 60 seconds ago
expect(service.isOnline(recentTimestamp, now)).toBe(true);
});
it('should return true for heartbeat within window', () => {
const now = new Date();
const withinWindow = Math.floor(now.getTime() / 1000) - 179; // 179 seconds ago (within 180 window)
expect(service.isOnline(withinWindow, now)).toBe(true);
});
it('should return false for heartbeat at window boundary', () => {
const now = new Date();
const atBoundary = Math.floor(now.getTime() / 1000) - 180; // Exactly 180 seconds ago
expect(service.isOnline(atBoundary, now)).toBe(false);
});
it('should return false for old heartbeat', () => {
const now = new Date();
const oldTimestamp = Math.floor(now.getTime() / 1000) - 300; // 5 minutes ago
expect(service.isOnline(oldTimestamp, now)).toBe(false);
});
it('should return false for very old heartbeat', () => {
const now = new Date();
const veryOldTimestamp = Math.floor(now.getTime() / 1000) - 3600; // 1 hour ago
expect(service.isOnline(veryOldTimestamp, now)).toBe(false);
});
it('should return true for heartbeat just now', () => {
const now = new Date();
const justNow = Math.floor(now.getTime() / 1000);
expect(service.isOnline(justNow, now)).toBe(true);
});
it('should use current time when no time provided', () => {
const justNow = Math.floor(Date.now() / 1000);
expect(service.isOnline(justNow)).toBe(true);
});
});
describe('getOnlineThreshold', () => {
it('should return correct threshold timestamp', () => {
const now = new Date('2025-01-01T12:00:00.000Z');
const threshold = service.getOnlineThreshold(now);
const expectedTimestamp = Math.floor(now.getTime() / 1000) - TimeWindow.DEFAULT_ONLINE_WINDOW_SECONDS;
expect(threshold).toBe(expectedTimestamp);
});
it('should use current time when no time provided', () => {
const beforeCall = Math.floor(Date.now() / 1000) - TimeWindow.DEFAULT_ONLINE_WINDOW_SECONDS;
const threshold = service.getOnlineThreshold();
const afterCall = Math.floor(Date.now() / 1000) - TimeWindow.DEFAULT_ONLINE_WINDOW_SECONDS;
expect(threshold).toBeGreaterThanOrEqual(beforeCall);
expect(threshold).toBeLessThanOrEqual(afterCall);
});
});
describe('getWindowSeconds', () => {
it('should return default window seconds', () => {
expect(service.getWindowSeconds()).toBe(TimeWindow.DEFAULT_ONLINE_WINDOW_SECONDS);
});
it('should return 180 seconds', () => {
expect(service.getWindowSeconds()).toBe(180);
});
});
describe('integration scenarios', () => {
it('should correctly determine online status for multiple users', () => {
const now = new Date();
const nowTimestamp = Math.floor(now.getTime() / 1000);
const users = [
{ id: 1, lastHeartbeat: nowTimestamp - 30, expectedOnline: true }, // 30s ago
{ id: 2, lastHeartbeat: nowTimestamp - 90, expectedOnline: true }, // 90s ago
{ id: 3, lastHeartbeat: nowTimestamp - 150, expectedOnline: true }, // 150s ago
{ id: 4, lastHeartbeat: nowTimestamp - 180, expectedOnline: false }, // 180s ago (boundary)
{ id: 5, lastHeartbeat: nowTimestamp - 200, expectedOnline: false }, // 200s ago
];
users.forEach((user) => {
expect(service.isOnline(user.lastHeartbeat, now)).toBe(user.expectedOnline);
});
});
it('should work correctly with getOnlineThreshold', () => {
const now = new Date();
const threshold = service.getOnlineThreshold(now);
// Users with timestamp > threshold should be online
expect(service.isOnline(threshold + 1, now)).toBe(true);
// Users with timestamp <= threshold should be offline
expect(service.isOnline(threshold, now)).toBe(false);
expect(service.isOnline(threshold - 1, now)).toBe(false);
});
});
});