diff --git a/package.json b/package.json index 5d8942619..fe4a20898 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "helmet": "3.21.2", "jsonschema": "1.2.5", "jsonwebtoken": "8.5.1", - "lodash": "4.17.15", + "lodash": "^4.17.15", "moment": "2.24.0", "mongoose": "5.8.9", "nestjs-typegoose": "7.0.0", @@ -59,7 +59,7 @@ "@types/jasmine": "3.5.1", "@types/jsonschema": "1.1.1", "@types/jsonwebtoken": "8.3.5", - "@types/lodash": "4.14.149", + "@types/lodash": "^4.14.149", "@types/mongoose": "5.5.43", "@types/node": "12.12.21", "@types/passport": "1.0.2", diff --git a/src/games/services/server-configurator.service.spec.ts b/src/games/services/server-configurator.service.spec.ts index 1b2162bd8..bab814d17 100644 --- a/src/games/services/server-configurator.service.spec.ts +++ b/src/games/services/server-configurator.service.spec.ts @@ -4,14 +4,60 @@ import { Environment } from '@/environment/environment'; import { PlayersService } from '@/players/services/players.service'; import { QueueConfigService } from '@/queue/services/queue-config.service'; import { RconFactoryService } from './rcon-factory.service'; +import { logAddressAdd, kickAll, changelevel, execConfig, addGamePlayer, enablePlayerWhitelist } from '../utils/rcon-commands'; -class EnvironmentStub { } -class PlayersServiceStub { } -class QueueConfigServiceStub { } -class RconFactoryServiceStub { } +class EnvironmentStub { + logRelayAddress = 'FAKE_RELAY_ADDRESS'; + logRelayPort = '1234'; +} + +class PlayersServiceStub { + players = new Map([ + ['PLAYER_1', { steamId: 'PLAYER_1_STEAMID', name: 'PLAYER_1_NAME' }], + ['PLAYER_2', { steamId: 'PLAYER_2_STEAMID', name: 'PLAYER_2_NAME' }], + ]); + getById(id: string) { return this.players.get(id); } +} + +class QueueConfigServiceStub { + queueConfig = { + execConfigs: [ 'etf2l_6v6_5cp' ], + }; +} + +class RconStub { + send(cmd: string) { return null; } + end() { return null; } +} + +class RconFactoryServiceStub { + createRcon() { return new RconStub(); } +} + +const gameServer = { + name: 'FAKE_SERVER', +}; + +const game = { + map: 'cp_badlands', + slots: [ + { + playerId: 'PLAYER_1', + teamId: 0, + gameClass: 'soldier', + }, + { + playerId: 'PLAYER_2', + teamId: 1, + gameClass: 'soldier', + }, + ], +}; describe('ServerConfiguratorService', () => { let service: ServerConfiguratorService; + let rconFactoryService: RconFactoryServiceStub; + let playersService: PlayersServiceStub; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ @@ -25,9 +71,49 @@ describe('ServerConfiguratorService', () => { }).compile(); service = module.get(ServerConfiguratorService); + rconFactoryService = module.get(RconFactoryService); + playersService = module.get(PlayersService); }); it('should be defined', () => { expect(service).toBeDefined(); }); + + describe('#configureServer()', () => { + let rcon: RconStub; + + beforeEach(() => { + rcon = new RconStub(); + spyOn(rconFactoryService, 'createRcon').and.returnValue(rcon); + }); + + it('should execute correct rcon commands', async () => { + const spy = spyOn(rcon, 'send'); + + await service.configureServer(gameServer as any, game as any); + + expect(spy).toHaveBeenCalledWith(logAddressAdd('FAKE_RELAY_ADDRESS:1234')); + expect(spy).toHaveBeenCalledWith(kickAll()); + expect(spy).toHaveBeenCalledWith(changelevel('cp_badlands')); + expect(spy).toHaveBeenCalledWith(execConfig('etf2l_6v6_5cp')); + expect(spy).toHaveBeenCalledWith(jasmine.stringMatching(/^sv_password\s.+$/)); + expect(spy).toHaveBeenCalledWith(addGamePlayer('PLAYER_1_STEAMID', 'PLAYER_1_NAME', 2, 'soldier')); + expect(spy).toHaveBeenCalledWith(addGamePlayer('PLAYER_2_STEAMID', 'PLAYER_2_NAME', 3, 'soldier')); + expect(spy).toHaveBeenCalledWith(enablePlayerWhitelist()); + }); + + it('should close the rcon connection', async () => { + const spy = spyOn(rcon, 'end'); + await service.configureServer(gameServer as any, game as any); + expect(spy).toHaveBeenCalled(); + }); + + it('should deburr player nicknames', async () => { + playersService.players.get('PLAYER_1').name = 'mały'; + const spy = spyOn(rcon, 'send'); + + await service.configureServer(gameServer as any, game as any); + expect(spy).toHaveBeenCalledWith(addGamePlayer('PLAYER_1_STEAMID', 'maly', 2, 'soldier')); + }); + }); }); diff --git a/src/games/services/server-configurator.service.ts b/src/games/services/server-configurator.service.ts index 76d8a6926..2d994dbd6 100644 --- a/src/games/services/server-configurator.service.ts +++ b/src/games/services/server-configurator.service.ts @@ -7,9 +7,8 @@ import { PlayersService } from '@/players/services/players.service'; import { QueueConfigService } from '@/queue/services/queue-config.service'; import { RconFactoryService } from './rcon-factory.service'; import { logAddressAdd, changelevel, execConfig, setPassword, addGamePlayer, logAddressDel, delAllGamePlayers, - kickAll, - enablePlayerWhitelist, - disablePlayerWhitelist} from '../utils/rcon-commands'; + kickAll, enablePlayerWhitelist, disablePlayerWhitelist } from '../utils/rcon-commands'; +import { deburr } from 'lodash'; @Injectable() export class ServerConfiguratorService { @@ -52,7 +51,8 @@ export class ServerConfiguratorService { const player = await this.playersService.getById(slot.playerId); const team = parseInt(slot.teamId, 10) + 2; - const cmd = addGamePlayer(player.steamId, player.name, team, slot.gameClass); + const playerName = deburr(player.name); + const cmd = addGamePlayer(player.steamId, playerName, team, slot.gameClass); this.logger.debug(`[${server.name}] ${cmd}`); await rcon.send(cmd); }