tests & endgame logic (start)

This commit is contained in:
Kirill Ivlev 2024-11-11 12:32:04 +04:00
parent 08fa0563e7
commit ced62ddfba
14 changed files with 132 additions and 30 deletions

18
package-lock.json generated
View file

@ -41,7 +41,7 @@
},
"devDependencies": {
"@nestjs/schematics": "^10.0.3",
"@nestjs/testing": "^10.2.8",
"@nestjs/testing": "^10.4.7",
"@types/cron": "^2.0.1",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.8",
@ -1905,12 +1905,13 @@
}
},
"node_modules/@nestjs/testing": {
"version": "10.2.8",
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.8.tgz",
"integrity": "sha512-9Kj5IQhM67/nj/MT6Wi2OmWr5YQnCMptwKVFrX1TDaikpY12196v7frk0jVjdT7wms7rV07GZle9I2z0aSjqtQ==",
"version": "10.4.7",
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.4.7.tgz",
"integrity": "sha512-aS3sQ0v4g8cyHDzW3xJv1+8MiFAkxUNXmnau588IFFI/nBIo/kevLNHNPr85keYekkJ/lwNDW72h8UGg8BYd9w==",
"dev": true,
"license": "MIT",
"dependencies": {
"tslib": "2.6.2"
"tslib": "2.7.0"
},
"funding": {
"type": "opencollective",
@ -1931,6 +1932,13 @@
}
}
},
"node_modules/@nestjs/testing/node_modules/tslib": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
"dev": true,
"license": "0BSD"
},
"node_modules/@nestjs/websockets": {
"version": "10.2.8",
"resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.2.8.tgz",

View file

@ -53,7 +53,7 @@
},
"devDependencies": {
"@nestjs/schematics": "^10.0.3",
"@nestjs/testing": "^10.2.8",
"@nestjs/testing": "^10.4.7",
"@types/cron": "^2.0.1",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.8",

View file

@ -3,6 +3,7 @@ import { GiveOutAPrizeCommand } from '../commands/give-out-a-prize.command';
import { GameService } from '../game.service';
import { Logger } from '@nestjs/common';
import { GameQueueTypes } from '../../schemas/game-queue.schema';
import {GuestsService} from "../../guests/guests.service";
@CommandHandler(GiveOutAPrizeCommand)
export class GameGiveOutAPrizeCommandHandler
@ -10,11 +11,12 @@ export class GameGiveOutAPrizeCommandHandler
private readonly logger = new Logger(GameGiveOutAPrizeCommandHandler.name);
constructor(private gameService: GameService) {
constructor(private gameService: GameService, private guestService: GuestsService) {
}
async execute(command: GiveOutAPrizeCommand): Promise<any> {
this.logger.verbose(`Player winning a prize ${command.telegramId}`);
await this.guestService.incrementPrizeCount(command.telegramId);
return this.gameService.addTaskToGameQueue(
command.telegramId,
GameQueueTypes.giveOutAPrize,

View file

@ -24,8 +24,6 @@ import {MqtMessageModel} from "../messaging/models/mqt-message.model";
import {ConfigService} from "@nestjs/config";
import {StringHelper} from "../helpers/stringhelper";
import {DebuffsConsts} from "../game/entities/debuffs.consts";
import {CreateNewQueueItemCommand} from "../game/commands/create-new-queue-item.command";
import {GameQueueTypes} from "../schemas/game-queue.schema";
import {VoiceService} from "../voice/voice.service";
import {screpaDictManyInvalidAnswersDict} from "../voice/dicts/screpa-dict-many-invalid-answers.dict";
import {GuestPropertiesConsts} from "../schemas/properties.consts";
@ -66,6 +64,10 @@ export class GuestsService {
return this.guestModel.find().exec();
}
getModel() {
return this.guestModel;
}
async filter(properties: object) {
return this.guestModel.find(properties).exec();
}
@ -340,4 +342,16 @@ export class GuestsService {
guest.invalidAnswersInRow = 0;
await guest.save();
}
async incrementPrizeCount(telegramId: number) {
const guest = await this.findById(telegramId);
guest.rewardsReceived += 1;
await guest.save();
}
async updatePenaltiesCount(user: number) {
const guest = await this.findById(user);
guest.penaltiesReceived += 1;
await guest.save();
}
}

View file

@ -0,0 +1,3 @@
export const GiftServiceMock = {
getRemainingPrizeCount: () => jest.fn(),
}

View file

@ -0,0 +1,3 @@
export const QuizServiceMock = {
getRemainQuestionCount: () =>jest.fn(),
}

View file

@ -0,0 +1,3 @@
export const SharedServiceMock = {
sendSocketNotificationToAllClients: jest.fn(),
}

View file

@ -0,0 +1,3 @@
export const StateServiceMock = {
setState: jest.fn(),
}

View file

@ -1,7 +1,7 @@
import { Body, Controller, Get, Post } from "@nestjs/common";
import { QuestionDto, QuestionDtoExcel } from './dto/question.dto';
import { QuizService } from "./quiz.service";
import { ExtraQuestionDto } from './dto/extra-question.dto';
import {Body, Controller, Get, Post} from "@nestjs/common";
import {QuestionDto, QuestionDtoExcel} from './dto/question.dto';
import {QuizService} from "./quiz.service";
import {ExtraQuestionDto} from './dto/extra-question.dto';
@Controller('quiz')
export class QuizController {
@ -50,4 +50,10 @@ export class QuizController {
async dealPrize() {
return this.quizService.dealPrize();
}
@Get('endgame-extrapoints')
async endgameExtrapoints()
{
return await this.quizService.addEndgamePoints();
}
}

View file

@ -10,12 +10,11 @@ import {ValidAnswerReceivedEvent} from '../game/events/valid-answer.recieved';
import {QuestionStorage, QuestionStorageDocument,} from '../schemas/question-storage.schema';
import {WrongAnswerReceivedEvent} from '../game/events/wrong-answer-received.event';
import {ProceedGameQueueCommand} from '../game/commands/proceed-game-queue.command';
import {getRandomInt} from 'src/helpers/rand-number';
import {getRandomInt} from '../helpers/rand-number';
import {Messages} from "../messaging/tg.text";
import {CreateNewQueueItemCommand} from "../game/commands/create-new-queue-item.command";
import {GameQueueTypes} from "../schemas/game-queue.schema";
import {IncreasePlayerWinningRateCommand} from "../game/commands/increase-player-winning-rate.command";
import {SocketEvents} from "../shared/events.consts";
import {IncreasePlayerScoreCommand} from "../guests/command/increase-player-score.command";
@Injectable({ scope: Scope.TRANSIENT })
@ -156,10 +155,36 @@ export class QuizService {
return;
}
targetUser = lastInvalidAnswer.user;
await this.guestService.updatePenaltiesCount(lastInvalidAnswer.user);
await this.commandBus.execute(new CreateNewQueueItemCommand(lastInvalidAnswer.user, GameQueueTypes.penalty));
}
await this.commandBus.execute(new CreateNewQueueItemCommand(targetUser, GameQueueTypes.showresults));
}
public async addEndgamePoints() {
const maxInvalidAnswersPromise = this.guestService.getModel().find({}).sort({ ['invalidAnswers']: 'desc'}).exec();
const maxRewardsPromise = this.guestService.getModel().find({}).sort({['rewardsReceived']: "desc"}).exec();
const maxPenaltiesPromise = this.guestService.getModel().find({}).sort({['penaltiesReceived']: 'desc'}).exec();
//const { maxRewards, maxInvalidAnswers } = Promise.all([maxRewardsPromise, maxInvalidAnswersPromise]);
const [maxRewards, maxInvalidAnswers, maxPenaltiesReceived] = await Promise.all([maxRewardsPromise, maxInvalidAnswersPromise, maxPenaltiesPromise]);
return {
maxInvalidAnswers: {
id: maxInvalidAnswers[0].id,
count: maxInvalidAnswers[0].invalidAnswers,
name: maxInvalidAnswers[0].name,
},
maxRewards: {
id: maxRewards[0].id,
count: maxRewards[0].rewardsReceived,
name: maxRewards[0].name,
},
maxPenalties: {
id: maxPenaltiesReceived[0].id,
count: maxPenaltiesReceived[0].penaltiesReceived,
name: maxPenaltiesReceived[0].name,
}
}
}
private async getNextQuestion() {

View file

@ -1,18 +1,55 @@
import { Test, TestingModule } from '@nestjs/testing';
import { SchedulerService } from './scheduler.service';
import {GiftsService} from "../gifts/gifts.service";
import {GiftServiceMock} from "../mocks/gift-service.mock";
import {StateService} from "../state/state.service";
import {StateServiceMock} from "../mocks/state-service.mock";
import {QuizService} from "../quiz/quiz.service";
import {QuizServiceMock} from "../mocks/quiz-service.mock";
import {SharedService} from "../shared/shared.service";
import {SharedServiceMock} from "../mocks/shared-service.mock";
describe('SchedulerService', () => {
let service: SchedulerService;
let giftService: GiftsService;
let sharedService: SharedService;
let stateService: StateService;
beforeEach(async () => {
jest.clearAllMocks();
const module: TestingModule = await Test.createTestingModule({
providers: [SchedulerService],
providers: [SchedulerService,
{ provide: GiftsService, useValue: GiftServiceMock },
{ provide: StateService, useValue: StateServiceMock },
{ provide: QuizService, useValue: QuizServiceMock },
{ provide: SharedService, useValue: SharedServiceMock },
],
}).compile();
service = module.get<SchedulerService>(SchedulerService);
giftService = module.get<GiftsService>(GiftsService);
sharedService = module.get<SharedService>(SharedService);
stateService = module.get<StateService>(StateService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
it('should finish game if prizes count is 0', async () => {
const getRemainingPrizeCountFn = jest.spyOn(giftService, 'getRemainingPrizeCount').mockImplementation(() => Promise.resolve(0));
const notificationFn = jest.spyOn(sharedService,'sendSocketNotificationToAllClients').mockImplementation();
const setStateFn = jest.spyOn(stateService,'setState').mockImplementation((name,newstate) => Promise.resolve({ state: name, value: newstate}));
await service.gameStatus();
expect(getRemainingPrizeCountFn).toHaveBeenCalled();
expect(notificationFn).toHaveBeenCalled();
expect(notificationFn).toHaveBeenCalledWith('state_changed', expect.objectContaining({ state: 'main', value: 'finish'}));
});
it('should not finish game if prizes count above 0', async () => {
const getRemainingPrizeCountFn = jest.spyOn(giftService, 'getRemainingPrizeCount').mockImplementation(() => Promise.resolve(5));
const notificationFn = jest.spyOn(sharedService,'sendSocketNotificationToAllClients').mockImplementation()
await service.gameStatus();
expect(notificationFn).not.toHaveBeenCalled();
});
});

View file

@ -1,14 +1,10 @@
import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { StateService } from '../state/state.service';
import {CommandBus, QueryBus} from '@nestjs/cqrs';
import { GiftsService } from 'src/gifts/gifts.service';
import { QuizService } from 'src/quiz/quiz.service';
import { SharedService } from 'src/shared/shared.service';
import {GetGuestPropertyQuery} from "../guests/command/get-guest-property.handler";
import {GuestPropertiesConsts} from "../schemas/properties.consts";
import {GetGuestQuery} from "../guests/queries/getguest.query";
import {StringHelper} from "../helpers/stringhelper";
import { QuizService } from '../quiz/quiz.service';
import { GiftsService } from '../gifts/gifts.service';
import { SharedService } from '../shared/shared.service';
@Injectable()
export class SchedulerService {
private readonly logger = new Logger(SchedulerService.name);
@ -17,8 +13,6 @@ export class SchedulerService {
constructor(
private stateService: StateService,
private cmdBus: CommandBus,
private queryBus: QueryBus,
private giftsService: GiftsService,
private quizService: QuizService,
private sharedService: SharedService,
@ -38,6 +32,7 @@ export class SchedulerService {
const giftsLeft = await this.giftsService.getRemainingPrizeCount();
if (giftsLeft === 0) {
const state = await this.stateService.setState('main', 'finish');
console.log(this.state);
this.sharedService.sendSocketNotificationToAllClients(
'state_changed',
state,

View file

@ -25,8 +25,6 @@ export class Guest {
@Prop({ default: 10 })
prizeChance: number;
@Prop({ default: 0 })
prizesCount: number;
@Prop({ default: 0 })
validAnswers: number;
@Prop({ default: 0 })
invalidAnswers: number;
@ -34,6 +32,8 @@ export class Guest {
invalidAnswersInRow: number;
@Prop({ default:0 })
rewardsReceived: number;
@Prop({ default: 0})
penaltiesReceived: number;
@Prop({ type: Map })
properties: Record<string, string>;
}

View file

@ -37,6 +37,9 @@ export class StateService {
const stateEntity = await this.getState(name);
stateEntity.value = newValue;
await stateEntity.save();
return stateEntity;
return {
state: stateEntity.state,
value: stateEntity.value,
}
}
}