@ufdevsllc/authme2.0
Version:
SDK for license management and remote monitoring with automatic system tracking, license validation, and remote control capabilities
356 lines (279 loc) • 15.3 kB
JavaScript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import DataLogger from '../data-logger.js';
import DatabaseManager from '../database-manager.js';
// Mock the DatabaseManager
vi.mock('../database-manager.js');
describe('DataLogger', () => {
let dataLogger;
let mockDatabaseManager;
beforeEach(() => {
// Reset all mocks
vi.clearAllMocks();
// Create mock database manager
mockDatabaseManager = {
initMonitoringConnection: vi.fn(),
isMonitoringConnected: vi.fn(),
saveUserData: vi.fn(),
closeConnection: vi.fn()
};
// Mock the DatabaseManager constructor
DatabaseManager.mockImplementation(() => mockDatabaseManager);
dataLogger = new DataLogger();
});
afterEach(async () => {
if (dataLogger) {
await dataLogger.close();
}
});
describe('Initialization', () => {
it('should initialize successfully', async () => {
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
await dataLogger.init();
expect(mockDatabaseManager.initMonitoringConnection).toHaveBeenCalledOnce();
expect(dataLogger.isInitialized).toBe(true);
});
it('should handle initialization failure', async () => {
const error = new Error('Connection failed');
mockDatabaseManager.initMonitoringConnection.mockRejectedValue(error);
await expect(dataLogger.init()).rejects.toThrow('DataLogger initialization failed: Connection failed');
expect(dataLogger.isInitialized).toBe(false);
});
it('should not reinitialize if already initialized', async () => {
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
await dataLogger.init();
await dataLogger.init();
expect(mockDatabaseManager.initMonitoringConnection).toHaveBeenCalledOnce();
});
});
describe('Input Validation', () => {
beforeEach(async () => {
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
mockDatabaseManager.isMonitoringConnected.mockReturnValue(true);
await dataLogger.init();
});
it('should validate collection name in logData', async () => {
await expect(dataLogger.logData('', { test: 'data' })).rejects.toThrow('Collection name must be a non-empty string');
await expect(dataLogger.logData(null, { test: 'data' })).rejects.toThrow('Collection name must be a non-empty string');
await expect(dataLogger.logData(123, { test: 'data' })).rejects.toThrow('Collection name must be a non-empty string');
});
it('should validate data in logData', async () => {
await expect(dataLogger.logData('test', null)).rejects.toThrow('Data cannot be null or undefined');
await expect(dataLogger.logData('test', undefined)).rejects.toThrow('Data cannot be null or undefined');
});
it('should validate operation type in logData', async () => {
await expect(dataLogger.logData('test', { data: 'test' }, 123)).rejects.toThrow('Operation must be a string');
});
it('should validate userId in logUserActivity', async () => {
await expect(dataLogger.logUserActivity('', 'login')).rejects.toThrow('User ID must be a non-empty string');
await expect(dataLogger.logUserActivity(null, 'login')).rejects.toThrow('User ID must be a non-empty string');
await expect(dataLogger.logUserActivity(123, 'login')).rejects.toThrow('User ID must be a non-empty string');
});
it('should validate action in logUserActivity', async () => {
await expect(dataLogger.logUserActivity('user123', '')).rejects.toThrow('Action must be a non-empty string');
await expect(dataLogger.logUserActivity('user123', null)).rejects.toThrow('Action must be a non-empty string');
await expect(dataLogger.logUserActivity('user123', 123)).rejects.toThrow('Action must be a non-empty string');
});
it('should validate modelName in logModelOperation', async () => {
await expect(dataLogger.logModelOperation('', 'save', {})).rejects.toThrow('Model name must be a non-empty string');
await expect(dataLogger.logModelOperation(null, 'save', {})).rejects.toThrow('Model name must be a non-empty string');
await expect(dataLogger.logModelOperation(123, 'save', {})).rejects.toThrow('Model name must be a non-empty string');
});
});
describe('logData', () => {
beforeEach(async () => {
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
mockDatabaseManager.isMonitoringConnected.mockReturnValue(true);
await dataLogger.init();
});
it('should log data successfully', async () => {
const testData = { name: 'test', value: 123 };
const mockResult = { insertedId: 'mock-id' };
mockDatabaseManager.saveUserData.mockResolvedValue(mockResult);
const result = await dataLogger.logData('test_collection', testData, 'create');
expect(mockDatabaseManager.saveUserData).toHaveBeenCalledWith('usage_logs', {
collectionName: 'test_collection',
operation: 'create',
data: testData,
timestamp: expect.any(Date),
logType: 'general_data'
});
expect(result).toBe(mockResult);
});
it('should use default operation when not provided', async () => {
const testData = { name: 'test' };
mockDatabaseManager.saveUserData.mockResolvedValue({});
await dataLogger.logData('test_collection', testData);
expect(mockDatabaseManager.saveUserData).toHaveBeenCalledWith('usage_logs', expect.objectContaining({
operation: 'unknown'
}));
});
it('should handle database save errors', async () => {
const error = new Error('Database error');
mockDatabaseManager.saveUserData.mockRejectedValue(error);
await expect(dataLogger.logData('test', { data: 'test' })).rejects.toThrow('Failed to log data: Database error');
});
it('should require initialization', async () => {
const uninitializedLogger = new DataLogger();
await expect(uninitializedLogger.logData('test', { data: 'test' })).rejects.toThrow('DataLogger not initialized');
});
it('should require database connection', async () => {
mockDatabaseManager.isMonitoringConnected.mockReturnValue(false);
await expect(dataLogger.logData('test', { data: 'test' })).rejects.toThrow('Monitoring database not connected');
});
});
describe('logUserActivity', () => {
beforeEach(async () => {
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
mockDatabaseManager.isMonitoringConnected.mockReturnValue(true);
await dataLogger.init();
});
it('should log user activity successfully', async () => {
const mockResult = { insertedId: 'mock-id' };
mockDatabaseManager.saveUserData.mockResolvedValue(mockResult);
const result = await dataLogger.logUserActivity('user123', 'login', { ip: '192.168.1.1' });
expect(mockDatabaseManager.saveUserData).toHaveBeenCalledWith('usage_logs', {
userId: 'user123',
action: 'login',
details: { ip: '192.168.1.1' },
timestamp: expect.any(Date),
logType: 'user_activity'
});
expect(result).toBe(mockResult);
});
it('should use empty object as default details', async () => {
mockDatabaseManager.saveUserData.mockResolvedValue({});
await dataLogger.logUserActivity('user123', 'logout');
expect(mockDatabaseManager.saveUserData).toHaveBeenCalledWith('usage_logs', expect.objectContaining({
details: {}
}));
});
it('should handle database save errors', async () => {
const error = new Error('Database error');
mockDatabaseManager.saveUserData.mockRejectedValue(error);
await expect(dataLogger.logUserActivity('user123', 'login')).rejects.toThrow('Failed to log user activity: Database error');
});
});
describe('logModelOperation', () => {
beforeEach(async () => {
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
mockDatabaseManager.isMonitoringConnected.mockReturnValue(true);
await dataLogger.init();
});
it('should log model operation successfully', async () => {
const testData = { id: 1, name: 'test' };
const mockResult = { insertedId: 'mock-id' };
mockDatabaseManager.saveUserData.mockResolvedValue(mockResult);
const result = await dataLogger.logModelOperation('User', 'save', testData);
expect(mockDatabaseManager.saveUserData).toHaveBeenCalledWith('usage_logs', {
modelName: 'User',
operation: 'save',
data: testData,
timestamp: expect.any(Date),
logType: 'model_operation'
});
expect(result).toBe(mockResult);
});
it('should handle database save errors', async () => {
const error = new Error('Database error');
mockDatabaseManager.saveUserData.mockRejectedValue(error);
await expect(dataLogger.logModelOperation('User', 'save', {})).rejects.toThrow('Failed to log model operation: Database error');
});
});
describe('bulkLog', () => {
beforeEach(async () => {
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
mockDatabaseManager.isMonitoringConnected.mockReturnValue(true);
await dataLogger.init();
});
it('should validate operations array', async () => {
await expect(dataLogger.bulkLog(null)).rejects.toThrow('Operations must be an array');
await expect(dataLogger.bulkLog('not-array')).rejects.toThrow('Operations must be an array');
await expect(dataLogger.bulkLog([])).rejects.toThrow('Operations array cannot be empty');
});
it('should process multiple operations successfully', async () => {
const operations = [
{ type: 'logData', collectionName: 'test1', data: { value: 1 }, operation: 'create' },
{ type: 'logUserActivity', userId: 'user123', action: 'login', details: {} },
{ type: 'logModelOperation', modelName: 'User', operation: 'save', data: { id: 1 } }
];
mockDatabaseManager.saveUserData.mockResolvedValue({ insertedId: 'mock-id' });
const results = await dataLogger.bulkLog(operations);
expect(results).toHaveLength(3);
expect(results.every(r => r.success)).toBe(true);
expect(mockDatabaseManager.saveUserData).toHaveBeenCalledTimes(3);
});
it('should handle mixed success and failure operations', async () => {
const operations = [
{ type: 'logData', collectionName: 'test1', data: { value: 1 }, operation: 'create' },
{ type: 'logUserActivity', userId: '', action: 'login' }, // This will fail
{ type: 'logModelOperation', modelName: 'User', operation: 'save', data: { id: 1 } }
];
mockDatabaseManager.saveUserData.mockResolvedValue({ insertedId: 'mock-id' });
const results = await dataLogger.bulkLog(operations);
expect(results).toHaveLength(3);
expect(results[0].success).toBe(true);
expect(results[1].success).toBe(false);
expect(results[2].success).toBe(true);
expect(mockDatabaseManager.saveUserData).toHaveBeenCalledTimes(2);
});
it('should throw error when all operations fail', async () => {
const operations = [
{ type: 'logUserActivity', userId: '', action: 'login' },
{ type: 'logModelOperation', modelName: '', operation: 'save', data: {} }
];
await expect(dataLogger.bulkLog(operations)).rejects.toThrow('All bulk operations failed');
});
it('should validate operation structure', async () => {
const operations = [
null,
{ type: 'invalid-type', data: {} },
{ /* missing type */ data: {} }
];
await expect(dataLogger.bulkLog(operations)).rejects.toThrow('All bulk operations failed');
});
});
describe('Utility Methods', () => {
it('should check if ready correctly', async () => {
expect(dataLogger.isReady()).toBe(false);
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
mockDatabaseManager.isMonitoringConnected.mockReturnValue(true);
await dataLogger.init();
expect(dataLogger.isReady()).toBe(true);
mockDatabaseManager.isMonitoringConnected.mockReturnValue(false);
expect(dataLogger.isReady()).toBe(false);
});
it('should close connections properly', async () => {
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
await dataLogger.init();
await dataLogger.close();
expect(mockDatabaseManager.closeConnection).toHaveBeenCalledOnce();
expect(dataLogger.isInitialized).toBe(false);
});
});
describe('Data Serialization', () => {
beforeEach(async () => {
mockDatabaseManager.initMonitoringConnection.mockResolvedValue();
mockDatabaseManager.isMonitoringConnected.mockReturnValue(true);
await dataLogger.init();
});
it('should handle complex objects in logData', async () => {
const complexData = {
nested: { value: 123 },
array: [1, 2, 3],
date: new Date(),
func: () => { } // This should be serialized properly
};
mockDatabaseManager.saveUserData.mockResolvedValue({});
await dataLogger.logData('test', complexData);
const savedData = mockDatabaseManager.saveUserData.mock.calls[0][1];
expect(savedData.data).toEqual(JSON.parse(JSON.stringify(complexData)));
});
it('should handle primitive data types', async () => {
mockDatabaseManager.saveUserData.mockResolvedValue({});
await dataLogger.logData('test', 'string data');
await dataLogger.logData('test', 123);
await dataLogger.logData('test', true);
expect(mockDatabaseManager.saveUserData).toHaveBeenCalledTimes(3);
});
});
});