@solidxai/core 0.1.8 → 0.1.9-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entities/setting.entity.js +1 -1
- package/dist/entities/setting.entity.js.map +1 -1
- package/dist/seeders/module-test-data.service.d.ts +3 -0
- package/dist/seeders/module-test-data.service.d.ts.map +1 -1
- package/dist/seeders/module-test-data.service.js +92 -0
- package/dist/seeders/module-test-data.service.js.map +1 -1
- package/dist/testing/contracts/testing-metadata.types.d.ts +14 -0
- package/dist/testing/contracts/testing-metadata.types.d.ts.map +1 -1
- package/dist/testing/contracts/testing-metadata.types.js.map +1 -1
- package/package.json +1 -1
- package/src/entities/setting.entity.ts +2 -2
- package/src/seeders/module-test-data.service.ts +106 -0
- package/src/testing/contracts/testing-metadata.types.ts +16 -0
|
@@ -39,7 +39,7 @@ __decorate([
|
|
|
39
39
|
__metadata("design:type", String)
|
|
40
40
|
], Setting.prototype, "level", void 0);
|
|
41
41
|
__decorate([
|
|
42
|
-
(0, typeorm_1.Column)({ name: "encrypted",
|
|
42
|
+
(0, typeorm_1.Column)({ name: "encrypted", default: false }),
|
|
43
43
|
__metadata("design:type", Boolean)
|
|
44
44
|
], Setting.prototype, "encrypted", void 0);
|
|
45
45
|
__decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setting.entity.js","sourceRoot":"","sources":["../../src/entities/setting.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,mDAAyD;AACzD,qCAAuE;AACvE,+CAA+C;AAC/C,qEAA0D;AAGnD,IAAM,OAAO,GAAb,MAAM,OAAQ,SAAQ,4BAAY;;;;CA2BxC,CAAA;AA3BY,0BAAO;AAIhB;IAFC,IAAA,eAAK,EAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACvB,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;;oCACjC;AAGZ;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;sCAC9B;AAGd;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;qCAC7C;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;sCAC7C;AAGd;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"setting.entity.js","sourceRoot":"","sources":["../../src/entities/setting.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,mDAAyD;AACzD,qCAAuE;AACvE,+CAA+C;AAC/C,qEAA0D;AAGnD,IAAM,OAAO,GAAb,MAAM,OAAQ,SAAQ,4BAAY;;;;CA2BxC,CAAA;AA3BY,0BAAO;AAIhB;IAFC,IAAA,eAAK,EAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACvB,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;;oCACjC;AAGZ;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;sCAC9B;AAGd;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;qCAC7C;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;sCAC7C;AAGd;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;;0CAC3B;AAKnB;IAHC,IAAA,eAAK,GAAE;IACP,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,kBAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACzC,IAAA,oBAAU,GAAE;8BACP,kBAAI;qCAAC;AAKX;IAHC,IAAA,eAAK,GAAE;IACP,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,uCAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACnD,IAAA,oBAAU,GAAE;8BACG,uCAAc;+CAAC;kBA1BtB,OAAO;IADnB,IAAA,gBAAM,EAAC,YAAY,CAAC;GACR,OAAO,CA2BnB","sourcesContent":["import { CommonEntity } from 'src/entities/common.entity'\nimport { Entity, Column, Index, JoinColumn, ManyToOne } from 'typeorm';\nimport { User } from 'src/entities/user.entity'\nimport { ModuleMetadata } from './module-metadata.entity';\n\n@Entity(\"ss_setting\")\nexport class Setting extends CommonEntity {\n\n @Index({ unique: true })\n @Column({ type: \"varchar\", nullable: false })\n key: string;\n\n @Column({ type: \"varchar\", nullable: true })\n value: string;\n\n @Column({ name: \"type\", type: \"varchar\", nullable: true })\n type: string;\n\n @Column({ name: \"level\", type: \"varchar\", nullable: true })\n level: string;\n\n @Column({ name: \"encrypted\", default: false })\n encrypted: boolean; \n\n @Index()\n @ManyToOne(() => User, { nullable: true })\n @JoinColumn()\n user: User;\n\n @Index()\n @ManyToOne(() => ModuleMetadata, { nullable: true })\n @JoinColumn()\n moduleMetadata: ModuleMetadata;\n}\n"]}
|
|
@@ -11,6 +11,9 @@ export declare class ModuleTestDataService {
|
|
|
11
11
|
deleteTestDatasources(): Promise<void>;
|
|
12
12
|
private get testDataFiles();
|
|
13
13
|
private seedTestData;
|
|
14
|
+
private seedTestRoles;
|
|
15
|
+
private expandPermissionNames;
|
|
16
|
+
private seedTestUsers;
|
|
14
17
|
private seedMultiRelations;
|
|
15
18
|
private seedEntityMedia;
|
|
16
19
|
private get entityManager();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-test-data.service.d.ts","sourceRoot":"","sources":["../../src/seeders/module-test-data.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAY3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"module-test-data.service.d.ts","sourceRoot":"","sources":["../../src/seeders/module-test-data.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAY3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAU3D,qBACa,qBAAqB;IAI9B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa;IALhC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;gBAG9C,SAAS,EAAE,SAAS,EACpB,gBAAgB,EAAE,gBAAgB,EAClC,aAAa,EAAE,aAAa;IAGzC,aAAa,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBtD,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAqEtC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAoD5C,OAAO,KAAK,aAAa,GAexB;YAEa,YAAY;YA4HZ,aAAa;YAoCb,qBAAqB;YA6BrB,aAAa;YA0Bb,kBAAkB;YAsDlB,eAAe;IAsD7B,OAAO,KAAK,aAAa,GAExB;IAED,OAAO,KAAK,oBAAoB,GAE/B;IAED,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,oBAAoB;YA4Bd,yBAAyB;IA6BvC,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,kBAAkB;YAmCZ,uBAAuB;YA4BvB,eAAe;CA4B9B"}
|
|
@@ -59,7 +59,11 @@ const create_media_storage_provider_metadata_dto_1 = require("../dtos/create-med
|
|
|
59
59
|
const module_helper_1 = require("../helpers/module.helper");
|
|
60
60
|
const solid_registry_1 = require("../helpers/solid-registry");
|
|
61
61
|
const media_repository_1 = require("../repository/media.repository");
|
|
62
|
+
const permission_metadata_repository_1 = require("../repository/permission-metadata.repository");
|
|
63
|
+
const authentication_service_1 = require("../services/authentication.service");
|
|
62
64
|
const model_metadata_service_1 = require("../services/model-metadata.service");
|
|
65
|
+
const role_metadata_service_1 = require("../services/role-metadata.service");
|
|
66
|
+
const user_service_1 = require("../services/user.service");
|
|
63
67
|
const mediaStorageProviders_1 = require("../services/mediaStorageProviders");
|
|
64
68
|
let ModuleTestDataService = ModuleTestDataService_1 = class ModuleTestDataService {
|
|
65
69
|
constructor(moduleRef, discoveryService, solidRegistry) {
|
|
@@ -201,7 +205,15 @@ let ModuleTestDataService = ModuleTestDataService_1 = class ModuleTestDataServic
|
|
|
201
205
|
if (!moduleMetadata) {
|
|
202
206
|
throw new Error('Module metadata missing from test data payload.');
|
|
203
207
|
}
|
|
208
|
+
const testingRoles = overallMetadata?.testing?.roles ?? [];
|
|
209
|
+
const testingUsers = overallMetadata?.testing?.users ?? [];
|
|
204
210
|
const testingData = overallMetadata?.testing?.data ?? [];
|
|
211
|
+
if (testingRoles.length > 0) {
|
|
212
|
+
await this.seedTestRoles(testingRoles);
|
|
213
|
+
}
|
|
214
|
+
if (testingUsers.length > 0) {
|
|
215
|
+
await this.seedTestUsers(testingUsers);
|
|
216
|
+
}
|
|
205
217
|
if (testingData.length === 0) {
|
|
206
218
|
this.logger.debug(`No test data found for ${moduleMetadata.name}`);
|
|
207
219
|
return;
|
|
@@ -290,6 +302,86 @@ let ModuleTestDataService = ModuleTestDataService_1 = class ModuleTestDataServic
|
|
|
290
302
|
}
|
|
291
303
|
}
|
|
292
304
|
}
|
|
305
|
+
async seedTestRoles(roles) {
|
|
306
|
+
const roleService = this.moduleRef.get(role_metadata_service_1.RoleMetadataService, { strict: false });
|
|
307
|
+
if (!roleService) {
|
|
308
|
+
throw new Error('RoleMetadataService not available — cannot seed test roles.');
|
|
309
|
+
}
|
|
310
|
+
await roleService.createRolesIfNotExists(roles.map((r) => ({ name: r.name })));
|
|
311
|
+
for (const role of roles) {
|
|
312
|
+
const perms = role.permissions ?? [];
|
|
313
|
+
if (perms.length === 0)
|
|
314
|
+
continue;
|
|
315
|
+
if (perms.some((p) => p === '*')) {
|
|
316
|
+
await roleService.addAllPermissionsToRole(role.name);
|
|
317
|
+
this.logger.log(`Bound all permissions to test role "${role.name}"`);
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const expanded = await this.expandPermissionNames(perms);
|
|
321
|
+
if (expanded.length === 0) {
|
|
322
|
+
this.logger.warn(`Test role "${role.name}" has permissions declared but none resolved — skipping binding.`);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
await roleService.addPermissionsToRole(role.name, expanded);
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
throw new Error(`Failed to bind permissions to test role "${role.name}": ${err?.message ?? err}. ` +
|
|
330
|
+
`Did you run "solid seed" first so controller permissions are registered?`);
|
|
331
|
+
}
|
|
332
|
+
this.logger.log(`Bound ${expanded.length} permissions to test role "${role.name}"`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async expandPermissionNames(permissions) {
|
|
336
|
+
const permissionRepo = this.moduleRef.get(permission_metadata_repository_1.PermissionMetadataRepository, { strict: false });
|
|
337
|
+
if (!permissionRepo) {
|
|
338
|
+
throw new Error('PermissionMetadataRepository not available — cannot resolve test role permissions.');
|
|
339
|
+
}
|
|
340
|
+
const exact = new Set();
|
|
341
|
+
const prefixes = [];
|
|
342
|
+
for (const entry of permissions) {
|
|
343
|
+
if (!entry)
|
|
344
|
+
continue;
|
|
345
|
+
if (entry.endsWith('.*')) {
|
|
346
|
+
prefixes.push(entry.slice(0, -1));
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
exact.add(entry);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (prefixes.length > 0) {
|
|
353
|
+
const allPermissions = await permissionRepo.find();
|
|
354
|
+
for (const p of allPermissions) {
|
|
355
|
+
if (prefixes.some((prefix) => p.name.startsWith(prefix))) {
|
|
356
|
+
exact.add(p.name);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return Array.from(exact);
|
|
361
|
+
}
|
|
362
|
+
async seedTestUsers(users) {
|
|
363
|
+
const userService = this.moduleRef.get(user_service_1.UserService, { strict: false });
|
|
364
|
+
const authService = this.moduleRef.get(authentication_service_1.AuthenticationService, { strict: false });
|
|
365
|
+
if (!userService || !authService) {
|
|
366
|
+
throw new Error('UserService / AuthenticationService not available — cannot seed test users.');
|
|
367
|
+
}
|
|
368
|
+
for (const user of users) {
|
|
369
|
+
const existing = await userService.findOneByUsername(user.username);
|
|
370
|
+
if (existing) {
|
|
371
|
+
this.logger.debug(`Test user "${user.username}" already exists — skipping signUp.`);
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
await authService.signUp({
|
|
375
|
+
username: user.username,
|
|
376
|
+
email: user.email,
|
|
377
|
+
password: user.password,
|
|
378
|
+
fullName: user.fullName,
|
|
379
|
+
mobile: user.mobile,
|
|
380
|
+
roles: user.roles,
|
|
381
|
+
});
|
|
382
|
+
this.logger.log(`Created test user "${user.username}"${user.roles?.length ? ` with roles [${user.roles.join(', ')}]` : ''}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
293
385
|
async seedMultiRelations(entityId, modelUserKey, relations, modelsByName) {
|
|
294
386
|
for (const { field, userKeys } of relations) {
|
|
295
387
|
if (!userKeys.length)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-test-data.service.js","sourceRoot":"","sources":["../../src/seeders/module-test-data.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\nimport { DiscoveryService, ModuleRef } from '@nestjs/core';\nimport { getDataSourceToken } from '@nestjs/typeorm';\nimport { classify } from '@angular-devkit/core/src/utils/strings';\nimport { DataSource, EntityManager } from 'typeorm';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport solidCoreMetadata from './seed-data/solid-core-metadata.json';\nimport { CreateModuleMetadataDto } from 'src/dtos/create-module-metadata.dto';\nimport { CreateModelMetadataDto } from 'src/dtos/create-model-metadata.dto';\nimport { MediaStorageProviderType } from 'src/dtos/create-media-storage-provider-metadata.dto';\nimport { getDynamicModuleNamesBasedOnMetadata } from 'src/helpers/module.helper';\nimport { SolidRegistry } from 'src/helpers/solid-registry';\nimport { MediaRepository } from 'src/repository/media.repository';\nimport { ModelMetadataService } from 'src/services/model-metadata.service';\nimport { getMediaStorageProvider } from 'src/services/mediaStorageProviders';\n\n@Injectable()\nexport class ModuleTestDataService {\n private readonly logger = new Logger(ModuleTestDataService.name);\n\n constructor(\n private readonly moduleRef: ModuleRef,\n private readonly discoveryService: DiscoveryService,\n private readonly solidRegistry: SolidRegistry,\n ) {}\n\n async setupTestData(modulesToTest?: string[]): Promise<void> {\n const testDataFiles = this.testDataFiles;\n const filteredFiles = modulesToTest?.length ? testDataFiles.filter((file) => modulesToTest.includes(file.moduleMetadata?.name)) : testDataFiles;\n\n if (filteredFiles.length === 0) {\n this.logger.warn('No modules matched the provided modulesToTest list.');\n console.log('No modules matched the provided modulesToTest list.');\n return;\n }\n\n for (const overallMetadata of filteredFiles) {\n const moduleName = overallMetadata?.moduleMetadata?.name ?? 'unknown';\n this.logger.log(`Processing test data for module: ${moduleName}`);\n console.log(`Processing test data for module: ${moduleName}`);\n await this.seedTestData(overallMetadata);\n console.log(`✔ Test data setup complete for module: ${moduleName}`);\n }\n }\n\n async createTestDatasources(): Promise<void> {\n const manifestPath = path.join(process.cwd(), '.solidx-test-manifest');\n if (fs.existsSync(manifestPath)) {\n console.log('Existing .solidx-test-manifest found; skipping test datasource creation.');\n return;\n }\n\n const dbRunName = this.generateDbRunName();\n const timestamp = this.getTimestamp();\n const envPath = path.join(process.cwd(), '.env');\n if (!fs.existsSync(envPath)) {\n throw new Error(`Base .env file not found at ${envPath}`);\n }\n\n const datasourceNames = this.solidRegistry\n .getSolidDatabaseModules()\n .map((wrapper) => wrapper.instance?.name?.())\n .filter(Boolean)\n .map((name) => name.toLowerCase()) as string[];\n\n if (datasourceNames.length === 0) {\n throw new Error('No solid database modules registered; cannot create test datasources.');\n }\n\n const dbNameByDatasource = new Map<string, string>();\n for (const dsName of datasourceNames) {\n dbNameByDatasource.set(dsName, `${dsName}_${timestamp}_${dbRunName}`);\n }\n\n const newEnvContents = this.buildTestEnvContents(\n fs.readFileSync(envPath, 'utf-8'),\n dbNameByDatasource,\n );\n\n const backupEnvPath = path.join(process.cwd(), `.env.backup.${dbRunName}`);\n fs.copyFileSync(envPath, backupEnvPath);\n fs.writeFileSync(envPath, newEnvContents);\n console.log(`Backed up .env to ${path.basename(backupEnvPath)} and applied new test datasource names to .env.`);\n\n this.updateTestManifest(dbRunName, timestamp, dbNameByDatasource);\n\n await this.createTestDatabaseObjects(dbNameByDatasource);\n\n const dbList = Array.from(dbNameByDatasource.entries())\n .map(([dsName, dbName]) => `- ${dsName}: ${dbName}`)\n .join('\\n');\n\n const instructions = [\n '',\n '============================================================',\n ' TEST DATASOURCE ENVIRONMENT CREATED',\n '------------------------------------------------------------',\n ` Run name : ${dbRunName}`,\n ` Env backup : ${path.basename(backupEnvPath)}`,\n '',\n ' Test databases/schemas created:',\n dbList || ' (none)',\n '',\n ' Next steps:',\n ' 1) Using updated .env with test datasource names',\n ' 2) Run solid seed as usual',\n ' 3) Proceed with the next steps in the workflow',\n '============================================================',\n '',\n ].join('\\n');\n\n console.log(instructions);\n }\n\n async deleteTestDatasources(): Promise<void> {\n const manifestPath = path.join(process.cwd(), '.solidx-test-manifest');\n if (!fs.existsSync(manifestPath)) {\n this.logger.log('No .solidx-test-manifest found; nothing to delete.');\n console.log('No .solidx-test-manifest found; nothing to delete.');\n return;\n }\n\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) as {\n runs?: Record<string, { databases?: Record<string, string>; createdAt?: string }>;\n };\n const runs = manifest?.runs ?? {};\n const runNames = Object.keys(runs);\n if (runNames.length === 0) {\n fs.unlinkSync(manifestPath);\n return;\n }\n\n const latestRunName = runNames\n .slice()\n .sort((a, b) => {\n const aCreated = runs[a]?.createdAt ?? '';\n const bCreated = runs[b]?.createdAt ?? '';\n return aCreated.localeCompare(bCreated);\n })\n .pop();\n if (latestRunName) {\n const backupEnvPath = path.join(process.cwd(), `.env.backup.${latestRunName}`);\n if (fs.existsSync(backupEnvPath)) {\n fs.copyFileSync(backupEnvPath, path.join(process.cwd(), '.env'));\n console.log(`Restored .env from ${path.basename(backupEnvPath)}.`);\n fs.unlinkSync(backupEnvPath);\n }\n }\n\n for (const runName of runNames) {\n const envFileName = `.env.${runName}`;\n const envPath = path.join(process.cwd(), envFileName);\n if (fs.existsSync(envPath)) {\n fs.unlinkSync(envPath);\n }\n }\n\n for (const runName of runNames) {\n const databases = runs[runName]?.databases ?? {};\n await this.dropTestDatabaseObjects(databases);\n }\n\n fs.unlinkSync(manifestPath);\n console.log('✔ Test datasource env files and manifest deleted; test databases dropped.');\n }\n\n private get testDataFiles(): any[] {\n const typedSolidCoreMetadata = structuredClone(solidCoreMetadata);\n const testDataFiles = [typedSolidCoreMetadata];\n const enabledModules = getDynamicModuleNamesBasedOnMetadata();\n for (const enabledModule of enabledModules) {\n const enabledModuleSeedFile = `module-metadata/${enabledModule}/${enabledModule}-metadata.json`;\n const fullPath = path.join(process.cwd(), enabledModuleSeedFile);\n\n if (fs.existsSync(fullPath)) {\n const overallMetadata = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n testDataFiles.push(overallMetadata);\n }\n }\n\n return testDataFiles;\n }\n\n private async seedTestData(overallMetadata: any): Promise<void> {\n const moduleMetadata: CreateModuleMetadataDto = overallMetadata.moduleMetadata;\n if (!moduleMetadata) {\n throw new Error('Module metadata missing from test data payload.');\n }\n\n // console.log(JSON.stringify(moduleMetadata, null, 2));\n\n const testingData: Array<{ modelUserKey: string; data: Record<string, any> }> = overallMetadata?.testing?.data ?? [];\n if (testingData.length === 0) {\n this.logger.debug(`No test data found for ${moduleMetadata.name}`);\n return;\n }\n\n const modelsByName = new Map<string, CreateModelMetadataDto>(\n (moduleMetadata.models ?? []).map((m) => [m.singularName, m]),\n );\n\n for (const entry of testingData) {\n const modelUserKey = entry.modelUserKey;\n const modelDef = modelsByName.get(modelUserKey);\n if (!modelDef) {\n throw new Error(`Test data modelUserKey not found in metadata: ${modelUserKey}`);\n }\n\n const entityRepo = this.resolveRepository(modelUserKey);\n const payload: Record<string, any> = { ...(entry.data ?? {}) };\n\n for (const field of modelDef.fields ?? []) {\n if (field.type === 'relation' && field.relationType === 'many-to-one') {\n const userKeyProp = `${field.name}UserKey`;\n if (!(userKeyProp in payload)) {\n continue;\n }\n\n const userKeyValue = payload[userKeyProp];\n if (userKeyValue === null || userKeyValue === undefined || userKeyValue === '') {\n delete payload[userKeyProp];\n continue;\n }\n\n const coModelName = field.relationCoModelSingularName;\n const coModelDef = coModelName ? modelsByName.get(coModelName) : null;\n if (!coModelDef) {\n throw new Error(`Test data relation model ${coModelName} not found in metadata, when attempting to resolve field ${modelDef.singularName}.${field.name}`);\n }\n const coUserKeyField = coModelDef.userKeyFieldUserKey;\n if (!coUserKeyField) {\n throw new Error(`Test data relation model ${coModelName} is missing userKeyFieldUserKey, when attempting to resolve field ${modelDef.singularName}.${field.name}`);\n }\n\n const coRepo = this.resolveRepository(coModelName);\n const related = typeof coRepo.findOneByUserKey === 'function'\n ? await coRepo.findOneByUserKey(userKeyValue)\n : await coRepo.findOne({ where: { [coUserKeyField]: userKeyValue } });\n if (!related) {\n throw new Error(`Test data relation not found: ${coModelName}.${coUserKeyField}=${userKeyValue}`);\n }\n\n payload[field.name] = related;\n delete payload[userKeyProp];\n }\n }\n\n // Strip media fields from entity payload — file paths cannot be saved as columns\n const mediaPayload: Record<string, string> = {};\n for (const field of modelDef.fields ?? []) {\n if ((field.type === 'mediaSingle' || field.type === 'mediaMultiple') && payload[field.name] !== undefined) {\n mediaPayload[field.name] = payload[field.name] as string;\n delete payload[field.name];\n }\n }\n\n // Strip many-to-many and one-to-many fields — these are resolved post-save via the relation builder\n const multiRelationPayload: Array<{ field: any; userKeys: string[] }> = [];\n for (const field of modelDef.fields ?? []) {\n if (field.type !== 'relation') continue;\n if (field.relationType !== 'many-to-many' && field.relationType !== 'one-to-many') continue;\n\n const userKeysProp = `${field.name}UserKeys`;\n if (userKeysProp in payload && Array.isArray(payload[userKeysProp])) {\n multiRelationPayload.push({ field, userKeys: payload[userKeysProp] });\n delete payload[userKeysProp];\n }\n // Remove raw field value if accidentally present\n delete payload[field.name];\n }\n\n // Upsert entity, capturing the saved result for post-save steps\n let savedEntity: any;\n const userKeyField = modelDef.userKeyFieldUserKey;\n if (userKeyField && payload[userKeyField] !== undefined) {\n const existing = await entityRepo.findOne({\n where: { [userKeyField]: payload[userKeyField] },\n });\n if (existing) {\n savedEntity = await entityRepo.save(entityRepo.merge(existing, payload));\n } else {\n savedEntity = await entityRepo.save(entityRepo.create(payload));\n }\n } else {\n savedEntity = await entityRepo.save(entityRepo.create(payload));\n }\n\n if (multiRelationPayload.length > 0) {\n await this.seedMultiRelations(savedEntity.id, modelUserKey, multiRelationPayload, modelsByName);\n }\n\n if (Object.keys(mediaPayload).length > 0) {\n await this.seedEntityMedia(savedEntity.id, modelUserKey, mediaPayload);\n }\n }\n }\n\n private async seedMultiRelations(\n entityId: number,\n modelUserKey: string,\n relations: Array<{ field: any; userKeys: string[] }>,\n modelsByName: Map<string, CreateModelMetadataDto>,\n ): Promise<void> {\n for (const { field, userKeys } of relations) {\n if (!userKeys.length) continue;\n\n const coModelName = field.relationCoModelSingularName;\n const coModelDef = modelsByName.get(coModelName);\n if (!coModelDef) {\n throw new Error(`Relation model \"${coModelName}\" not found in metadata for field ${modelUserKey}.${field.name}`);\n }\n const coUserKeyField = coModelDef.userKeyFieldUserKey;\n if (!coUserKeyField) {\n throw new Error(`Relation model \"${coModelName}\" is missing userKeyFieldUserKey, needed to resolve ${modelUserKey}.${field.name}`);\n }\n\n const coRepo = this.resolveRepository(coModelName);\n const resolvedIds: number[] = [];\n for (const uk of userKeys) {\n const related = typeof coRepo.findOneByUserKey === 'function'\n ? await coRepo.findOneByUserKey(uk)\n : await coRepo.findOne({ where: { [coUserKeyField]: uk } });\n if (!related) {\n throw new Error(`Related entity not found: ${coModelName}.${coUserKeyField}=${uk}`);\n }\n resolvedIds.push(related.id);\n }\n\n // Load currently associated entities to diff (set semantics — idempotent)\n const existingRelated: any[] = await this.entityManager\n .createQueryBuilder()\n .relation(classify(modelUserKey), field.name)\n .of(entityId)\n .loadMany();\n const existingIds: number[] = existingRelated.map((e) => e.id);\n\n const toAdd = resolvedIds.filter((id) => !existingIds.includes(id));\n const toRemove = existingIds.filter((id) => !resolvedIds.includes(id));\n\n if (toAdd.length > 0 || toRemove.length > 0) {\n await this.entityManager\n .createQueryBuilder()\n .relation(classify(modelUserKey), field.name)\n .of(entityId)\n .addAndRemove(toAdd, toRemove);\n }\n\n this.logger.debug(`Seeded ${field.relationType} relation ${modelUserKey}.${field.name} entityId=${entityId}: +${toAdd.length} -${toRemove.length}`);\n }\n }\n\n private async seedEntityMedia(\n entityId: number,\n modelUserKey: string,\n mediaPayload: Record<string, string>,\n ): Promise<void> {\n const mediaBasePath = process.env.TEST_UPLOADS_MEDIA_FILE_PATH;\n if (!mediaBasePath) {\n throw new Error('TEST_UPLOADS_MEDIA_FILE_PATH is not set. Cannot seed test media.');\n }\n\n const modelMetadata = await this.modelMetadataService.findOneBySingularName(modelUserKey, {\n fields: {\n model: { userKeyField: true },\n mediaStorageProvider: true,\n },\n });\n\n for (const [fieldName, fileName] of Object.entries(mediaPayload)) {\n if (!fileName) continue;\n\n const fieldMetadata = modelMetadata.fields.find((f) => f.name === fieldName);\n if (!fieldMetadata) {\n throw new Error(`Media field \"${fieldName}\" not found in loaded metadata for model ${modelUserKey}`);\n }\n if (!fieldMetadata.mediaStorageProvider) {\n throw new Error(`Media field \"${fieldName}\" in model ${modelUserKey} has no storage provider configured`);\n }\n\n const storageProviderType = fieldMetadata.mediaStorageProvider.type as MediaStorageProviderType;\n if (storageProviderType !== MediaStorageProviderType.Filesystem) {\n throw new Error(`Test media seeding supports filesystem storage only. Field \"${fieldName}\" uses \"${storageProviderType}\".`);\n }\n\n // Idempotency: skip if media already exists for this entity + field\n const existing = await this.mediaRepository.findByEntityIdAndFieldIdAndModelMetadataId(\n entityId, fieldMetadata.id, fieldMetadata.model.id,\n );\n if (existing.length > 0) {\n this.logger.debug(`Media already seeded for ${modelUserKey}.${fieldName} entityId=${entityId}, skipping`);\n continue;\n }\n\n const sourcePath = path.join(mediaBasePath, fileName);\n if (!fs.existsSync(sourcePath)) {\n throw new Error(`Test media file not found: ${sourcePath}`);\n }\n\n const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);\n const stream = fs.createReadStream(sourcePath);\n await storageProvider.storeStreams([[stream, fileName]], { id: entityId }, fieldMetadata);\n this.logger.debug(`Seeded media for ${modelUserKey}.${fieldName} entityId=${entityId} file=${fileName}`);\n }\n }\n\n private get entityManager(): EntityManager {\n return this.moduleRef.get(EntityManager, { strict: false });\n }\n\n private get modelMetadataService(): ModelMetadataService {\n return this.moduleRef.get(ModelMetadataService, { strict: false });\n }\n\n private get mediaRepository(): MediaRepository {\n return this.moduleRef.get(MediaRepository, { strict: false });\n }\n\n private resolveRepository(modelUserKey: string): any {\n const repoName = `${classify(modelUserKey)}Repository`;\n const providers = this.discoveryService.getProviders();\n const wrapper = providers.find((provider) => provider.name === repoName);\n const repo = wrapper?.instance;\n if (repo) {\n return repo;\n }\n\n try {\n const resolved = this.moduleRef.get(repoName as any, { strict: false });\n if (resolved) {\n return resolved;\n }\n } catch {\n // fall through\n }\n\n throw new Error(`Repository not found for model ${modelUserKey}. Expected provider: ${repoName}`);\n }\n\n private generateDbRunName(): string {\n const adjectives = [\n 'brave', 'bright', 'calm', 'clever', 'curious', 'gentle', 'jolly', 'lively', 'mighty', 'nimble',\n 'proud', 'quick', 'quiet', 'sharp', 'sly', 'steady', 'swift', 'wise', 'witty', 'zesty',\n ];\n const animals = [\n 'lion', 'tiger', 'panther', 'eagle', 'falcon', 'otter', 'wolf', 'fox', 'bear', 'badger',\n 'monkey', 'panda', 'leopard', 'whale', 'dolphin', 'rhino', 'giraffe', 'camel', 'koala', 'lynx',\n ];\n const adjective = adjectives[Math.floor(Math.random() * adjectives.length)];\n const animal = animals[Math.floor(Math.random() * animals.length)];\n return `${adjective}_${animal}`;\n }\n\n private getTimestamp(): string {\n const now = new Date();\n const pad = (value: number) => value.toString().padStart(2, '0');\n return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;\n }\n\n private buildTestEnvContents(baseEnv: string, dbNameByDatasource: Map<string, string>): string {\n const datasourceNameSet = new Set(Array.from(dbNameByDatasource.keys()));\n const lines = baseEnv.split(/\\r?\\n/);\n return lines\n .map((line) => {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#') || !trimmed.includes('=')) {\n return line;\n }\n const [rawKey] = line.split('=');\n const key = rawKey.trim();\n if (!key.endsWith('_DATABASE_NAME')) {\n return line;\n }\n const prefix = key.replace(/_DATABASE_NAME$/, '').toLowerCase();\n const matchedDatasource = Array.from(datasourceNameSet).find((name) => name === prefix);\n if (!matchedDatasource) {\n return line;\n }\n const dbName = dbNameByDatasource.get(matchedDatasource);\n if (!dbName) {\n return line;\n }\n return `${key}=${dbName}`;\n })\n .join('\\n');\n }\n\n private async createTestDatabaseObjects(dbNameByDatasource: Map<string, string>): Promise<void> {\n for (const [dsName, dbName] of dbNameByDatasource.entries()) {\n const dataSource = this.resolveDataSourceByName(dsName);\n if (!dataSource.isInitialized) {\n await dataSource.initialize();\n }\n\n console.log(`Creating test database/schema \"${dbName}\" on datasource \"${dsName}\"...`);\n\n const queryRunner = dataSource.createQueryRunner();\n try {\n const type = dataSource.options.type;\n if (type === 'postgres') {\n await queryRunner.query(`CREATE DATABASE \"${dbName}\"`);\n } else if (type === 'mssql') {\n await queryRunner.query(\n `IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '${dbName}') EXEC('CREATE SCHEMA [${dbName}]')`,\n );\n } else if (type === 'mysql' || type === 'mariadb') {\n await queryRunner.query(`CREATE DATABASE IF NOT EXISTS \\`${dbName}\\``);\n } else {\n throw new Error(`Unsupported database type for test data creation: ${type}`);\n }\n } finally {\n await queryRunner.release();\n }\n }\n }\n\n private resolveDataSourceByName(datasourceName: string): DataSource {\n const token = datasourceName ? getDataSourceToken(datasourceName) : getDataSourceToken();\n try {\n const ds = this.moduleRef.get<DataSource>(token, { strict: false });\n if (!ds) {\n throw new Error(`No DataSource found for \"${datasourceName}\"`);\n }\n return ds;\n } catch (err: any) {\n throw new Error(`Failed to resolve DataSource \"${datasourceName}\": ${err?.message ?? err}`);\n }\n }\n\n private updateTestManifest(\n dbRunName: string,\n timestamp: string,\n dbNameByDatasource: Map<string, string>,\n ): void {\n const manifestPath = path.join(process.cwd(), '.solidx-test-manifest');\n let manifest: Record<string, any> = {};\n if (fs.existsSync(manifestPath)) {\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n if (parsed && typeof parsed === 'object') {\n manifest = parsed;\n }\n } catch {\n // fall through with empty manifest\n }\n }\n\n if (!manifest.runs || typeof manifest.runs !== 'object') {\n manifest.runs = {};\n }\n\n const databases: Record<string, string> = {};\n for (const [dsName, dbName] of dbNameByDatasource.entries()) {\n databases[dsName] = dbName;\n }\n\n manifest.runs[dbRunName] = {\n createdAt: timestamp,\n databases,\n };\n\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));\n }\n\n private async dropTestDatabaseObjects(databases: Record<string, string>): Promise<void> {\n const entries = Object.entries(databases);\n for (const [dsName, dbName] of entries) {\n const dataSource = this.resolveDataSourceByName(dsName);\n if (!dataSource.isInitialized) {\n await dataSource.initialize();\n }\n\n console.log(`Dropping test database/schema \"${dbName}\" on datasource \"${dsName}\"...`);\n\n const queryRunner = dataSource.createQueryRunner();\n try {\n const type = dataSource.options.type;\n if (type === 'postgres') {\n await queryRunner.query(`DROP DATABASE IF EXISTS \"${dbName}\"`);\n } else if (type === 'mssql') {\n await this.dropMssqlSchema(queryRunner, dbName);\n } else if (type === 'mysql' || type === 'mariadb') {\n await queryRunner.query(`DROP DATABASE IF EXISTS \\`${dbName}\\``);\n } else {\n throw new Error(`Unsupported database type for test data deletion: ${type}`);\n }\n } finally {\n await queryRunner.release();\n }\n }\n }\n\n private async dropMssqlSchema(queryRunner: ReturnType<DataSource['createQueryRunner']>, schemaName: string): Promise<void> {\n const foreignKeys: Array<{ fk_name: string; table_name: string }> = await queryRunner.query(\n `SELECT fk.name AS fk_name, t.name AS table_name\n FROM sys.foreign_keys fk\n INNER JOIN sys.tables t ON fk.parent_object_id = t.object_id\n INNER JOIN sys.schemas s ON t.schema_id = s.schema_id\n WHERE s.name = '${schemaName}'`,\n );\n for (const fk of foreignKeys) {\n await queryRunner.query(`ALTER TABLE [${schemaName}].[${fk.table_name}] DROP CONSTRAINT [${fk.fk_name}]`);\n }\n\n const tables: Array<{ TABLE_NAME: string }> = await queryRunner.query(\n `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${schemaName}'`,\n );\n for (const table of tables) {\n await queryRunner.query(`DROP TABLE [${schemaName}].[${table.TABLE_NAME}]`);\n }\n\n const views: Array<{ TABLE_NAME: string }> = await queryRunner.query(\n `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = '${schemaName}'`,\n );\n for (const view of views) {\n await queryRunner.query(`DROP VIEW [${schemaName}].[${view.TABLE_NAME}]`);\n }\n\n await queryRunner.query(`DROP SCHEMA [${schemaName}]`);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"module-test-data.service.js","sourceRoot":"","sources":["../../src/seeders/module-test-data.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Logger } from '@nestjs/common';\nimport { DiscoveryService, ModuleRef } from '@nestjs/core';\nimport { getDataSourceToken } from '@nestjs/typeorm';\nimport { classify } from '@angular-devkit/core/src/utils/strings';\nimport { DataSource, EntityManager } from 'typeorm';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport solidCoreMetadata from './seed-data/solid-core-metadata.json';\nimport { CreateModuleMetadataDto } from 'src/dtos/create-module-metadata.dto';\nimport { CreateModelMetadataDto } from 'src/dtos/create-model-metadata.dto';\nimport { MediaStorageProviderType } from 'src/dtos/create-media-storage-provider-metadata.dto';\nimport { getDynamicModuleNamesBasedOnMetadata } from 'src/helpers/module.helper';\nimport { SolidRegistry } from 'src/helpers/solid-registry';\nimport { MediaRepository } from 'src/repository/media.repository';\nimport { PermissionMetadataRepository } from 'src/repository/permission-metadata.repository';\nimport { AuthenticationService } from 'src/services/authentication.service';\nimport { ModelMetadataService } from 'src/services/model-metadata.service';\nimport { RoleMetadataService } from 'src/services/role-metadata.service';\nimport { UserService } from 'src/services/user.service';\nimport { getMediaStorageProvider } from 'src/services/mediaStorageProviders';\nimport { TestingRoleSpec, TestingUserSpec } from 'src/testing/contracts/testing-metadata.types';\n\n@Injectable()\nexport class ModuleTestDataService {\n private readonly logger = new Logger(ModuleTestDataService.name);\n\n constructor(\n private readonly moduleRef: ModuleRef,\n private readonly discoveryService: DiscoveryService,\n private readonly solidRegistry: SolidRegistry,\n ) {}\n\n async setupTestData(modulesToTest?: string[]): Promise<void> {\n const testDataFiles = this.testDataFiles;\n const filteredFiles = modulesToTest?.length ? testDataFiles.filter((file) => modulesToTest.includes(file.moduleMetadata?.name)) : testDataFiles;\n\n if (filteredFiles.length === 0) {\n this.logger.warn('No modules matched the provided modulesToTest list.');\n console.log('No modules matched the provided modulesToTest list.');\n return;\n }\n\n for (const overallMetadata of filteredFiles) {\n const moduleName = overallMetadata?.moduleMetadata?.name ?? 'unknown';\n this.logger.log(`Processing test data for module: ${moduleName}`);\n console.log(`Processing test data for module: ${moduleName}`);\n await this.seedTestData(overallMetadata);\n console.log(`✔ Test data setup complete for module: ${moduleName}`);\n }\n }\n\n async createTestDatasources(): Promise<void> {\n const manifestPath = path.join(process.cwd(), '.solidx-test-manifest');\n if (fs.existsSync(manifestPath)) {\n console.log('Existing .solidx-test-manifest found; skipping test datasource creation.');\n return;\n }\n\n const dbRunName = this.generateDbRunName();\n const timestamp = this.getTimestamp();\n const envPath = path.join(process.cwd(), '.env');\n if (!fs.existsSync(envPath)) {\n throw new Error(`Base .env file not found at ${envPath}`);\n }\n\n const datasourceNames = this.solidRegistry\n .getSolidDatabaseModules()\n .map((wrapper) => wrapper.instance?.name?.())\n .filter(Boolean)\n .map((name) => name.toLowerCase()) as string[];\n\n if (datasourceNames.length === 0) {\n throw new Error('No solid database modules registered; cannot create test datasources.');\n }\n\n const dbNameByDatasource = new Map<string, string>();\n for (const dsName of datasourceNames) {\n dbNameByDatasource.set(dsName, `${dsName}_${timestamp}_${dbRunName}`);\n }\n\n const newEnvContents = this.buildTestEnvContents(\n fs.readFileSync(envPath, 'utf-8'),\n dbNameByDatasource,\n );\n\n const backupEnvPath = path.join(process.cwd(), `.env.backup.${dbRunName}`);\n fs.copyFileSync(envPath, backupEnvPath);\n fs.writeFileSync(envPath, newEnvContents);\n console.log(`Backed up .env to ${path.basename(backupEnvPath)} and applied new test datasource names to .env.`);\n\n this.updateTestManifest(dbRunName, timestamp, dbNameByDatasource);\n\n await this.createTestDatabaseObjects(dbNameByDatasource);\n\n const dbList = Array.from(dbNameByDatasource.entries())\n .map(([dsName, dbName]) => `- ${dsName}: ${dbName}`)\n .join('\\n');\n\n const instructions = [\n '',\n '============================================================',\n ' TEST DATASOURCE ENVIRONMENT CREATED',\n '------------------------------------------------------------',\n ` Run name : ${dbRunName}`,\n ` Env backup : ${path.basename(backupEnvPath)}`,\n '',\n ' Test databases/schemas created:',\n dbList || ' (none)',\n '',\n ' Next steps:',\n ' 1) Using updated .env with test datasource names',\n ' 2) Run solid seed as usual',\n ' 3) Proceed with the next steps in the workflow',\n '============================================================',\n '',\n ].join('\\n');\n\n console.log(instructions);\n }\n\n async deleteTestDatasources(): Promise<void> {\n const manifestPath = path.join(process.cwd(), '.solidx-test-manifest');\n if (!fs.existsSync(manifestPath)) {\n this.logger.log('No .solidx-test-manifest found; nothing to delete.');\n console.log('No .solidx-test-manifest found; nothing to delete.');\n return;\n }\n\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) as {\n runs?: Record<string, { databases?: Record<string, string>; createdAt?: string }>;\n };\n const runs = manifest?.runs ?? {};\n const runNames = Object.keys(runs);\n if (runNames.length === 0) {\n fs.unlinkSync(manifestPath);\n return;\n }\n\n const latestRunName = runNames\n .slice()\n .sort((a, b) => {\n const aCreated = runs[a]?.createdAt ?? '';\n const bCreated = runs[b]?.createdAt ?? '';\n return aCreated.localeCompare(bCreated);\n })\n .pop();\n if (latestRunName) {\n const backupEnvPath = path.join(process.cwd(), `.env.backup.${latestRunName}`);\n if (fs.existsSync(backupEnvPath)) {\n fs.copyFileSync(backupEnvPath, path.join(process.cwd(), '.env'));\n console.log(`Restored .env from ${path.basename(backupEnvPath)}.`);\n fs.unlinkSync(backupEnvPath);\n }\n }\n\n for (const runName of runNames) {\n const envFileName = `.env.${runName}`;\n const envPath = path.join(process.cwd(), envFileName);\n if (fs.existsSync(envPath)) {\n fs.unlinkSync(envPath);\n }\n }\n\n for (const runName of runNames) {\n const databases = runs[runName]?.databases ?? {};\n await this.dropTestDatabaseObjects(databases);\n }\n\n fs.unlinkSync(manifestPath);\n console.log('✔ Test datasource env files and manifest deleted; test databases dropped.');\n }\n\n private get testDataFiles(): any[] {\n const typedSolidCoreMetadata = structuredClone(solidCoreMetadata);\n const testDataFiles = [typedSolidCoreMetadata];\n const enabledModules = getDynamicModuleNamesBasedOnMetadata();\n for (const enabledModule of enabledModules) {\n const enabledModuleSeedFile = `module-metadata/${enabledModule}/${enabledModule}-metadata.json`;\n const fullPath = path.join(process.cwd(), enabledModuleSeedFile);\n\n if (fs.existsSync(fullPath)) {\n const overallMetadata = JSON.parse(fs.readFileSync(fullPath, 'utf-8'));\n testDataFiles.push(overallMetadata);\n }\n }\n\n return testDataFiles;\n }\n\n private async seedTestData(overallMetadata: any): Promise<void> {\n const moduleMetadata: CreateModuleMetadataDto = overallMetadata.moduleMetadata;\n if (!moduleMetadata) {\n throw new Error('Module metadata missing from test data payload.');\n }\n\n // console.log(JSON.stringify(moduleMetadata, null, 2));\n\n const testingRoles: TestingRoleSpec[] = overallMetadata?.testing?.roles ?? [];\n const testingUsers: TestingUserSpec[] = overallMetadata?.testing?.users ?? [];\n const testingData: Array<{ modelUserKey: string; data: Record<string, any> }> = overallMetadata?.testing?.data ?? [];\n\n if (testingRoles.length > 0) {\n await this.seedTestRoles(testingRoles);\n }\n if (testingUsers.length > 0) {\n await this.seedTestUsers(testingUsers);\n }\n\n if (testingData.length === 0) {\n this.logger.debug(`No test data found for ${moduleMetadata.name}`);\n return;\n }\n\n const modelsByName = new Map<string, CreateModelMetadataDto>(\n (moduleMetadata.models ?? []).map((m) => [m.singularName, m]),\n );\n\n for (const entry of testingData) {\n const modelUserKey = entry.modelUserKey;\n const modelDef = modelsByName.get(modelUserKey);\n if (!modelDef) {\n throw new Error(`Test data modelUserKey not found in metadata: ${modelUserKey}`);\n }\n\n const entityRepo = this.resolveRepository(modelUserKey);\n const payload: Record<string, any> = { ...(entry.data ?? {}) };\n\n for (const field of modelDef.fields ?? []) {\n if (field.type === 'relation' && field.relationType === 'many-to-one') {\n const userKeyProp = `${field.name}UserKey`;\n if (!(userKeyProp in payload)) {\n continue;\n }\n\n const userKeyValue = payload[userKeyProp];\n if (userKeyValue === null || userKeyValue === undefined || userKeyValue === '') {\n delete payload[userKeyProp];\n continue;\n }\n\n const coModelName = field.relationCoModelSingularName;\n const coModelDef = coModelName ? modelsByName.get(coModelName) : null;\n if (!coModelDef) {\n throw new Error(`Test data relation model ${coModelName} not found in metadata, when attempting to resolve field ${modelDef.singularName}.${field.name}`);\n }\n const coUserKeyField = coModelDef.userKeyFieldUserKey;\n if (!coUserKeyField) {\n throw new Error(`Test data relation model ${coModelName} is missing userKeyFieldUserKey, when attempting to resolve field ${modelDef.singularName}.${field.name}`);\n }\n\n const coRepo = this.resolveRepository(coModelName);\n const related = typeof coRepo.findOneByUserKey === 'function'\n ? await coRepo.findOneByUserKey(userKeyValue)\n : await coRepo.findOne({ where: { [coUserKeyField]: userKeyValue } });\n if (!related) {\n throw new Error(`Test data relation not found: ${coModelName}.${coUserKeyField}=${userKeyValue}`);\n }\n\n payload[field.name] = related;\n delete payload[userKeyProp];\n }\n }\n\n // Strip media fields from entity payload — file paths cannot be saved as columns\n const mediaPayload: Record<string, string> = {};\n for (const field of modelDef.fields ?? []) {\n if ((field.type === 'mediaSingle' || field.type === 'mediaMultiple') && payload[field.name] !== undefined) {\n mediaPayload[field.name] = payload[field.name] as string;\n delete payload[field.name];\n }\n }\n\n // Strip many-to-many and one-to-many fields — these are resolved post-save via the relation builder\n const multiRelationPayload: Array<{ field: any; userKeys: string[] }> = [];\n for (const field of modelDef.fields ?? []) {\n if (field.type !== 'relation') continue;\n if (field.relationType !== 'many-to-many' && field.relationType !== 'one-to-many') continue;\n\n const userKeysProp = `${field.name}UserKeys`;\n if (userKeysProp in payload && Array.isArray(payload[userKeysProp])) {\n multiRelationPayload.push({ field, userKeys: payload[userKeysProp] });\n delete payload[userKeysProp];\n }\n // Remove raw field value if accidentally present\n delete payload[field.name];\n }\n\n // Upsert entity, capturing the saved result for post-save steps\n let savedEntity: any;\n const userKeyField = modelDef.userKeyFieldUserKey;\n if (userKeyField && payload[userKeyField] !== undefined) {\n const existing = await entityRepo.findOne({\n where: { [userKeyField]: payload[userKeyField] },\n });\n if (existing) {\n savedEntity = await entityRepo.save(entityRepo.merge(existing, payload));\n } else {\n savedEntity = await entityRepo.save(entityRepo.create(payload));\n }\n } else {\n savedEntity = await entityRepo.save(entityRepo.create(payload));\n }\n\n if (multiRelationPayload.length > 0) {\n await this.seedMultiRelations(savedEntity.id, modelUserKey, multiRelationPayload, modelsByName);\n }\n\n if (Object.keys(mediaPayload).length > 0) {\n await this.seedEntityMedia(savedEntity.id, modelUserKey, mediaPayload);\n }\n }\n }\n\n private async seedTestRoles(roles: TestingRoleSpec[]): Promise<void> {\n const roleService = this.moduleRef.get(RoleMetadataService, { strict: false });\n if (!roleService) {\n throw new Error('RoleMetadataService not available — cannot seed test roles.');\n }\n\n await roleService.createRolesIfNotExists(roles.map((r) => ({ name: r.name } as any)));\n\n for (const role of roles) {\n const perms = role.permissions ?? [];\n if (perms.length === 0) continue;\n\n if (perms.some((p) => p === '*')) {\n await roleService.addAllPermissionsToRole(role.name);\n this.logger.log(`Bound all permissions to test role \"${role.name}\"`);\n continue;\n }\n\n const expanded = await this.expandPermissionNames(perms);\n if (expanded.length === 0) {\n this.logger.warn(`Test role \"${role.name}\" has permissions declared but none resolved — skipping binding.`);\n continue;\n }\n\n try {\n await roleService.addPermissionsToRole(role.name, expanded);\n } catch (err: any) {\n throw new Error(\n `Failed to bind permissions to test role \"${role.name}\": ${err?.message ?? err}. ` +\n `Did you run \"solid seed\" first so controller permissions are registered?`,\n );\n }\n this.logger.log(`Bound ${expanded.length} permissions to test role \"${role.name}\"`);\n }\n }\n\n private async expandPermissionNames(permissions: string[]): Promise<string[]> {\n const permissionRepo = this.moduleRef.get(PermissionMetadataRepository, { strict: false });\n if (!permissionRepo) {\n throw new Error('PermissionMetadataRepository not available — cannot resolve test role permissions.');\n }\n\n const exact = new Set<string>();\n const prefixes: string[] = [];\n for (const entry of permissions) {\n if (!entry) continue;\n if (entry.endsWith('.*')) {\n prefixes.push(entry.slice(0, -1));\n } else {\n exact.add(entry);\n }\n }\n\n if (prefixes.length > 0) {\n const allPermissions = await permissionRepo.find();\n for (const p of allPermissions) {\n if (prefixes.some((prefix) => p.name.startsWith(prefix))) {\n exact.add(p.name);\n }\n }\n }\n\n return Array.from(exact);\n }\n\n private async seedTestUsers(users: TestingUserSpec[]): Promise<void> {\n const userService = this.moduleRef.get(UserService, { strict: false });\n const authService = this.moduleRef.get(AuthenticationService, { strict: false });\n if (!userService || !authService) {\n throw new Error('UserService / AuthenticationService not available — cannot seed test users.');\n }\n\n for (const user of users) {\n const existing = await userService.findOneByUsername(user.username);\n if (existing) {\n this.logger.debug(`Test user \"${user.username}\" already exists — skipping signUp.`);\n continue;\n }\n\n await authService.signUp({\n username: user.username,\n email: user.email,\n password: user.password,\n fullName: user.fullName,\n mobile: user.mobile,\n roles: user.roles,\n });\n this.logger.log(`Created test user \"${user.username}\"${user.roles?.length ? ` with roles [${user.roles.join(', ')}]` : ''}`);\n }\n }\n\n private async seedMultiRelations(\n entityId: number,\n modelUserKey: string,\n relations: Array<{ field: any; userKeys: string[] }>,\n modelsByName: Map<string, CreateModelMetadataDto>,\n ): Promise<void> {\n for (const { field, userKeys } of relations) {\n if (!userKeys.length) continue;\n\n const coModelName = field.relationCoModelSingularName;\n const coModelDef = modelsByName.get(coModelName);\n if (!coModelDef) {\n throw new Error(`Relation model \"${coModelName}\" not found in metadata for field ${modelUserKey}.${field.name}`);\n }\n const coUserKeyField = coModelDef.userKeyFieldUserKey;\n if (!coUserKeyField) {\n throw new Error(`Relation model \"${coModelName}\" is missing userKeyFieldUserKey, needed to resolve ${modelUserKey}.${field.name}`);\n }\n\n const coRepo = this.resolveRepository(coModelName);\n const resolvedIds: number[] = [];\n for (const uk of userKeys) {\n const related = typeof coRepo.findOneByUserKey === 'function'\n ? await coRepo.findOneByUserKey(uk)\n : await coRepo.findOne({ where: { [coUserKeyField]: uk } });\n if (!related) {\n throw new Error(`Related entity not found: ${coModelName}.${coUserKeyField}=${uk}`);\n }\n resolvedIds.push(related.id);\n }\n\n // Load currently associated entities to diff (set semantics — idempotent)\n const existingRelated: any[] = await this.entityManager\n .createQueryBuilder()\n .relation(classify(modelUserKey), field.name)\n .of(entityId)\n .loadMany();\n const existingIds: number[] = existingRelated.map((e) => e.id);\n\n const toAdd = resolvedIds.filter((id) => !existingIds.includes(id));\n const toRemove = existingIds.filter((id) => !resolvedIds.includes(id));\n\n if (toAdd.length > 0 || toRemove.length > 0) {\n await this.entityManager\n .createQueryBuilder()\n .relation(classify(modelUserKey), field.name)\n .of(entityId)\n .addAndRemove(toAdd, toRemove);\n }\n\n this.logger.debug(`Seeded ${field.relationType} relation ${modelUserKey}.${field.name} entityId=${entityId}: +${toAdd.length} -${toRemove.length}`);\n }\n }\n\n private async seedEntityMedia(\n entityId: number,\n modelUserKey: string,\n mediaPayload: Record<string, string>,\n ): Promise<void> {\n const mediaBasePath = process.env.TEST_UPLOADS_MEDIA_FILE_PATH;\n if (!mediaBasePath) {\n throw new Error('TEST_UPLOADS_MEDIA_FILE_PATH is not set. Cannot seed test media.');\n }\n\n const modelMetadata = await this.modelMetadataService.findOneBySingularName(modelUserKey, {\n fields: {\n model: { userKeyField: true },\n mediaStorageProvider: true,\n },\n });\n\n for (const [fieldName, fileName] of Object.entries(mediaPayload)) {\n if (!fileName) continue;\n\n const fieldMetadata = modelMetadata.fields.find((f) => f.name === fieldName);\n if (!fieldMetadata) {\n throw new Error(`Media field \"${fieldName}\" not found in loaded metadata for model ${modelUserKey}`);\n }\n if (!fieldMetadata.mediaStorageProvider) {\n throw new Error(`Media field \"${fieldName}\" in model ${modelUserKey} has no storage provider configured`);\n }\n\n const storageProviderType = fieldMetadata.mediaStorageProvider.type as MediaStorageProviderType;\n if (storageProviderType !== MediaStorageProviderType.Filesystem) {\n throw new Error(`Test media seeding supports filesystem storage only. Field \"${fieldName}\" uses \"${storageProviderType}\".`);\n }\n\n // Idempotency: skip if media already exists for this entity + field\n const existing = await this.mediaRepository.findByEntityIdAndFieldIdAndModelMetadataId(\n entityId, fieldMetadata.id, fieldMetadata.model.id,\n );\n if (existing.length > 0) {\n this.logger.debug(`Media already seeded for ${modelUserKey}.${fieldName} entityId=${entityId}, skipping`);\n continue;\n }\n\n const sourcePath = path.join(mediaBasePath, fileName);\n if (!fs.existsSync(sourcePath)) {\n throw new Error(`Test media file not found: ${sourcePath}`);\n }\n\n const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);\n const stream = fs.createReadStream(sourcePath);\n await storageProvider.storeStreams([[stream, fileName]], { id: entityId }, fieldMetadata);\n this.logger.debug(`Seeded media for ${modelUserKey}.${fieldName} entityId=${entityId} file=${fileName}`);\n }\n }\n\n private get entityManager(): EntityManager {\n return this.moduleRef.get(EntityManager, { strict: false });\n }\n\n private get modelMetadataService(): ModelMetadataService {\n return this.moduleRef.get(ModelMetadataService, { strict: false });\n }\n\n private get mediaRepository(): MediaRepository {\n return this.moduleRef.get(MediaRepository, { strict: false });\n }\n\n private resolveRepository(modelUserKey: string): any {\n const repoName = `${classify(modelUserKey)}Repository`;\n const providers = this.discoveryService.getProviders();\n const wrapper = providers.find((provider) => provider.name === repoName);\n const repo = wrapper?.instance;\n if (repo) {\n return repo;\n }\n\n try {\n const resolved = this.moduleRef.get(repoName as any, { strict: false });\n if (resolved) {\n return resolved;\n }\n } catch {\n // fall through\n }\n\n throw new Error(`Repository not found for model ${modelUserKey}. Expected provider: ${repoName}`);\n }\n\n private generateDbRunName(): string {\n const adjectives = [\n 'brave', 'bright', 'calm', 'clever', 'curious', 'gentle', 'jolly', 'lively', 'mighty', 'nimble',\n 'proud', 'quick', 'quiet', 'sharp', 'sly', 'steady', 'swift', 'wise', 'witty', 'zesty',\n ];\n const animals = [\n 'lion', 'tiger', 'panther', 'eagle', 'falcon', 'otter', 'wolf', 'fox', 'bear', 'badger',\n 'monkey', 'panda', 'leopard', 'whale', 'dolphin', 'rhino', 'giraffe', 'camel', 'koala', 'lynx',\n ];\n const adjective = adjectives[Math.floor(Math.random() * adjectives.length)];\n const animal = animals[Math.floor(Math.random() * animals.length)];\n return `${adjective}_${animal}`;\n }\n\n private getTimestamp(): string {\n const now = new Date();\n const pad = (value: number) => value.toString().padStart(2, '0');\n return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;\n }\n\n private buildTestEnvContents(baseEnv: string, dbNameByDatasource: Map<string, string>): string {\n const datasourceNameSet = new Set(Array.from(dbNameByDatasource.keys()));\n const lines = baseEnv.split(/\\r?\\n/);\n return lines\n .map((line) => {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#') || !trimmed.includes('=')) {\n return line;\n }\n const [rawKey] = line.split('=');\n const key = rawKey.trim();\n if (!key.endsWith('_DATABASE_NAME')) {\n return line;\n }\n const prefix = key.replace(/_DATABASE_NAME$/, '').toLowerCase();\n const matchedDatasource = Array.from(datasourceNameSet).find((name) => name === prefix);\n if (!matchedDatasource) {\n return line;\n }\n const dbName = dbNameByDatasource.get(matchedDatasource);\n if (!dbName) {\n return line;\n }\n return `${key}=${dbName}`;\n })\n .join('\\n');\n }\n\n private async createTestDatabaseObjects(dbNameByDatasource: Map<string, string>): Promise<void> {\n for (const [dsName, dbName] of dbNameByDatasource.entries()) {\n const dataSource = this.resolveDataSourceByName(dsName);\n if (!dataSource.isInitialized) {\n await dataSource.initialize();\n }\n\n console.log(`Creating test database/schema \"${dbName}\" on datasource \"${dsName}\"...`);\n\n const queryRunner = dataSource.createQueryRunner();\n try {\n const type = dataSource.options.type;\n if (type === 'postgres') {\n await queryRunner.query(`CREATE DATABASE \"${dbName}\"`);\n } else if (type === 'mssql') {\n await queryRunner.query(\n `IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '${dbName}') EXEC('CREATE SCHEMA [${dbName}]')`,\n );\n } else if (type === 'mysql' || type === 'mariadb') {\n await queryRunner.query(`CREATE DATABASE IF NOT EXISTS \\`${dbName}\\``);\n } else {\n throw new Error(`Unsupported database type for test data creation: ${type}`);\n }\n } finally {\n await queryRunner.release();\n }\n }\n }\n\n private resolveDataSourceByName(datasourceName: string): DataSource {\n const token = datasourceName ? getDataSourceToken(datasourceName) : getDataSourceToken();\n try {\n const ds = this.moduleRef.get<DataSource>(token, { strict: false });\n if (!ds) {\n throw new Error(`No DataSource found for \"${datasourceName}\"`);\n }\n return ds;\n } catch (err: any) {\n throw new Error(`Failed to resolve DataSource \"${datasourceName}\": ${err?.message ?? err}`);\n }\n }\n\n private updateTestManifest(\n dbRunName: string,\n timestamp: string,\n dbNameByDatasource: Map<string, string>,\n ): void {\n const manifestPath = path.join(process.cwd(), '.solidx-test-manifest');\n let manifest: Record<string, any> = {};\n if (fs.existsSync(manifestPath)) {\n try {\n const parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));\n if (parsed && typeof parsed === 'object') {\n manifest = parsed;\n }\n } catch {\n // fall through with empty manifest\n }\n }\n\n if (!manifest.runs || typeof manifest.runs !== 'object') {\n manifest.runs = {};\n }\n\n const databases: Record<string, string> = {};\n for (const [dsName, dbName] of dbNameByDatasource.entries()) {\n databases[dsName] = dbName;\n }\n\n manifest.runs[dbRunName] = {\n createdAt: timestamp,\n databases,\n };\n\n fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));\n }\n\n private async dropTestDatabaseObjects(databases: Record<string, string>): Promise<void> {\n const entries = Object.entries(databases);\n for (const [dsName, dbName] of entries) {\n const dataSource = this.resolveDataSourceByName(dsName);\n if (!dataSource.isInitialized) {\n await dataSource.initialize();\n }\n\n console.log(`Dropping test database/schema \"${dbName}\" on datasource \"${dsName}\"...`);\n\n const queryRunner = dataSource.createQueryRunner();\n try {\n const type = dataSource.options.type;\n if (type === 'postgres') {\n await queryRunner.query(`DROP DATABASE IF EXISTS \"${dbName}\"`);\n } else if (type === 'mssql') {\n await this.dropMssqlSchema(queryRunner, dbName);\n } else if (type === 'mysql' || type === 'mariadb') {\n await queryRunner.query(`DROP DATABASE IF EXISTS \\`${dbName}\\``);\n } else {\n throw new Error(`Unsupported database type for test data deletion: ${type}`);\n }\n } finally {\n await queryRunner.release();\n }\n }\n }\n\n private async dropMssqlSchema(queryRunner: ReturnType<DataSource['createQueryRunner']>, schemaName: string): Promise<void> {\n const foreignKeys: Array<{ fk_name: string; table_name: string }> = await queryRunner.query(\n `SELECT fk.name AS fk_name, t.name AS table_name\n FROM sys.foreign_keys fk\n INNER JOIN sys.tables t ON fk.parent_object_id = t.object_id\n INNER JOIN sys.schemas s ON t.schema_id = s.schema_id\n WHERE s.name = '${schemaName}'`,\n );\n for (const fk of foreignKeys) {\n await queryRunner.query(`ALTER TABLE [${schemaName}].[${fk.table_name}] DROP CONSTRAINT [${fk.fk_name}]`);\n }\n\n const tables: Array<{ TABLE_NAME: string }> = await queryRunner.query(\n `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${schemaName}'`,\n );\n for (const table of tables) {\n await queryRunner.query(`DROP TABLE [${schemaName}].[${table.TABLE_NAME}]`);\n }\n\n const views: Array<{ TABLE_NAME: string }> = await queryRunner.query(\n `SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = '${schemaName}'`,\n );\n for (const view of views) {\n await queryRunner.query(`DROP VIEW [${schemaName}].[${view.TABLE_NAME}]`);\n }\n\n await queryRunner.query(`DROP SCHEMA [${schemaName}]`);\n }\n}\n"]}
|
|
@@ -4,9 +4,23 @@ export interface TestingDataRecord {
|
|
|
4
4
|
recUserKeyValue: string;
|
|
5
5
|
data: Record<string, any>;
|
|
6
6
|
}
|
|
7
|
+
export interface TestingRoleSpec {
|
|
8
|
+
name: string;
|
|
9
|
+
permissions?: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface TestingUserSpec {
|
|
12
|
+
username: string;
|
|
13
|
+
email: string;
|
|
14
|
+
password: string;
|
|
15
|
+
fullName?: string;
|
|
16
|
+
mobile?: string;
|
|
17
|
+
roles?: string[];
|
|
18
|
+
}
|
|
7
19
|
export interface TestingMetadata {
|
|
8
20
|
testing: {
|
|
9
21
|
specs?: string[];
|
|
22
|
+
roles?: TestingRoleSpec[];
|
|
23
|
+
users?: TestingUserSpec[];
|
|
10
24
|
data?: TestingDataRecord[];
|
|
11
25
|
scenarios: ScenarioSpec[];
|
|
12
26
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing-metadata.types.d.ts","sourceRoot":"","sources":["../../../src/testing/contracts/testing-metadata.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,IAAI,GAAG,OAAO,CAAC;AAElD,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,IAAI,CAAC,EAAE,iBAAiB,EAAE,CAAC;QAC3B,SAAS,EAAE,YAAY,EAAE,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAKD,MAAM,MAAM,SAAS,GACjB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAE,GAC3B;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GACf,MAAM,CAAC;AAEX,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
|
1
|
+
{"version":3,"file":"testing-metadata.types.d.ts","sourceRoot":"","sources":["../../../src/testing/contracts/testing-metadata.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,IAAI,GAAG,OAAO,CAAC;AAElD,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;QAC1B,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;QAC1B,IAAI,CAAC,EAAE,iBAAiB,EAAE,CAAC;QAC3B,SAAS,EAAE,YAAY,EAAE,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAKD,MAAM,MAAM,SAAS,GACjB;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;CAAE,GAC3B;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GACf,MAAM,CAAC;AAEX,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing-metadata.types.js","sourceRoot":"","sources":["../../../src/testing/contracts/testing-metadata.types.ts"],"names":[],"mappings":"","sourcesContent":["export type ScenarioType = \"api\" | \"ui\" | \"mixed\";\n\nexport interface TestingDataRecord {\n modelUserKey: string;\n recUserKeyValue: string;\n data: Record<string, any>;\n}\n\nexport interface TestingMetadata {\n testing: {\n specs?: string[];\n data?: TestingDataRecord[];\n scenarios: ScenarioSpec[];\n };\n}\n\nexport interface ScenarioSpec {\n id: string;\n name?: string;\n type: ScenarioType;\n params?: Record<string, any>;\n tags?: string[];\n timeoutMs?: number;\n retries?: number;\n steps: StepBlock[];\n}\n\n/**\n * A step can be written in a phase block (Given/When/Then/And) or as a flat op step.\n */\nexport type StepBlock =\n | { given: OpStep }\n | { when: OpStep }\n | { then: OpStep | OpStep[] }\n | { and: OpStep }\n | OpStep;\n\nexport interface OpStep {\n op: string;\n with?: Record<string, any>;\n saveAs?: string;\n name?: string;\n // spec is used by op \"test.spec\" to point to a registered custom spec implementation.\n spec?: string;\n timeoutMs?: number;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"testing-metadata.types.js","sourceRoot":"","sources":["../../../src/testing/contracts/testing-metadata.types.ts"],"names":[],"mappings":"","sourcesContent":["export type ScenarioType = \"api\" | \"ui\" | \"mixed\";\n\nexport interface TestingDataRecord {\n modelUserKey: string;\n recUserKeyValue: string;\n data: Record<string, any>;\n}\n\nexport interface TestingRoleSpec {\n name: string;\n permissions?: string[];\n}\n\nexport interface TestingUserSpec {\n username: string;\n email: string;\n password: string;\n fullName?: string;\n mobile?: string;\n roles?: string[];\n}\n\nexport interface TestingMetadata {\n testing: {\n specs?: string[];\n roles?: TestingRoleSpec[];\n users?: TestingUserSpec[];\n data?: TestingDataRecord[];\n scenarios: ScenarioSpec[];\n };\n}\n\nexport interface ScenarioSpec {\n id: string;\n name?: string;\n type: ScenarioType;\n params?: Record<string, any>;\n tags?: string[];\n timeoutMs?: number;\n retries?: number;\n steps: StepBlock[];\n}\n\n/**\n * A step can be written in a phase block (Given/When/Then/And) or as a flat op step.\n */\nexport type StepBlock =\n | { given: OpStep }\n | { when: OpStep }\n | { then: OpStep | OpStep[] }\n | { and: OpStep }\n | OpStep;\n\nexport interface OpStep {\n op: string;\n with?: Record<string, any>;\n saveAs?: string;\n name?: string;\n // spec is used by op \"test.spec\" to point to a registered custom spec implementation.\n spec?: string;\n timeoutMs?: number;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -19,8 +19,8 @@ export class Setting extends CommonEntity {
|
|
|
19
19
|
@Column({ name: "level", type: "varchar", nullable: true })
|
|
20
20
|
level: string;
|
|
21
21
|
|
|
22
|
-
@Column({ name: "encrypted",
|
|
23
|
-
encrypted: boolean;
|
|
22
|
+
@Column({ name: "encrypted", default: false })
|
|
23
|
+
encrypted: boolean;
|
|
24
24
|
|
|
25
25
|
@Index()
|
|
26
26
|
@ManyToOne(() => User, { nullable: true })
|
|
@@ -13,8 +13,13 @@ import { MediaStorageProviderType } from 'src/dtos/create-media-storage-provider
|
|
|
13
13
|
import { getDynamicModuleNamesBasedOnMetadata } from 'src/helpers/module.helper';
|
|
14
14
|
import { SolidRegistry } from 'src/helpers/solid-registry';
|
|
15
15
|
import { MediaRepository } from 'src/repository/media.repository';
|
|
16
|
+
import { PermissionMetadataRepository } from 'src/repository/permission-metadata.repository';
|
|
17
|
+
import { AuthenticationService } from 'src/services/authentication.service';
|
|
16
18
|
import { ModelMetadataService } from 'src/services/model-metadata.service';
|
|
19
|
+
import { RoleMetadataService } from 'src/services/role-metadata.service';
|
|
20
|
+
import { UserService } from 'src/services/user.service';
|
|
17
21
|
import { getMediaStorageProvider } from 'src/services/mediaStorageProviders';
|
|
22
|
+
import { TestingRoleSpec, TestingUserSpec } from 'src/testing/contracts/testing-metadata.types';
|
|
18
23
|
|
|
19
24
|
@Injectable()
|
|
20
25
|
export class ModuleTestDataService {
|
|
@@ -191,7 +196,17 @@ export class ModuleTestDataService {
|
|
|
191
196
|
|
|
192
197
|
// console.log(JSON.stringify(moduleMetadata, null, 2));
|
|
193
198
|
|
|
199
|
+
const testingRoles: TestingRoleSpec[] = overallMetadata?.testing?.roles ?? [];
|
|
200
|
+
const testingUsers: TestingUserSpec[] = overallMetadata?.testing?.users ?? [];
|
|
194
201
|
const testingData: Array<{ modelUserKey: string; data: Record<string, any> }> = overallMetadata?.testing?.data ?? [];
|
|
202
|
+
|
|
203
|
+
if (testingRoles.length > 0) {
|
|
204
|
+
await this.seedTestRoles(testingRoles);
|
|
205
|
+
}
|
|
206
|
+
if (testingUsers.length > 0) {
|
|
207
|
+
await this.seedTestUsers(testingUsers);
|
|
208
|
+
}
|
|
209
|
+
|
|
195
210
|
if (testingData.length === 0) {
|
|
196
211
|
this.logger.debug(`No test data found for ${moduleMetadata.name}`);
|
|
197
212
|
return;
|
|
@@ -297,6 +312,97 @@ export class ModuleTestDataService {
|
|
|
297
312
|
}
|
|
298
313
|
}
|
|
299
314
|
|
|
315
|
+
private async seedTestRoles(roles: TestingRoleSpec[]): Promise<void> {
|
|
316
|
+
const roleService = this.moduleRef.get(RoleMetadataService, { strict: false });
|
|
317
|
+
if (!roleService) {
|
|
318
|
+
throw new Error('RoleMetadataService not available — cannot seed test roles.');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
await roleService.createRolesIfNotExists(roles.map((r) => ({ name: r.name } as any)));
|
|
322
|
+
|
|
323
|
+
for (const role of roles) {
|
|
324
|
+
const perms = role.permissions ?? [];
|
|
325
|
+
if (perms.length === 0) continue;
|
|
326
|
+
|
|
327
|
+
if (perms.some((p) => p === '*')) {
|
|
328
|
+
await roleService.addAllPermissionsToRole(role.name);
|
|
329
|
+
this.logger.log(`Bound all permissions to test role "${role.name}"`);
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const expanded = await this.expandPermissionNames(perms);
|
|
334
|
+
if (expanded.length === 0) {
|
|
335
|
+
this.logger.warn(`Test role "${role.name}" has permissions declared but none resolved — skipping binding.`);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
await roleService.addPermissionsToRole(role.name, expanded);
|
|
341
|
+
} catch (err: any) {
|
|
342
|
+
throw new Error(
|
|
343
|
+
`Failed to bind permissions to test role "${role.name}": ${err?.message ?? err}. ` +
|
|
344
|
+
`Did you run "solid seed" first so controller permissions are registered?`,
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
this.logger.log(`Bound ${expanded.length} permissions to test role "${role.name}"`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
private async expandPermissionNames(permissions: string[]): Promise<string[]> {
|
|
352
|
+
const permissionRepo = this.moduleRef.get(PermissionMetadataRepository, { strict: false });
|
|
353
|
+
if (!permissionRepo) {
|
|
354
|
+
throw new Error('PermissionMetadataRepository not available — cannot resolve test role permissions.');
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const exact = new Set<string>();
|
|
358
|
+
const prefixes: string[] = [];
|
|
359
|
+
for (const entry of permissions) {
|
|
360
|
+
if (!entry) continue;
|
|
361
|
+
if (entry.endsWith('.*')) {
|
|
362
|
+
prefixes.push(entry.slice(0, -1));
|
|
363
|
+
} else {
|
|
364
|
+
exact.add(entry);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (prefixes.length > 0) {
|
|
369
|
+
const allPermissions = await permissionRepo.find();
|
|
370
|
+
for (const p of allPermissions) {
|
|
371
|
+
if (prefixes.some((prefix) => p.name.startsWith(prefix))) {
|
|
372
|
+
exact.add(p.name);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return Array.from(exact);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private async seedTestUsers(users: TestingUserSpec[]): Promise<void> {
|
|
381
|
+
const userService = this.moduleRef.get(UserService, { strict: false });
|
|
382
|
+
const authService = this.moduleRef.get(AuthenticationService, { strict: false });
|
|
383
|
+
if (!userService || !authService) {
|
|
384
|
+
throw new Error('UserService / AuthenticationService not available — cannot seed test users.');
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
for (const user of users) {
|
|
388
|
+
const existing = await userService.findOneByUsername(user.username);
|
|
389
|
+
if (existing) {
|
|
390
|
+
this.logger.debug(`Test user "${user.username}" already exists — skipping signUp.`);
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
await authService.signUp({
|
|
395
|
+
username: user.username,
|
|
396
|
+
email: user.email,
|
|
397
|
+
password: user.password,
|
|
398
|
+
fullName: user.fullName,
|
|
399
|
+
mobile: user.mobile,
|
|
400
|
+
roles: user.roles,
|
|
401
|
+
});
|
|
402
|
+
this.logger.log(`Created test user "${user.username}"${user.roles?.length ? ` with roles [${user.roles.join(', ')}]` : ''}`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
300
406
|
private async seedMultiRelations(
|
|
301
407
|
entityId: number,
|
|
302
408
|
modelUserKey: string,
|
|
@@ -6,9 +6,25 @@ export interface TestingDataRecord {
|
|
|
6
6
|
data: Record<string, any>;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export interface TestingRoleSpec {
|
|
10
|
+
name: string;
|
|
11
|
+
permissions?: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface TestingUserSpec {
|
|
15
|
+
username: string;
|
|
16
|
+
email: string;
|
|
17
|
+
password: string;
|
|
18
|
+
fullName?: string;
|
|
19
|
+
mobile?: string;
|
|
20
|
+
roles?: string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
export interface TestingMetadata {
|
|
10
24
|
testing: {
|
|
11
25
|
specs?: string[];
|
|
26
|
+
roles?: TestingRoleSpec[];
|
|
27
|
+
users?: TestingUserSpec[];
|
|
12
28
|
data?: TestingDataRecord[];
|
|
13
29
|
scenarios: ScenarioSpec[];
|
|
14
30
|
};
|