Skip to content

Commit f9cd70d

Browse files
committed
test: coverage and test cases
1 parent 32b69e5 commit f9cd70d

File tree

2 files changed

+287
-45
lines changed

2 files changed

+287
-45
lines changed

.github/workflows/test.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Publish to npm
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v2
13+
- uses: actions/setup-node@v2
14+
with:
15+
node-version: '18.x'
16+
registry-url: 'https://registry.npmjs.org'
17+
- run: npm install
18+
19+
# Run tests and generate coverage report
20+
- run: npm test -- --coverage
21+
continue-on-error: false
22+
23+
# Send the coverage report to Coveralls
24+
- run: npm install coveralls --save-dev
25+
- run: cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
26+
env:
27+
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_POSTGRES_TOKEN }}

tests/index.test.js

Lines changed: 260 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ describe('ErrsolePostgres', () => {
3737

3838
poolMock = {
3939
connect: jest.fn().mockResolvedValue(clientMock),
40-
query: jest.fn().mockResolvedValue({ rows: [{ work_mem: '8192kB' }] })
40+
query: jest.fn().mockImplementation((query, values) => {
41+
if (query.includes('SHOW work_mem')) {
42+
return Promise.resolve({ rows: [{ work_mem: '8192kB' }] }); // Mock for getWorkMem
43+
}
44+
if (query.includes('INSERT INTO')) {
45+
return Promise.resolve({ rows: [{ id: 1 }] }); // Mock for createUser
46+
}
47+
return Promise.resolve({ rows: [] });
48+
})
4149
};
4250

4351
Pool.mockImplementation(() => poolMock);
@@ -1098,65 +1106,65 @@ describe('ErrsolePostgres', () => {
10981106
});
10991107
});
11001108

1101-
describe('#ensureLogsTTL', () => {
1102-
let getConfigSpy;
1103-
let setConfigSpy; it('should handle query errors during user password update', async () => {
1104-
const user = { id: 1, name: 'test', email: 'test@example.com', hashed_password: 'hashedPassword', role: 'admin' };
1105-
poolMock.query
1106-
.mockResolvedValueOnce({ rows: [user] }) // First query response
1107-
.mockRejectedValueOnce(new Error('Query error')); // Second query response
1108-
bcrypt.compare.mockResolvedValue(true);
1109-
bcrypt.hash.mockResolvedValue('newHashedPassword');
1109+
// describe('#ensureLogsTTL', () => {
1110+
// let getConfigSpy;
1111+
// let setConfigSpy; it('should handle query errors during user password update', async () => {
1112+
// const user = { id: 1, name: 'test', email: 'test@example.com', hashed_password: 'hashedPassword', role: 'admin' };
1113+
// poolMock.query
1114+
// .mockResolvedValueOnce({ rows: [user] }) // First query response
1115+
// .mockRejectedValueOnce(new Error('Query error')); // Second query response
1116+
// bcrypt.compare.mockResolvedValue(true);
1117+
// bcrypt.hash.mockResolvedValue('newHashedPassword');
11101118

1111-
await expect(errsolePostgres.updatePassword('test@example.com', 'password', 'newPassword')).rejects.toThrow('Query error');
1112-
});
1119+
// await expect(errsolePostgres.updatePassword('test@example.com', 'password', 'newPassword')).rejects.toThrow('Query error');
1120+
// });
11131121

1114-
beforeEach(() => {
1115-
getConfigSpy = jest.spyOn(errsolePostgres, 'getConfig');
1116-
setConfigSpy = jest.spyOn(errsolePostgres, 'setConfig').mockResolvedValue({ item: { key: 'logsTTL', value: '2592000000' } });
1117-
});
1122+
// beforeEach(() => {
1123+
// getConfigSpy = jest.spyOn(errsolePostgres, 'getConfig');
1124+
// setConfigSpy = jest.spyOn(errsolePostgres, 'setConfig').mockResolvedValue({ item: { key: 'logsTTL', value: '2592000000' } });
1125+
// });
11181126

1119-
afterEach(() => {
1120-
jest.clearAllMocks();
1121-
});
1127+
// afterEach(() => {
1128+
// jest.clearAllMocks();
1129+
// });
11221130

1123-
it('should set default logsTTL if config does not exist', async () => {
1124-
getConfigSpy.mockResolvedValueOnce({ item: null });
1131+
// it('should set default logsTTL if config does not exist', async () => {
1132+
// getConfigSpy.mockResolvedValueOnce({ item: null });
11251133

1126-
await errsolePostgres.ensureLogsTTL();
1134+
// await errsolePostgres.ensureLogsTTL();
11271135

1128-
expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1129-
expect(setConfigSpy).toHaveBeenCalledWith('logsTTL', '2592000000');
1130-
});
1136+
// expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1137+
// expect(setConfigSpy).toHaveBeenCalledWith('logsTTL', '2592000000');
1138+
// });
11311139

1132-
it('should not set logsTTL if config already exists', async () => {
1133-
getConfigSpy.mockResolvedValueOnce({ item: { key: 'logsTTL', value: '2592000000' } });
1140+
// it('should not set logsTTL if config already exists', async () => {
1141+
// getConfigSpy.mockResolvedValueOnce({ item: { key: 'logsTTL', value: '2592000000' } });
11341142

1135-
await errsolePostgres.ensureLogsTTL();
1143+
// await errsolePostgres.ensureLogsTTL();
11361144

1137-
expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1138-
expect(setConfigSpy).not.toHaveBeenCalled();
1139-
});
1145+
// expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1146+
// expect(setConfigSpy).not.toHaveBeenCalled();
1147+
// });
11401148

1141-
it('should handle errors in getting configuration', async () => {
1142-
getConfigSpy.mockRejectedValueOnce(new Error('Query error'));
1149+
// it('should handle errors in getting configuration', async () => {
1150+
// getConfigSpy.mockRejectedValueOnce(new Error('Query error'));
11431151

1144-
await expect(errsolePostgres.ensureLogsTTL()).rejects.toThrow('Query error');
1152+
// await expect(errsolePostgres.ensureLogsTTL()).rejects.toThrow('Query error');
11451153

1146-
expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1147-
expect(setConfigSpy).not.toHaveBeenCalled();
1148-
});
1154+
// expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1155+
// expect(setConfigSpy).not.toHaveBeenCalled();
1156+
// });
11491157

1150-
it('should handle errors in setting configuration', async () => {
1151-
getConfigSpy.mockResolvedValueOnce({ item: null });
1152-
setConfigSpy.mockRejectedValueOnce(new Error('Query error'));
1158+
// it('should handle errors in setting configuration', async () => {
1159+
// getConfigSpy.mockResolvedValueOnce({ item: null });
1160+
// setConfigSpy.mockRejectedValueOnce(new Error('Query error'));
11531161

1154-
await expect(errsolePostgres.ensureLogsTTL()).rejects.toThrow('Query error');
1162+
// await expect(errsolePostgres.ensureLogsTTL()).rejects.toThrow('Query error');
11551163

1156-
expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1157-
expect(setConfigSpy).toHaveBeenCalledWith('logsTTL', '2592000000');
1158-
});
1159-
});
1164+
// expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1165+
// expect(setConfigSpy).toHaveBeenCalledWith('logsTTL', '2592000000');
1166+
// });
1167+
// });
11601168

11611169
describe('#getHostnames', () => {
11621170
let poolQuerySpy;
@@ -1472,6 +1480,213 @@ describe('ErrsolePostgres', () => {
14721480
expect(poolQuerySpy).toHaveBeenCalledWith('TRUNCATE TABLE errsole_logs_v3 RESTART IDENTITY CASCADE');
14731481
});
14741482
});
1483+
1484+
describe('#searchLogs', () => {
1485+
let poolQuerySpy;
1486+
1487+
beforeEach(() => {
1488+
poolQuerySpy = jest.spyOn(poolMock, 'query');
1489+
});
1490+
1491+
afterEach(() => {
1492+
jest.clearAllMocks();
1493+
});
1494+
1495+
it('should retrieve logs with no filters and search terms', async () => {
1496+
const logs = [
1497+
{ id: 1, hostname: 'localhost', pid: 1234, source: 'test', timestamp: new Date(), level: 'info', message: 'test message' }
1498+
];
1499+
poolMock.query.mockResolvedValueOnce({ rows: logs });
1500+
1501+
const result = await errsolePostgres.searchLogs();
1502+
1503+
expect(poolMock.query).toHaveBeenCalledWith(expect.stringContaining('SELECT id, hostname, pid, source, timestamp, level, message,errsole_id'), expect.any(Array));
1504+
expect(result.items).toEqual(logs.reverse());
1505+
});
1506+
1507+
it('should apply search terms filter', async () => {
1508+
const logs = [{ id: 1, message: 'error occurred' }];
1509+
const searchTerms = ['error', 'occurred'];
1510+
poolMock.query.mockResolvedValueOnce({ rows: logs });
1511+
1512+
const result = await errsolePostgres.searchLogs(searchTerms);
1513+
1514+
expect(poolMock.query).toHaveBeenCalledWith(expect.stringContaining('message_tsv @@ phraseto_tsquery'), expect.arrayContaining(searchTerms));
1515+
expect(result.items).toEqual(logs.reverse());
1516+
});
1517+
1518+
it('should apply hostnames filter', async () => {
1519+
const logs = [{ id: 2, hostname: 'server1' }];
1520+
const filters = { hostnames: ['server1', 'server2'] };
1521+
poolMock.query.mockResolvedValueOnce({ rows: logs });
1522+
1523+
const result = await errsolePostgres.searchLogs([], filters);
1524+
1525+
expect(poolMock.query).toHaveBeenCalledWith(expect.stringContaining('hostname = ANY'), expect.arrayContaining([['server1', 'server2']]));
1526+
expect(result.items).toEqual(logs.reverse());
1527+
});
1528+
1529+
it('should apply level_json and errsole_id filters', async () => {
1530+
const logs = [{ id: 3, source: 'app', level: 'error', errsole_id: 123 }];
1531+
const filters = {
1532+
level_json: [{ source: 'app', level: 'error' }],
1533+
errsole_id: 123
1534+
};
1535+
poolMock.query.mockResolvedValueOnce({ rows: logs });
1536+
1537+
const result = await errsolePostgres.searchLogs([], filters);
1538+
1539+
expect(poolMock.query).toHaveBeenCalledWith(expect.stringContaining('(source = $'), expect.arrayContaining(['app', 'error', 123]));
1540+
expect(result.items).toEqual(logs.reverse());
1541+
});
1542+
1543+
it('should apply lt_id filter and order logs correctly', async () => {
1544+
const logs = [{ id: 4, message: 'test log' }];
1545+
const filters = { lt_id: 10 };
1546+
poolMock.query.mockResolvedValueOnce({ rows: logs });
1547+
1548+
const result = await errsolePostgres.searchLogs([], filters);
1549+
1550+
expect(poolMock.query).toHaveBeenCalledWith(expect.stringContaining('id < $'), expect.arrayContaining([10]));
1551+
expect(result.items).toEqual(logs.reverse());
1552+
});
1553+
1554+
it('should apply gt_id filter and order logs correctly', async () => {
1555+
const logs = [{ id: 5, message: 'new log' }];
1556+
const filters = { gt_id: 5 };
1557+
poolMock.query.mockResolvedValueOnce({ rows: logs });
1558+
1559+
const result = await errsolePostgres.searchLogs([], filters);
1560+
1561+
expect(poolMock.query).toHaveBeenCalledWith(expect.stringContaining('id > $'), expect.arrayContaining([5]));
1562+
expect(result.items).toEqual(logs);
1563+
});
1564+
1565+
it('should apply timestamp filters and adjust missing gte_timestamp or lte_timestamp', async () => {
1566+
const logs = [{ id: 6, timestamp: new Date() }];
1567+
const filters = { lte_timestamp: new Date('2023-01-01T00:00:00Z') };
1568+
const expectedGteTimestamp = new Date(filters.lte_timestamp.getTime() - 24 * 60 * 60 * 1000);
1569+
1570+
poolMock.query.mockResolvedValueOnce({ rows: logs });
1571+
1572+
const result = await errsolePostgres.searchLogs([], filters);
1573+
1574+
expect(poolMock.query).toHaveBeenCalledWith(expect.stringContaining('timestamp <= $'), expect.arrayContaining([filters.lte_timestamp, expectedGteTimestamp]));
1575+
expect(result.items).toEqual(logs.reverse());
1576+
});
1577+
1578+
it('should apply gte_timestamp and auto-set lte_timestamp if missing', async () => {
1579+
const logs = [{ id: 7, timestamp: new Date() }];
1580+
const filters = { gte_timestamp: new Date('2023-01-01T00:00:00Z') };
1581+
const expectedLteTimestamp = new Date(filters.gte_timestamp.getTime() + 24 * 60 * 60 * 1000);
1582+
1583+
poolMock.query.mockResolvedValueOnce({ rows: logs });
1584+
1585+
const result = await errsolePostgres.searchLogs([], filters);
1586+
1587+
expect(poolMock.query).toHaveBeenCalledWith(expect.stringContaining('timestamp >= $'), expect.arrayContaining([filters.gte_timestamp, expectedLteTimestamp]));
1588+
expect(result.items).toEqual(logs.reverse());
1589+
});
1590+
1591+
it('should handle errors during search query execution', async () => {
1592+
poolMock.query.mockRejectedValueOnce(new Error('Query error'));
1593+
1594+
await expect(errsolePostgres.searchLogs()).rejects.toThrow('Query error');
1595+
});
1596+
});
1597+
1598+
describe('#createUser', () => {
1599+
it('should create a new user successfully', async () => {
1600+
const user = { name: 'John', email: 'john@example.com', password: 'password123', role: 'admin' };
1601+
const hashedPassword = 'hashedPassword';
1602+
1603+
bcrypt.hash.mockResolvedValueOnce(hashedPassword);
1604+
poolMock.query.mockResolvedValueOnce({ rows: [{ id: 1 }] });
1605+
1606+
const result = await errsolePostgres.createUser(user);
1607+
1608+
expect(bcrypt.hash).toHaveBeenCalledWith(user.password, 10);
1609+
expect(poolMock.query).toHaveBeenCalledWith(
1610+
expect.stringContaining('INSERT INTO'),
1611+
expect.arrayContaining([user.name, user.email, hashedPassword, user.role])
1612+
);
1613+
expect(result).toEqual({ item: { id: 1, name: user.name, email: user.email, role: user.role } });
1614+
});
1615+
1616+
it('should throw an error if database query fails unexpectedly', async () => {
1617+
const user = { name: 'Jane', email: 'jane@example.com', password: 'securepass', role: 'user' };
1618+
const hashedPassword = 'hashedPassword';
1619+
1620+
bcrypt.hash.mockResolvedValueOnce(hashedPassword);
1621+
const originalQueryMock = poolMock.query;
1622+
poolMock.query = jest.fn().mockImplementation((query, values) => {
1623+
if (query.includes('INSERT INTO')) {
1624+
return Promise.reject(new Error('Database error'));
1625+
}
1626+
return originalQueryMock(query, values);
1627+
});
1628+
1629+
await expect(errsolePostgres.createUser(user)).rejects.toThrow('Database error');
1630+
1631+
expect(bcrypt.hash).toHaveBeenCalledWith(user.password, 10);
1632+
expect(poolMock.query).toHaveBeenCalledWith(
1633+
expect.stringContaining('INSERT INTO'),
1634+
expect.arrayContaining([user.name, user.email, hashedPassword, user.role])
1635+
);
1636+
poolMock.query = originalQueryMock;
1637+
});
1638+
});
1639+
1640+
describe('#ensureLogsTTL', () => {
1641+
let getConfigSpy, setConfigSpy;
1642+
1643+
beforeEach(() => {
1644+
getConfigSpy = jest.spyOn(errsolePostgres, 'getConfig').mockResolvedValue({ item: { key: 'logsTTL', value: '2592000000' } });
1645+
setConfigSpy = jest.spyOn(errsolePostgres, 'setConfig').mockResolvedValue({ item: { key: 'logsTTL', value: '2592000000' } });
1646+
});
1647+
1648+
afterEach(() => {
1649+
jest.clearAllMocks();
1650+
});
1651+
1652+
it('should set logsTTL to default if it does not exist', async () => {
1653+
getConfigSpy.mockResolvedValueOnce({ item: null });
1654+
1655+
await errsolePostgres.ensureLogsTTL();
1656+
1657+
expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1658+
expect(setConfigSpy).toHaveBeenCalledWith('logsTTL', (30 * 24 * 60 * 60 * 1000).toString());
1659+
});
1660+
1661+
it('should not update logsTTL if it already exists', async () => {
1662+
getConfigSpy.mockResolvedValueOnce({ item: { key: 'logsTTL', value: '2592000000' } });
1663+
1664+
await errsolePostgres.ensureLogsTTL();
1665+
1666+
expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1667+
expect(setConfigSpy).not.toHaveBeenCalled(); // ✅ Now this should pass
1668+
});
1669+
1670+
it('should handle errors in getConfig', async () => {
1671+
getConfigSpy.mockRejectedValueOnce(new Error('Query error'));
1672+
1673+
await expect(errsolePostgres.ensureLogsTTL()).rejects.toThrow('Query error');
1674+
1675+
expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1676+
expect(setConfigSpy).not.toHaveBeenCalled(); // ✅ Now this should pass
1677+
});
1678+
1679+
it('should handle errors in setConfig when logsTTL does not exist', async () => {
1680+
getConfigSpy.mockResolvedValueOnce({ item: null });
1681+
setConfigSpy.mockRejectedValueOnce(new Error('Insert error'));
1682+
1683+
await expect(errsolePostgres.ensureLogsTTL()).rejects.toThrow('Insert error');
1684+
1685+
expect(getConfigSpy).toHaveBeenCalledWith('logsTTL');
1686+
expect(setConfigSpy).toHaveBeenCalledWith('logsTTL', (30 * 24 * 60 * 60 * 1000).toString());
1687+
});
1688+
});
1689+
14751690
afterAll(() => {
14761691
cronJob.stop();
14771692
clearInterval(errsolePostgres.flushIntervalId);

0 commit comments

Comments
 (0)