diff --git a/.gitea/workflows/DRBv3_tests.yaml b/.gitea/workflows/DRBv3_tests.yaml new file mode 100644 index 0000000..985090c --- /dev/null +++ b/.gitea/workflows/DRBv3_tests.yaml @@ -0,0 +1,58 @@ +name: DRB Tests + +on: + pull_request: + branches: + - master + push: + branches: + - master + +env: + NODE_ENV: development + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: admin + MONGO_INITDB_DATABASE: drb + SERVER_PORT: 3000 + MONGO_URL: "mongodb://mongodb:27017/drb" + DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }} + +jobs: + drb_mocha_tests: + runs-on: ubuntu-latest + + services: + mongodb: + image: mongo:latest + ports: + - 27017:27017 + options: >- + --health-cmd mongo + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Remove package-lock.json + run: rm package-lock.json + + - name: Install Node-GYP + run: npm install -g node-gyp + + - name: Install dependencies + run: npm install + + - run: echo "Node has finished installing dependencies" + + - name: Run Server tests + run: npm test + + - run: echo "Completed the DRB tests" \ No newline at end of file diff --git a/test/socketServerWrappers.test.js b/test/socketServerWrappers.test.js index 04caf89..b9caeec 100644 --- a/test/socketServerWrappers.test.js +++ b/test/socketServerWrappers.test.js @@ -3,6 +3,7 @@ import { expect } from 'chai'; import ioClient from 'socket.io-client'; import { deleteNodeByNuid, getNodeByNuid } from '../modules/mongoNodesWrappers.mjs'; import { deleteSystemByName, getSystemByName } from '../modules/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'; @@ -56,38 +57,37 @@ const updatedLocalNodeConfig = { } }; -// Start the Socket.IO server before running tests -let clientSocket; // The socket client -let serverClientSocket // The open client socket on the server -before(done => { - // Startup the node server - nodeIo.listen(process.env.SERVER_PORT || 3000, () => { - console.log(`server running at http://localhost:${process.env.SERVER_PORT}`); +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 + before(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(); + }) }); - // Connect a client socket to the server - clientSocket = ioClient.connect(`http://localhost:${process.env.SERVER_PORT}`); + // Close the Socket.IO server after running tests + after(async () => { + // Disconnect client socket + clientSocket.disconnect(); - nodeIo.on('connection', (socket) => { - serverClientSocket = socket; - done(); - }) -}); + // Close the server + nodeIo.close(); -// Close the Socket.IO server after running tests -after(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]) -}); - -describe('Node Core Server Tests', () => { + // 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 () => { @@ -269,7 +269,7 @@ describe('Node Core Server Tests', () => { // Get the updated system const updatedSystem = await getSystemByName("Testing P25 System Name"); - + console.log("Updated system:", updatedSystem); expect(updatedSystem).to.have.property('_id'); // Check if _id property exists @@ -281,10 +281,214 @@ describe('Node Core Server Tests', () => { }); }); - describe('Node Disconnect', () => { - it('Should trigger cleanup actions upon socket disconnection', async () => { - // Write test code to simulate a socket disconnection - // Check if the appropriate cleanup actions are triggered + // Test getNodeCurrentListeningSystem + describe('Get Node Current Listening System', () => { + it('Should return the current listening system for the node', async () => { + // Simulate that the client socket is listening to a system + const listeningSystem = 'Testing P25 System Name'; + + // Emit the event to the server and wait for the response + const nodeReply = new Promise((resolve) => { + clientSocket.once('node-check-current-system', (callback) => { + // Simulate receiving the current listening system from the client + callback(listeningSystem); + }); + + // Call the function to get the current listening system + const currentSystem = getNodeCurrentListeningSystem(serverClientSocket); + resolve(currentSystem); + }); + + // Wait for the promise to resolve + const currentSystem = await nodeReply; + + // Assert that the current system matches the expected listening system + expect(currentSystem).to.equal(listeningSystem); }); - }) + }); + + // 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).to.equal(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).to.equal(guildId); + // Simulate receiving the Discord username from the client + callback(discordUsername); + }); + + // Call the function to get the Discord username + const response = getNodeDiscordUsername(serverClientSocket, guildId); + resolve(response); + }); + + // Wait for the promise to resolve + const response = await nodeReply; + + // Assert that the response matches the expected Discord username + expect(response).to.equal(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).to.equal(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).to.equal(token); + expect(joinData.channelID).to.equal(channelId); + expect(joinData.system).to.equal(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).to.equal(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); + 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).to.be.undefined; + }); + }); }); \ No newline at end of file