Skip to content

Commit 09c84a3

Browse files
Merge pull request #7 from dota2classic/calibration_v2
Calibration v2
2 parents 0a3893a + 172dab8 commit 09c84a3

18 files changed

+907
-300
lines changed

package.json

+9-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@
2121
"test:e2e": "jest --config ./test/jest-e2e.json",
2222
"docker": "docker build . -t dota2classic/matchmaking:gameserver && docker push dota2classic/matchmaking:gameserver",
2323
"docker:local": "docker build . -t dota2classic/matchmaking:gameserver",
24-
"nodemon": "nodemon scrapper.js"
24+
"nodemon": "nodemon scrapper.js",
25+
"migration:generate": "npx ts-node -P ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate -d ./src/config/typeorm.config.ts",
26+
"migration:create": "npx ts-node -P ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:create",
27+
"migration:run": "npx ts-node -P ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:run -d ./src/config/typeorm.config.ts",
28+
"migration:run-fake": "npx ts-node -P ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:run --fake -d ./src/config/typeorm.config.ts",
29+
"migration:revert": "npx ts-node -P ./tsconfig.json -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:revert -d ./src/config/typeorm.config.ts"
2530
},
2631
"dependencies": {
2732
"@nestjs/cache-manager": "^2.3.0",
@@ -70,8 +75,9 @@
7075
"@nestjs/testing": "^10.4.10",
7176
"@swc/cli": "^0.5.1",
7277
"@swc/core": "^1.9.3",
73-
"testcontainers": "^10.15.0",
7478
"@testcontainers/postgresql": "^10.15.0",
79+
"@testcontainers/rabbitmq": "^10.18.0",
80+
"@testcontainers/redis": "^10.18.0",
7581
"@types/express": "^5.0.0",
7682
"@types/jest": "29.5.14",
7783
"@types/js-yaml": "^4.0.9",
@@ -86,7 +92,7 @@
8692
"nodemon": "^3.1.7",
8793
"prettier": "^3.4.1",
8894
"supertest": "^7.0.0",
89-
95+
"testcontainers": "^10.15.0",
9096
"ts-jest": "29.2.5",
9197
"ts-loader": "^9.5.1",
9298
"ts-node": "^10.9.2",

src/@test/create-fake-match.ts

+12-20
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
1-
import { Repository } from 'typeorm';
21
import FinishedMatchEntity from 'gameserver/model/finished-match.entity';
3-
import { getRepositoryToken } from '@nestjs/typeorm';
42
import { GameSeasonEntity } from 'gameserver/model/game-season.entity';
5-
import { TestingModule } from '@nestjs/testing';
63
import { MatchEntity } from 'gameserver/model/match.entity';
74
import { Dota2Version } from 'gateway/shared-types/dota2version';
85
import { MatchmakingMode } from 'gateway/shared-types/matchmaking-mode';
96
import { Dota_GameMode } from 'gateway/shared-types/dota-game-mode';
107
import { DotaTeam } from 'gateway/shared-types/dota-team';
118
import PlayerInMatchEntity from 'gameserver/model/player-in-match.entity';
9+
import { TestEnvironment } from '@test/useFullModule';
1210

13-
export async function createSeason(module: TestingModule) {
14-
const seasonRep = module.get<Repository<GameSeasonEntity>>(
15-
getRepositoryToken(GameSeasonEntity),
16-
);
11+
export async function createSeason(te: TestEnvironment) {
12+
const seasonRep = te.repo(GameSeasonEntity);
1713
const gs3 = new GameSeasonEntity();
1814
gs3.id = 3;
1915
gs3.start_timestamp = new Date("2023-08-31 20:00:00.000000");
@@ -22,18 +18,14 @@ export async function createSeason(module: TestingModule) {
2218
}
2319

2420
export async function createFakeMatch(
25-
module: TestingModule,
21+
te: TestEnvironment,
2622
winner: DotaTeam = DotaTeam.RADIANT,
2723
mode: MatchmakingMode = MatchmakingMode.UNRANKED,
2824
duration: number = 100,
2925
): Promise<FinishedMatchEntity> {
30-
const matchRep = module.get<Repository<FinishedMatchEntity>>(
31-
getRepositoryToken(FinishedMatchEntity),
32-
);
26+
const matchRep = te.repo(FinishedMatchEntity);
3327

34-
const meRep = module.get<Repository<MatchEntity>>(
35-
getRepositoryToken(MatchEntity),
36-
);
28+
const meRep = te.repo(MatchEntity);
3729

3830
// seasons setup
3931

@@ -59,16 +51,15 @@ export async function createFakeMatch(
5951
return match;
6052
}
6153

54+
const randInt = (r: number) => Math.round(Math.random() * r);
55+
6256
export async function fillMatch(
63-
module: TestingModule,
57+
te: TestEnvironment,
6458
fm: FinishedMatchEntity,
6559
count: number = 10,
60+
modify: (pim: PlayerInMatchEntity) => void = () => undefined,
6661
) {
67-
const pRep = module.get<Repository<PlayerInMatchEntity>>(
68-
getRepositoryToken(PlayerInMatchEntity),
69-
);
70-
71-
const randInt = (r: number) => Math.round(Math.random() * r);
62+
const pRep = te.repo(PlayerInMatchEntity);
7263

7364
const pims: PlayerInMatchEntity[] = [];
7465
for (let i = 0; i < count; i++) {
@@ -92,6 +83,7 @@ export async function fillMatch(
9283
pim.item3 = randInt(100);
9384
pim.item4 = randInt(100);
9485
pim.item5 = randInt(100);
86+
modify(pim);
9587
await pRep.save(pim);
9688
pims.push(pim);
9789
}

src/@test/useFullModule.ts

+216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { PostgreSqlContainer, StartedPostgreSqlContainer } from '@testcontainers/postgresql';
3+
import { getRepositoryToken, TypeOrmModule } from '@nestjs/typeorm';
4+
import { INestApplication } from '@nestjs/common';
5+
import { Constructor, CqrsModule, EventBus } from '@nestjs/cqrs';
6+
import { DataSource, ObjectLiteral, Repository } from 'typeorm';
7+
import { EntityClassOrSchema } from '@nestjs/typeorm/dist/interfaces/entity-class-or-schema.type';
8+
import { Entities } from 'util/typeorm-config';
9+
import { ClientsModule, RedisOptions, RmqOptions, Transport } from '@nestjs/microservices';
10+
import { RedisContainer, StartedRedisContainer } from '@testcontainers/redis';
11+
import { FantasyFunction1739896254921 } from 'database/migrations/1739896254921-FantasyFunction';
12+
import { AppService } from 'app.service';
13+
import { MetaService } from 'rest/meta/meta.service';
14+
import { MatchService } from 'rest/match/match.service';
15+
import { PlayerService } from 'rest/service/player.service';
16+
import { MatchMapper } from 'rest/match/match.mapper';
17+
import { MetaMapper } from 'rest/meta/meta.mapper';
18+
import { InfoMapper } from 'rest/info/info.mapper';
19+
import { InfoService } from 'rest/info/info.service';
20+
import { MmrBucketService } from 'gameserver/mmr-bucket.service';
21+
import { Mapper } from 'rest/mapper';
22+
import { GameServerDomain } from 'gameserver';
23+
import { ConfigModule } from '@nestjs/config';
24+
import { RabbitMQContainer, StartedRabbitMQContainer } from '@testcontainers/rabbitmq';
25+
import { WinstonWrapper } from 'util/logger';
26+
import { CoreController } from 'core.controller';
27+
import { RmqController } from 'rmq.controller';
28+
import { QueryController } from 'query.controller';
29+
import { MatchController } from 'rest/match/match.controller';
30+
import { PlayerController } from 'rest/player.controller';
31+
import { InfoController } from 'rest/info/info.controller';
32+
import { MetaController } from 'rest/meta/meta.controller';
33+
import { CrimeController } from 'rest/crime/crime.controller';
34+
import SpyInstance = jest.SpyInstance;
35+
36+
export interface TestEnvironment {
37+
module: TestingModule;
38+
app: INestApplication;
39+
containers: {
40+
pg: StartedPostgreSqlContainer;
41+
redis: StartedRedisContainer;
42+
rabbit: StartedRabbitMQContainer;
43+
};
44+
ebus: EventBus;
45+
ebusSpy: SpyInstance;
46+
queryMocks: Record<string, jest.Mock>;
47+
48+
service<R>(c: Constructor<R>): R;
49+
50+
repo<R extends ObjectLiteral>(c: EntityClassOrSchema): Repository<R>;
51+
}
52+
53+
export function useFullModule(): TestEnvironment {
54+
jest.setTimeout(120_000);
55+
56+
const te: TestEnvironment = {
57+
module: undefined as unknown as any,
58+
containers: {} as unknown as any,
59+
ebus: {} as unknown as any,
60+
ebusSpy: {} as unknown as any,
61+
app: {} as unknown as any,
62+
service: {} as unknown as any,
63+
repo: {} as unknown as any,
64+
65+
queryMocks: {},
66+
};
67+
68+
afterEach(() => {
69+
te.ebusSpy.mockReset();
70+
});
71+
72+
beforeAll(async () => {
73+
te.containers.pg = await new PostgreSqlContainer()
74+
.withUsername("username")
75+
.withPassword("password")
76+
.start();
77+
78+
te.containers.redis = await new RedisContainer()
79+
.withPassword("redispass")
80+
.start();
81+
82+
te.containers.rabbit = await new RabbitMQContainer()
83+
.start();
84+
85+
te.queryMocks = {};
86+
87+
te.module = await Test.createTestingModule({
88+
imports: [
89+
await ConfigModule.forRoot({
90+
isGlobal: true
91+
}),
92+
CqrsModule.forRoot(),
93+
TypeOrmModule.forRoot({
94+
host: te.containers.pg.getHost(),
95+
port: te.containers.pg.getFirstMappedPort(),
96+
97+
type: "postgres",
98+
database: "postgres",
99+
// logging: true,
100+
101+
username: te.containers.pg.getUsername(),
102+
password: te.containers.pg.getPassword(),
103+
entities: Entities,
104+
synchronize: true,
105+
dropSchema: true,
106+
ssl: false,
107+
}),
108+
TypeOrmModule.forFeature(Entities),
109+
ClientsModule.registerAsync([
110+
{
111+
name: "QueryCore",
112+
useFactory(): RedisOptions {
113+
return {
114+
transport: Transport.REDIS,
115+
options: {
116+
port: te.containers.redis.getPort(),
117+
host: te.containers.redis.getHost(),
118+
password: te.containers.redis.getPassword(),
119+
},
120+
};
121+
},
122+
inject: [],
123+
imports: [],
124+
},
125+
{
126+
name: "RMQ",
127+
useFactory(): RmqOptions {
128+
return {
129+
transport: Transport.RMQ,
130+
options: {
131+
urls: [
132+
{
133+
hostname: te.containers.rabbit.getHost(),
134+
port: te.containers.rabbit.getFirstMappedPort(),
135+
protocol: "amqp",
136+
// username: te.containers.rabbit.getName(),
137+
// password: te.containers.rabbit.get(),
138+
},
139+
],
140+
queue: 'gameserver_commands',
141+
queueOptions: {
142+
durable: true,
143+
},
144+
prefetchCount: 5,
145+
},
146+
};
147+
},
148+
inject: [],
149+
imports: [],
150+
}
151+
]),
152+
],
153+
providers: [
154+
AppService,
155+
MetaService,
156+
MatchService,
157+
PlayerService,
158+
MatchMapper,
159+
MetaMapper,
160+
InfoMapper,
161+
InfoService,
162+
MmrBucketService,
163+
Mapper,
164+
...GameServerDomain,
165+
],
166+
controllers: [
167+
CoreController,
168+
RmqController,
169+
QueryController,
170+
MatchController,
171+
PlayerController,
172+
InfoController,
173+
MetaController,
174+
CrimeController,
175+
]
176+
}).compile();
177+
178+
te.app = await te.module.createNestApplication({
179+
logger: new WinstonWrapper(
180+
'localhost',
181+
7777,
182+
true,
183+
),
184+
});
185+
186+
await te.app.listen(0)
187+
188+
te.service = (con) => te.module.get(con);
189+
te.repo = (con) => te.module.get(getRepositoryToken(con));
190+
te.ebus = te.module.get(EventBus);
191+
te.ebusSpy = jest.spyOn(te.ebus, "publish");
192+
193+
await new FantasyFunction1739896254921().up(
194+
te.service(DataSource).createQueryRunner(),
195+
);
196+
console.log("Created fantasy score function")
197+
198+
// Mocks:
199+
});
200+
201+
afterAll(async () => {
202+
await te.app.close();
203+
await te.containers.pg.stop();
204+
await te.containers.redis.stop();
205+
});
206+
207+
return te;
208+
}
209+
210+
export function testUser(): string {
211+
return Math.round(Math.random() * 1000000).toString();
212+
}
213+
214+
export async function sleep(ms: number) {
215+
return new Promise((resolve) => setTimeout(resolve, ms));
216+
}

0 commit comments

Comments
 (0)