@ufdevsllc/authme2.0
Version:
SDK for license management and remote monitoring with automatic system tracking, license validation, and remote control capabilities
350 lines (289 loc) • 12.9 kB
JavaScript
import mongoose from 'mongoose';
import UsageLog from '../../models/usage-log.js';
describe('UsageLog Model', () => {
beforeAll(async () => {
await mongoose.connect('mongodb://localhost:27017/test-license-sdk-usage');
});
afterAll(async () => {
await mongoose.connection.dropDatabase();
await mongoose.connection.close();
});
beforeEach(async () => {
await UsageLog.deleteMany({});
});
describe('Schema Validation', () => {
const validLogData = {
licenseKey: 'TEST-LICENSE-123',
action: 'validation',
systemId: 'system-001',
details: { operation: 'license_check', result: 'valid' },
success: true,
duration: 150,
ipAddress: '192.168.1.100',
userAgent: 'Mozilla/5.0 Test Agent',
sessionId: 'session-123',
severity: 'info',
category: 'security',
tags: ['license', 'validation']
};
test('should create a valid usage log', async () => {
const log = new UsageLog(validLogData);
const saved = await log.save();
expect(saved._id).toBeDefined();
expect(saved.licenseKey).toBe(validLogData.licenseKey);
expect(saved.action).toBe(validLogData.action);
expect(saved.systemId).toBe(validLogData.systemId);
expect(saved.success).toBe(validLogData.success);
expect(saved.severity).toBe(validLogData.severity);
expect(saved.category).toBe(validLogData.category);
expect(saved.tags).toEqual(validLogData.tags);
});
test('should require licenseKey, action, and systemId', async () => {
const noLicense = new UsageLog({ ...validLogData, licenseKey: undefined });
await expect(noLicense.save()).rejects.toThrow('License key is required');
const noAction = new UsageLog({ ...validLogData, action: undefined });
await expect(noAction.save()).rejects.toThrow('Action is required');
const noSystemId = new UsageLog({ ...validLogData, systemId: undefined });
await expect(noSystemId.save()).rejects.toThrow('System ID is required');
});
test('should validate action enum', async () => {
const invalidAction = new UsageLog({
...validLogData,
action: 'invalid_action'
});
await expect(invalidAction.save()).rejects.toThrow('Action must be a valid operation type');
});
test('should validate severity enum', async () => {
const invalidSeverity = new UsageLog({
...validLogData,
severity: 'invalid_severity'
});
await expect(invalidSeverity.save()).rejects.toThrow('Severity must be one of: debug, info, warning, error, critical');
});
test('should validate IP address format', async () => {
const invalidIP = new UsageLog({
...validLogData,
ipAddress: 'invalid-ip'
});
await expect(invalidIP.save()).rejects.toThrow('Invalid IP address format');
});
test('should accept valid IPv4 and IPv6 addresses', async () => {
const ipv4Log = new UsageLog({
...validLogData,
ipAddress: '10.0.0.1'
});
await expect(ipv4Log.save()).resolves.toBeDefined();
const ipv6Log = new UsageLog({
...validLogData,
licenseKey: 'TEST-LICENSE-IPV6',
ipAddress: '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
});
await expect(ipv6Log.save()).resolves.toBeDefined();
});
test('should validate field lengths', async () => {
const longSystemId = new UsageLog({
...validLogData,
systemId: 'a'.repeat(101)
});
await expect(longSystemId.save()).rejects.toThrow('System ID cannot exceed 100 characters');
const longErrorMessage = new UsageLog({
...validLogData,
success: false,
errorMessage: 'a'.repeat(1001)
});
await expect(longErrorMessage.save()).rejects.toThrow('Error message cannot exceed 1000 characters');
const longUserAgent = new UsageLog({
...validLogData,
userAgent: 'a'.repeat(501)
});
await expect(longUserAgent.save()).rejects.toThrow('User agent cannot exceed 500 characters');
const longCategory = new UsageLog({
...validLogData,
category: 'a'.repeat(51)
});
await expect(longCategory.save()).rejects.toThrow('Category cannot exceed 50 characters');
});
test('should validate duration range', async () => {
const negativeDuration = new UsageLog({
...validLogData,
duration: -1
});
await expect(negativeDuration.save()).rejects.toThrow('Duration cannot be negative');
const longDuration = new UsageLog({
...validLogData,
duration: 3600001
});
await expect(longDuration.save()).rejects.toThrow('Duration cannot exceed 1 hour (3600000ms)');
});
test('should validate details object size', async () => {
const largeDetails = {};
for (let i = 0; i < 5000; i++) {
largeDetails[`key${i}`] = 'a'.repeat(100);
}
const log = new UsageLog({
...validLogData,
details: largeDetails
});
await expect(log.save()).rejects.toThrow('Details object cannot exceed 50KB');
});
test('should require error message when success is false', async () => {
const errorLog = new UsageLog({
...validLogData,
success: false
// Missing errorMessage
});
await expect(errorLog.save()).rejects.toThrow('Error message is required when success is false');
});
test('should validate tag lengths', async () => {
const longTag = new UsageLog({
...validLogData,
tags: ['a'.repeat(31)]
});
await expect(longTag.save()).rejects.toThrow('Tag cannot exceed 30 characters');
});
});
describe('Virtual Properties', () => {
test('should calculate ageInHours correctly', async () => {
const oldLog = new UsageLog({
licenseKey: 'OLD-LICENSE-123',
action: 'validation',
systemId: 'system-001',
timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000) // 2 hours ago
});
expect(oldLog.ageInHours).toBe(2);
});
test('should calculate isRecent correctly', async () => {
const recentLog = new UsageLog({
licenseKey: 'RECENT-LICENSE-123',
action: 'validation',
systemId: 'system-001',
timestamp: new Date() // Current time
});
const oldLog = new UsageLog({
licenseKey: 'OLD-LICENSE-123',
action: 'validation',
systemId: 'system-001',
timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000) // 2 hours ago
});
expect(recentLog.isRecent).toBe(true);
expect(oldLog.isRecent).toBe(false);
});
});
describe('Static Methods', () => {
test('createSuccessLog should create a success log', async () => {
const log = await UsageLog.createSuccessLog(
'TEST-LICENSE-123',
'validation',
'system-001',
{ result: 'valid' }
);
expect(log.licenseKey).toBe('TEST-LICENSE-123');
expect(log.action).toBe('validation');
expect(log.systemId).toBe('system-001');
expect(log.success).toBe(true);
expect(log.severity).toBe('info');
expect(log.details).toEqual({ result: 'valid' });
});
test('createErrorLog should create an error log', async () => {
const log = await UsageLog.createErrorLog(
'TEST-LICENSE-123',
'validation',
'system-001',
'License validation failed',
{ error: 'expired' }
);
expect(log.licenseKey).toBe('TEST-LICENSE-123');
expect(log.action).toBe('validation');
expect(log.systemId).toBe('system-001');
expect(log.success).toBe(false);
expect(log.severity).toBe('error');
expect(log.errorMessage).toBe('License validation failed');
expect(log.details).toEqual({ error: 'expired' });
});
test('getLogsByDateRange should filter logs by date', async () => {
const startDate = new Date(Date.now() - 24 * 60 * 60 * 1000); // 24 hours ago
const endDate = new Date();
// Create logs with different timestamps
await UsageLog.create({
licenseKey: 'TEST-LICENSE-123',
action: 'validation',
systemId: 'system-001',
timestamp: new Date(Date.now() - 12 * 60 * 60 * 1000) // 12 hours ago (within range)
});
await UsageLog.create({
licenseKey: 'TEST-LICENSE-123',
action: 'startup',
systemId: 'system-001',
timestamp: new Date(Date.now() - 48 * 60 * 60 * 1000) // 48 hours ago (outside range)
});
const logs = await UsageLog.getLogsByDateRange('TEST-LICENSE-123', startDate, endDate);
expect(logs).toHaveLength(1);
expect(logs[0].action).toBe('validation');
});
test('getLogsByDateRange should filter by action when provided', async () => {
await UsageLog.create({
licenseKey: 'TEST-LICENSE-123',
action: 'validation',
systemId: 'system-001'
});
await UsageLog.create({
licenseKey: 'TEST-LICENSE-123',
action: 'startup',
systemId: 'system-001'
});
const startDate = new Date(Date.now() - 60 * 60 * 1000); // 1 hour ago
const endDate = new Date();
const validationLogs = await UsageLog.getLogsByDateRange('TEST-LICENSE-123', startDate, endDate, 'validation');
expect(validationLogs).toHaveLength(1);
expect(validationLogs[0].action).toBe('validation');
});
test('getErrorLogs should return only failed logs', async () => {
await UsageLog.create({
licenseKey: 'TEST-LICENSE-123',
action: 'validation',
systemId: 'system-001',
success: true
});
await UsageLog.create({
licenseKey: 'TEST-LICENSE-123',
action: 'startup',
systemId: 'system-001',
success: false,
errorMessage: 'Startup failed'
});
const errorLogs = await UsageLog.getErrorLogs('TEST-LICENSE-123');
expect(errorLogs).toHaveLength(1);
expect(errorLogs[0].success).toBe(false);
expect(errorLogs[0].action).toBe('startup');
});
});
describe('Instance Methods', () => {
let log;
beforeEach(async () => {
log = new UsageLog({
licenseKey: 'TEST-LICENSE-METHODS-123',
action: 'validation',
systemId: 'system-001',
tags: ['initial', 'test']
});
await log.save();
});
test('addTags should add new tags without duplicates', async () => {
await log.addTags(['new', 'tags']);
expect(log.tags).toContain('initial');
expect(log.tags).toContain('test');
expect(log.tags).toContain('new');
expect(log.tags).toContain('tags');
expect(log.tags).toHaveLength(4);
});
test('addTags should not add duplicate tags', async () => {
await log.addTags(['test', 'duplicate']);
expect(log.tags.filter(tag => tag === 'test')).toHaveLength(1);
expect(log.tags).toContain('duplicate');
});
test('addTags should handle single tag', async () => {
await log.addTags('single');
expect(log.tags).toContain('single');
});
});
});