diff --git a/package.json b/package.json index 1ab0952..d3ba374 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "server.js", "scripts": { - "test": "mocha --timeout 5000", + "test": "jasmine", "start": "node server.js" }, "author": "Logan Cusano", diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json new file mode 100644 index 0000000..6afe603 --- /dev/null +++ b/spec/support/jasmine.json @@ -0,0 +1,13 @@ +{ + "spec_dir": "spec", + "spec_files": [ + "**/*[sS]pec.?(m)js" + ], + "helpers": [ + "helpers/**/*.?(m)js" + ], + "env": { + "stopSpecOnExpectationFailure": false, + "random": true + } +} diff --git a/spec/test/rssManager.spec.js.b b/spec/test/rssManager.spec.js.b new file mode 100644 index 0000000..89943dd --- /dev/null +++ b/spec/test/rssManager.spec.js.b @@ -0,0 +1,29 @@ +import * as feedHandler from '../../rss-manager/feedHandler.mjs'; +import * as mw from '../../modules/mongo-wrappers/mongoFeedsWrappers.mjs'; +import * as drw from '../../discordBot/modules/rssWrappers.mjs'; + +describe('feedHandler', () => { + it('should call updateFeeds', async () => { + // Spy on the updateFeeds function + const feedsSpy = spyOn(mw, 'getAllFeeds').and.stub(); + const sendPostSpy = spyOn(drw, 'sendPost').and.stub(); + + // Call the function that triggers updateFeeds + // For example: + // someFunctionThatCallsUpdateFeeds(); + console.log(await spyOn(feedHandler, 'updateFeeds').and.callThrough({ + channels: { + cache: { + get: () => ([{ + // Stub methods or properties of the channel object as needed for testing + }]) + } + } + })); + + // Add your expectations here to ensure updateFeeds was called + expect(feedsSpy).toHaveBeenCalled(); + expect(sendPostSpy).toHaveBeenCalled(); + // Add more specific expectations if needed + }); +}); diff --git a/spec/test/socketServerWrappers.spec.js b/spec/test/socketServerWrappers.spec.js new file mode 100644 index 0000000..f1542b2 --- /dev/null +++ b/spec/test/socketServerWrappers.spec.js @@ -0,0 +1,494 @@ +// Import necessary modules for testing +import ioClient from 'socket.io-client'; +import { deleteNodeByNuid, getNodeByNuid } from '../../modules/mongo-wrappers/mongoNodesWrappers.mjs'; +import { deleteSystemByName, getSystemByName } from '../../modules/mongo-wrappers/mongoSystemsWrappers.mjs'; +import { nodeDisconnectWrapper, checkIfNodeHasOpenDiscordClient, getNodeCurrentListeningSystem, checkIfNodeIsConnectedToVC, getNodeDiscordUsername, getNodeDiscordID, requestBotLeaveServer, requestNodeJoinSystem, requestNodeUpdate } from '../../modules/socketServerWrappers.mjs'; +import { nodeIo } from '../../modules/socketServer.mjs'; + +import dotenv from 'dotenv'; +dotenv.config() + +process.env.SERVER_PORT = 6000 + +// Define necessary variables for testing, such as mocked database connections or socket instances +const localNodeConfig = { + serverIp: 'localhost', + serverPort: process.env.SERVER_PORT, + node: { + nuid: "4f29a6340901a12affc87047c0ac16b01b92496c460c880a2459abe8c7928374", + name: "testyv7", + location: "china", + capabilities: ["radio"] + }, + nearbySystems: { + "Testing P25 System Name": { + "frequencies": [ + 155344000, + 155444000, + 155555000, + 155588550 + ], + "mode": "p25", + "trunkFile": "trunk.tsv", + "whitelistFile": "whitelist.tsv" + } + } +}; + +const updatedLocalNodeConfig = { + node: { + nuid: localNodeConfig.node.nuid, + name: "updatedName", + location: "updatedLocation", + capabilities: ["radio", "weather"] // Updated capabilities + }, + nearbySystems: { + "Testing P25 System Name": { + "frequencies": [ + 155444000, + 155555000, + 155500000 + ], + "mode": "p25", + "trunkFile": "trunk2.tsv", + "whitelistFile": "whitelist2.tsv" + } + } +}; + +describe('Socket Server - Core Tests', () => { + // Start the Socket.IO server before running tests + let clientSocket; // The socket client + let serverClientSocket // The open client socket on the server + beforeAll(done => { + // Startup the node server + nodeIo.listen(process.env.SERVER_PORT || 3000, () => { + console.log(`server running at http://localhost:${process.env.SERVER_PORT}`); + }); + + // Connect a client socket to the server + clientSocket = ioClient.connect(`http://localhost:${process.env.SERVER_PORT}`); + + nodeIo.on('connection', (socket) => { + serverClientSocket = socket; + done(); + }) + }); + + // Close the Socket.IO server after running tests + afterAll(async () => { + // Disconnect client socket + clientSocket.disconnect(); + + // Close the server + nodeIo.close(); + + // Remove the test data + deleteNodeByNuid(localNodeConfig.node.nuid); // Delete the user + deleteSystemByName(Object.keys(localNodeConfig.nearbySystems)[0]) + }); + // Test Node Login functionality + describe('Node Login', () => { + it('Should add a new node if it does not exist', async () => { + // Simulate a node login request + // Use the getNodeByNuid mock function to simulate checking if node exists + const existingNode = await getNodeByNuid(localNodeConfig.node.nuid); + + // Assert that existingNode is null before node login + expect(existingNode).toEqual(null); + + // Wait for the update + const node_login = new Promise(res => { + clientSocket.on('node-login-successful', async () => { + res(); + }); + }); + + // Emit the login command + clientSocket.emit("node-login", localNodeConfig.node); + + // Wait for the successful login event + await node_login; + + // Now we need to check if the node is added to the database + // We can use getNodeByNuid again to verify if the node was added correctly + const addedNode = await getNodeByNuid(localNodeConfig.node.nuid); + + console.log("Added Node:", addedNode); + + // Assert that the node is added correctly + expect(addedNode['_id']).toBeDefined(); // Check if _id property exists + expect(addedNode['nuid']).toEqual(localNodeConfig.node.nuid); + expect(addedNode['name']).toEqual(localNodeConfig.node.name); + expect(addedNode['location']).toEqual(localNodeConfig.node.location); + expect(addedNode['capabilities']).toEqual(localNodeConfig.node.capabilities); + }) + it('Should update a node if it exists', async () => { + // Simulate a node login request + // Use the getNodeByNuid mock function to simulate checking if node exists + const existingNode = await getNodeByNuid(localNodeConfig.node.nuid); + + // Assert that existingNode is matches the existing data before logging in + expect(existingNode['_id']).toBeDefined(); // Check if _id property exists + expect(existingNode['nuid']).toEqual(localNodeConfig.node.nuid); + expect(existingNode['name']).toEqual(localNodeConfig.node.name); + expect(existingNode['location']).toEqual(localNodeConfig.node.location); + expect(existingNode['capabilities']).toEqual(localNodeConfig.node.capabilities); + + // Wait for the update + const node_login = new Promise(res => { + clientSocket.on('node-login-successful', async () => { + res(); + }); + }); + + // Emit the login command + clientSocket.emit("node-login", updatedLocalNodeConfig.node); + + // Wait for the successful login event + await node_login; + + // Now we need to check if the node is added to the database + // We can use getNodeByNuid again to verify if the node was added correctly + const updatedNode = await getNodeByNuid(localNodeConfig.node.nuid); + + console.log("Updated Node:", updatedNode); + + // Assert that the node is added correctly + expect(updatedNode['_id']).toBeDefined(); // Check if _id property exists + expect(updatedNode['nuid']).toEqual(updatedLocalNodeConfig.node.nuid); + expect(updatedNode['name']).toEqual(updatedLocalNodeConfig.node.name); + expect(updatedNode['location']).toEqual(updatedLocalNodeConfig.node.location); + expect(updatedNode['capabilities']).toEqual(updatedLocalNodeConfig.node.capabilities); + }) + }); + + // Test Node Update functionality + describe('Node Update', () => { + it('Should add a node\'s nearby systems', async () => { + // Simulate an update request sent from the client to the server + + // Get the existing node in the database + const existingNode = await getNodeByNuid(localNodeConfig.node.nuid); + + // Assert that existingNode matches the updatedLocalNodeConfig + expect(existingNode['_id']).toBeDefined(); // Check if _id property exists + expect(existingNode['nuid']).toEqual(updatedLocalNodeConfig.node.nuid); + expect(existingNode['name']).toEqual(updatedLocalNodeConfig.node.name); + expect(existingNode['location']).toEqual(updatedLocalNodeConfig.node.location); + expect(existingNode['capabilities']).toEqual(updatedLocalNodeConfig.node.capabilities); + + // Get the system from the DB + const existsingSystem = await getSystemByName("Testing P25 System Name"); + + // Assert that there is no existing system in the DB + expect(existsingSystem).toEqual(null); + + // Wait for the update + const node_system_update = new Promise(res => { + clientSocket.on('node-update-successful', async () => { + res(); + }); + }); + + // Emit the update command + clientSocket.emit("node-update", updatedLocalNodeConfig); + + // Wait for the successful update event + await node_system_update; + + // Now we need to check if the system is added to the database + // We can use getNodeByNuid again to verify if the node was added correctly + const updatedNode = await getNodeByNuid(localNodeConfig.node.nuid); + + console.log("Updated Node:", updatedNode); + + // Assert that the node is added correctly + expect(updatedNode['_id']).toBeDefined(); // Check if _id property exists + expect(updatedNode['nuid']).toEqual(updatedLocalNodeConfig.node.nuid); + expect(updatedNode['name']).toEqual(updatedLocalNodeConfig.node.name); + expect(updatedNode['location']).toEqual(updatedLocalNodeConfig.node.location); + expect(updatedNode['capabilities']).toEqual(updatedLocalNodeConfig.node.capabilities); + + // Get the updated system + const addedSystem = await getSystemByName("Testing P25 System Name"); + + console.log("Added system:", addedSystem); + + expect(addedSystem['_id']).toBeDefined(); // Check if _id property exists + expect(addedSystem['nodes']).toBeDefined(); // Check if nodes property exists + expect(addedSystem.nodes).toEqual(updatedLocalNodeConfig.node.nuid) // Check if this node ID is in the nodes array + expect(addedSystem['frequencies']).toEqual(updatedLocalNodeConfig.nearbySystems['Testing P25 System Name'].frequencies); + expect(addedSystem['mode']).toEqual(updatedLocalNodeConfig.nearbySystems['Testing P25 System Name'].mode); + }); + + it('should update a node and its nearby systems', async () => { + // Get the existing node in the database + const existingNode = await getNodeByNuid(localNodeConfig.node.nuid); + + // Assert that existingNode matches the updatedLocalNodeConfig + expect(existingNode['_id']).toBeDefined(); // Check if _id property exists + expect(existingNode['nuid']).toEqual(updatedLocalNodeConfig.node.nuid); + expect(existingNode['name']).toEqual(updatedLocalNodeConfig.node.name); + expect(existingNode['location']).toEqual(updatedLocalNodeConfig.node.location); + expect(existingNode['capabilities']).toEqual(updatedLocalNodeConfig.node.capabilities); + + // Get the updated system + const existingSystem = await getSystemByName("Testing P25 System Name"); + expect(existingSystem['_id']).toBeDefined(); // Check if _id property exists + expect(existingSystem['nodes']).toBeDefined(); // Check if nodes property exists + expect(existingSystem.nodes).toContain(updatedLocalNodeConfig.node.nuid); // Check if this node ID is in the nodes array + expect(existingSystem['frequencies']).toEqual(updatedLocalNodeConfig.nearbySystems['Testing P25 System Name'].frequencies); + expect(existingSystem['mode']).toEqual(updatedLocalNodeConfig.nearbySystems['Testing P25 System Name'].mode); + + // Wait for the update + const node_update = new Promise(res => { + clientSocket.on('node-update-successful', async () => { + res(); + }); + }); + + // Emit the update command + clientSocket.emit("node-update", localNodeConfig); + + // Wait for the successful update event + await node_update; + + const updatedNode = await getNodeByNuid(localNodeConfig.node.nuid); + + console.log("Updated Node:", updatedNode); + + // Assert that the node is added correctly + expect(updatedNode['_id']).toBeDefined(); // Check if _id property exists + expect(updatedNode['nuid']).toEqual(localNodeConfig.node.nuid); + expect(updatedNode['name']).toEqual(localNodeConfig.node.name); + expect(updatedNode['location']).toEqual(localNodeConfig.node.location); + expect(updatedNode['capabilities']).toEqual(localNodeConfig.node.capabilities); + + // Get the updated system + const updatedSystem = await getSystemByName("Testing P25 System Name"); + + console.log("Updated system:", updatedSystem); + + expect(updatedSystem['_id']).toBeDefined(); // Check if _id property exists + expect(updatedSystem['nodes']).toBeDefined(); // Check if nodes property exists + expect(updatedSystem.nodes).toContain(localNodeConfig.node.nuid); // Check if this node ID is in the nodes array + expect(updatedSystem['frequencies']).toEqual(localNodeConfig.nearbySystems['Testing P25 System Name'].frequencies); + expect(updatedSystem['mode']).toEqual(localNodeConfig.nearbySystems['Testing P25 System Name'].mode); + }); + }); + + // Test getNodeCurrentListeningSystem + describe('Get Node Current Listening System', () => { + it('should correctly determine if the node is connected to a voice channel', async () => { + // Simulate that the client socket is listening to a system + const isConnectedToVC = true; + const guildId = 'mockGuildId'; + + // Emit the event to the server and wait for the response + const nodeReply = new Promise((resolve) => { + clientSocket.once('node-check-connected-status', (passedGuildId, callback) => { + // Check if the passed guild ID matches the expected guild ID + expect(passedGuildId).toEqual(guildId); + // Simulate receiving the connection status from the client + callback(isConnectedToVC); + }); + + // Call the function to check if the node is connected to a voice channel + const response = checkIfNodeIsConnectedToVC(nodeIo, guildId, localNodeConfig.node.nuid); + resolve(response); + }); + + // Wait for the promise to resolve + const response = await nodeReply; + + // Assert that the response matches the expected connection status + expect(response).toEqual(isConnectedToVC); + }); + }); + + // Test checkIfNodeIsConnectedToVC + describe('Check if Node is Connected to VC', () => { + it('Should correctly determine if the node is connected to a voice channel', async () => { + // Simulate that the client socket is listening to a system + const isConnectedToVC = true; + const guildId = 'mockGuildId'; + + // Emit the event to the server and wait for the response + const nodeReply = new Promise((resolve) => { + clientSocket.once('node-check-connected-status', (passedGuildId, callback) => { + // Check if the passed guild ID matches the expected guild ID + expect(passedGuildId).to.equal(guildId); + // Simulate receiving the connection status from the client + callback(isConnectedToVC); + }); + + // Call the function to check if the node is connected to a voice channel + const response = checkIfNodeIsConnectedToVC(nodeIo, guildId, localNodeConfig.node.nuid); + resolve(response); + }); + + // Wait for the promise to resolve + const response = await nodeReply; + + // Assert that the response matches the expected connection status + expect(response).to.equal(isConnectedToVC); + }); + }); + + // Test checkIfNodeHasOpenDiscordClient + describe('Check if Node has an open discord client', () => { + it('should correctly determine if the node has an open Discord client', async () => { + const isDiscordOpen = true; + + // Emit the event to the server and wait for the response + const nodeReply = new Promise((resolve) => { + clientSocket.once('node-check-discord-open-client', (callback) => { + // Simulate receiving the client status from the client + callback(isDiscordOpen); + }); + + // Call the function to check if the node has an open Discord client + const response = checkIfNodeHasOpenDiscordClient(serverClientSocket); + resolve(response); + }); + + // Wait for the promise to resolve + const response = await nodeReply; + + // Assert that the response matches the expected client status + expect(response).toEqual(isDiscordOpen); + }); + }); + + // Test getNodeDiscordUsername + describe('Get the discord username from the client', () => { + it('should request the username from a specific client', async () => { + const discordUsername = "Test Discord Username"; + const guildId = 'mockGuildId'; + + // Emit the event to the server and wait for the response + const nodeReply = new Promise((resolve) => { + clientSocket.once('node-get-discord-username', (passedGuildId, callback) => { + // Check if the passed guild ID matches the expected guild ID + expect(passedGuildId).toEqual(guildId); + // Simulate receiving the username from the client + callback(discordUsername); + }); + + // Call the function to get the Discord username + const username = getNodeDiscordUsername(nodeIo, guildId, localNodeConfig.node.nuid); + resolve(username); + }); + + // Wait for the promise to resolve + const username = await nodeReply; + + // Assert that the username matches the expected username + expect(username).toEqual(discordUsername); + }); + }); + + // Test getNodeDiscordID + describe('Get the discord ID from the client', () => { + it('Should get the ID from the client', async () => { + // Mocked Discord ID + const discordId = "mockDiscordID"; + + // Emit the event to the server and wait for the response + const nodeReply = new Promise((resolve) => { + // Listen for the 'node-get-discord-id' event from the server + clientSocket.once('node-get-discord-id', (callback) => { + // Simulate receiving the Discord ID from the client + callback(discordId); + }); + + // Call the function to get the Discord ID + const response = getNodeDiscordID(serverClientSocket); + resolve(response); + }); + + // Wait for the promise to resolve + const response = await nodeReply; + + // Assert that the response matches the expected Discord ID + expect(response).toEqual(discordId); + }); + }); + + // Test requestNodeJoinSystem + describe('Request Node Join System', () => { + it('Should send a request to the node to join a system', async () => { + const systemName = 'mockSystemName'; + const channelId = 'mockChannelId'; + const token = 'mockToken'; + + // Emit the event to the server and wait for the response + await new Promise(async (resolve) => { + clientSocket.once('node-join', (joinData) => { + // Check if the passed system ID matches the expected system ID + expect(joinData.clientID).toEqual(token); + expect(joinData.channelID).toEqual(channelId); + expect(joinData.system).toEqual(systemName); + // Simulate receiving a success callback from the client + resolve(); + }); + + // Call the function to request joining a system + requestNodeJoinSystem(serverClientSocket, systemName, channelId, token); + }); + }); + }); + + // Test requestNodeLeaveSystem + describe('Request Node Leave System', () => { + it('Should send a request to the node to leave a given server', async () => { + const guildId = 'mockGuildId'; + + // Emit the event to the server and wait for the response + await new Promise(async (resolve) => { + clientSocket.once('node-leave', (passedGuildId) => { + // Check if the passed system ID matches the expected system ID + expect(passedGuildId).toEqual(guildId); + // Simulate receiving a success callback from the client + resolve(); + }); + + // Call the function to request joining a system + requestBotLeaveServer(serverClientSocket, guildId); + }); + }); + }); + + // Test requestNodeUpdate + describe('Request Node Update', () => { + it('Should send the node a request to check for an update', async () => { + // Emit the event to the server and wait for the response + await new Promise((resolve) => { + clientSocket.once('node-request-update', (callback) => { + // Simulate an out of date request + expect(callback).toBeDefined(); + callback(true); + }); + + // Call the function to request updating node information + const response = requestNodeUpdate(serverClientSocket); + resolve(response); + }); + }); + }); + + // Test nodeDisconnectWrapper + describe('Node Disconnect Wrapper', () => { + it('Should disconnect the node and trigger cleanup actions', async () => { + // Mock the socket ID + const socketId = 'mockSocketId'; + + // Call the nodeDisconnectWrapper function + const result = await nodeDisconnectWrapper(socketId); + + // Assert that the result is as expected (if any) + expect(result).toBeUndefined(); + }); + }); +}); \ No newline at end of file