feat(opsserver,web): replace the Angular UI and REST management layer with a TypedRequest-based ops server and bundled web frontend
This commit is contained in:
@@ -1,18 +1,18 @@
|
||||
version: "3.8"
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
mongodb-test:
|
||||
image: mongo:7
|
||||
container_name: stack-gallery-test-mongo
|
||||
ports:
|
||||
- "27117:27017"
|
||||
- '27117:27017'
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: testadmin
|
||||
MONGO_INITDB_ROOT_PASSWORD: testpass
|
||||
tmpfs:
|
||||
- /data/db
|
||||
healthcheck:
|
||||
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||
test: ['CMD', 'mongosh', '--eval', "db.adminCommand('ping')"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
@@ -21,8 +21,8 @@ services:
|
||||
image: minio/minio:latest
|
||||
container_name: stack-gallery-test-minio
|
||||
ports:
|
||||
- "9100:9000"
|
||||
- "9101:9001"
|
||||
- '9100:9000'
|
||||
- '9101:9001'
|
||||
environment:
|
||||
MINIO_ROOT_USER: testadmin
|
||||
MINIO_ROOT_PASSWORD: testpassword
|
||||
@@ -30,7 +30,7 @@ services:
|
||||
tmpfs:
|
||||
- /data
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live']
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
@@ -6,25 +6,25 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import * as path from '@std/path';
|
||||
import {
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
cleanupTestDb,
|
||||
createTestUser,
|
||||
createOrgWithOwner,
|
||||
createTestRepository,
|
||||
createTestApiToken,
|
||||
clients,
|
||||
skipIfMissing,
|
||||
createOrgWithOwner,
|
||||
createTestApiToken,
|
||||
createTestRepository,
|
||||
createTestUser,
|
||||
runCommand,
|
||||
setupTestDb,
|
||||
skipIfMissing,
|
||||
teardownTestDb,
|
||||
testConfig,
|
||||
} from '../helpers/index.ts';
|
||||
|
||||
const FIXTURE_DIR = path.join(
|
||||
path.dirname(path.fromFileUrl(import.meta.url)),
|
||||
'../fixtures/npm/@stack-test/demo-package'
|
||||
'../fixtures/npm/@stack-test/demo-package',
|
||||
);
|
||||
|
||||
describe('NPM E2E: Full lifecycle', () => {
|
||||
@@ -98,7 +98,7 @@ describe('NPM E2E: Full lifecycle', () => {
|
||||
const result = await clients.npm.publish(
|
||||
FIXTURE_DIR,
|
||||
`${registryUrl}/-/npm/${testOrgName}/`,
|
||||
apiToken
|
||||
apiToken,
|
||||
);
|
||||
|
||||
assertEquals(result.success, true, `npm publish failed: ${result.stderr}`);
|
||||
@@ -120,20 +120,28 @@ describe('NPM E2E: Full lifecycle', () => {
|
||||
|
||||
// First publish
|
||||
const npmrcPath = path.join(FIXTURE_DIR, '.npmrc');
|
||||
const npmrcContent = `//${new URL(registryUrl).host}/-/npm/${testOrgName}/:_authToken=${apiToken}`;
|
||||
const npmrcContent = `//${
|
||||
new URL(registryUrl).host
|
||||
}/-/npm/${testOrgName}/:_authToken=${apiToken}`;
|
||||
await Deno.writeTextFile(npmrcPath, npmrcContent);
|
||||
|
||||
try {
|
||||
await clients.npm.publish(
|
||||
FIXTURE_DIR,
|
||||
`${registryUrl}/-/npm/${testOrgName}/`,
|
||||
apiToken
|
||||
apiToken,
|
||||
);
|
||||
|
||||
// Fetch metadata via npm view
|
||||
const viewResult = await runCommand(
|
||||
['npm', 'view', '@stack-test/demo-package', '--registry', `${registryUrl}/-/npm/${testOrgName}/`],
|
||||
{ env: { npm_config__authToken: apiToken } }
|
||||
[
|
||||
'npm',
|
||||
'view',
|
||||
'@stack-test/demo-package',
|
||||
'--registry',
|
||||
`${registryUrl}/-/npm/${testOrgName}/`,
|
||||
],
|
||||
{ env: { npm_config__authToken: apiToken } },
|
||||
);
|
||||
|
||||
assertEquals(viewResult.success, true, `npm view failed: ${viewResult.stderr}`);
|
||||
@@ -159,32 +167,36 @@ describe('NPM E2E: Full lifecycle', () => {
|
||||
try {
|
||||
// First publish
|
||||
const npmrcPath = path.join(FIXTURE_DIR, '.npmrc');
|
||||
const npmrcContent = `//${new URL(registryUrl).host}/-/npm/${testOrgName}/:_authToken=${apiToken}`;
|
||||
const npmrcContent = `//${
|
||||
new URL(registryUrl).host
|
||||
}/-/npm/${testOrgName}/:_authToken=${apiToken}`;
|
||||
await Deno.writeTextFile(npmrcPath, npmrcContent);
|
||||
|
||||
await clients.npm.publish(
|
||||
FIXTURE_DIR,
|
||||
`${registryUrl}/-/npm/${testOrgName}/`,
|
||||
apiToken
|
||||
apiToken,
|
||||
);
|
||||
|
||||
// Create package.json in temp dir
|
||||
await Deno.writeTextFile(
|
||||
path.join(tempDir, 'package.json'),
|
||||
JSON.stringify({ name: 'test-install', version: '1.0.0' })
|
||||
JSON.stringify({ name: 'test-install', version: '1.0.0' }),
|
||||
);
|
||||
|
||||
// Create .npmrc in temp dir
|
||||
await Deno.writeTextFile(
|
||||
path.join(tempDir, '.npmrc'),
|
||||
`@stack-test:registry=${registryUrl}/-/npm/${testOrgName}/\n//${new URL(registryUrl).host}/-/npm/${testOrgName}/:_authToken=${apiToken}`
|
||||
`@stack-test:registry=${registryUrl}/-/npm/${testOrgName}/\n//${
|
||||
new URL(registryUrl).host
|
||||
}/-/npm/${testOrgName}/:_authToken=${apiToken}`,
|
||||
);
|
||||
|
||||
// Install
|
||||
const installResult = await clients.npm.install(
|
||||
'@stack-test/demo-package@1.0.0',
|
||||
`${registryUrl}/-/npm/${testOrgName}/`,
|
||||
tempDir
|
||||
tempDir,
|
||||
);
|
||||
|
||||
assertEquals(installResult.success, true, `npm install failed: ${installResult.stderr}`);
|
||||
@@ -213,33 +225,41 @@ describe('NPM E2E: Full lifecycle', () => {
|
||||
|
||||
// First publish
|
||||
const npmrcPath = path.join(FIXTURE_DIR, '.npmrc');
|
||||
const npmrcContent = `//${new URL(registryUrl).host}/-/npm/${testOrgName}/:_authToken=${apiToken}`;
|
||||
const npmrcContent = `//${
|
||||
new URL(registryUrl).host
|
||||
}/-/npm/${testOrgName}/:_authToken=${apiToken}`;
|
||||
await Deno.writeTextFile(npmrcPath, npmrcContent);
|
||||
|
||||
try {
|
||||
await clients.npm.publish(
|
||||
FIXTURE_DIR,
|
||||
`${registryUrl}/-/npm/${testOrgName}/`,
|
||||
apiToken
|
||||
apiToken,
|
||||
);
|
||||
|
||||
// Unpublish
|
||||
const unpublishResult = await clients.npm.unpublish(
|
||||
'@stack-test/demo-package@1.0.0',
|
||||
`${registryUrl}/-/npm/${testOrgName}/`,
|
||||
apiToken
|
||||
apiToken,
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
unpublishResult.success,
|
||||
true,
|
||||
`npm unpublish failed: ${unpublishResult.stderr}`
|
||||
`npm unpublish failed: ${unpublishResult.stderr}`,
|
||||
);
|
||||
|
||||
// Verify package is gone
|
||||
const viewResult = await runCommand(
|
||||
['npm', 'view', '@stack-test/demo-package', '--registry', `${registryUrl}/-/npm/${testOrgName}/`],
|
||||
{ env: { npm_config__authToken: apiToken } }
|
||||
[
|
||||
'npm',
|
||||
'view',
|
||||
'@stack-test/demo-package',
|
||||
'--registry',
|
||||
`${registryUrl}/-/npm/${testOrgName}/`,
|
||||
],
|
||||
{ env: { npm_config__authToken: apiToken } },
|
||||
);
|
||||
|
||||
// Should fail since package was unpublished
|
||||
|
||||
@@ -6,24 +6,24 @@
|
||||
*/
|
||||
|
||||
import { assertEquals } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import * as path from '@std/path';
|
||||
import {
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
cleanupTestDb,
|
||||
createTestUser,
|
||||
createOrgWithOwner,
|
||||
createTestRepository,
|
||||
createTestApiToken,
|
||||
clients,
|
||||
createOrgWithOwner,
|
||||
createTestApiToken,
|
||||
createTestRepository,
|
||||
createTestUser,
|
||||
setupTestDb,
|
||||
skipIfMissing,
|
||||
teardownTestDb,
|
||||
testConfig,
|
||||
} from '../helpers/index.ts';
|
||||
|
||||
const FIXTURE_DIR = path.join(
|
||||
path.dirname(path.fromFileUrl(import.meta.url)),
|
||||
'../fixtures/oci'
|
||||
'../fixtures/oci',
|
||||
);
|
||||
|
||||
describe('OCI E2E: Full lifecycle', () => {
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"name": "stacktest/demo-package",
|
||||
"description": "Demo package for Stack.Gallery Registry e2e tests",
|
||||
"version": "1.0.0",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Stack.Gallery Test",
|
||||
"email": "test@stack.gallery"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"StackTest\\DemoPackage\\": "src/"
|
||||
}
|
||||
"name": "stacktest/demo-package",
|
||||
"description": "Demo package for Stack.Gallery Registry e2e tests",
|
||||
"version": "1.0.0",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Stack.Gallery Test",
|
||||
"email": "test@stack.gallery"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"StackTest\\DemoPackage\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.stacktest</groupId>
|
||||
<artifactId>demo-artifact</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>Stack.Gallery Demo Artifact</name>
|
||||
<description>Demo Maven artifact for e2e tests</description>
|
||||
<url>https://github.com/stack-gallery/demo-artifact</url>
|
||||
<project
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.stacktest</groupId>
|
||||
<artifactId>demo-artifact</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>Stack.Gallery Demo Artifact</name>
|
||||
<description>Demo Maven artifact for e2e tests</description>
|
||||
<url>https://github.com/stack-gallery/demo-artifact</url>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>https://opensource.org/licenses/MIT</url>
|
||||
</license>
|
||||
</licenses>
|
||||
<licenses>
|
||||
<license>
|
||||
<name>MIT License</name>
|
||||
<url>https://opensource.org/licenses/MIT</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Stack.Gallery Test</name>
|
||||
<email>test@stack.gallery</email>
|
||||
</developer>
|
||||
</developers>
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Stack.Gallery Test</name>
|
||||
<email>test@stack.gallery</email>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
module.exports = {
|
||||
name: 'demo-package',
|
||||
greet: (name) => `Hello, ${name}!`,
|
||||
version: () => require('./package.json').version
|
||||
version: () => require('./package.json').version,
|
||||
};
|
||||
|
||||
@@ -6,7 +6,11 @@ import { User } from '../../ts/models/user.ts';
|
||||
import { ApiToken } from '../../ts/models/apitoken.ts';
|
||||
import { AuthService } from '../../ts/services/auth.service.ts';
|
||||
import { TokenService } from '../../ts/services/token.service.ts';
|
||||
import type { TRegistryProtocol, ITokenScope, TUserStatus } from '../../ts/interfaces/auth.interfaces.ts';
|
||||
import type {
|
||||
ITokenScope,
|
||||
TRegistryProtocol,
|
||||
TUserStatus,
|
||||
} from '../../ts/interfaces/auth.interfaces.ts';
|
||||
import { testConfig } from '../test.config.ts';
|
||||
|
||||
const TEST_PASSWORD = 'TestPassword123!';
|
||||
@@ -25,7 +29,7 @@ export interface ICreateTestUserOptions {
|
||||
* Create a test user with sensible defaults
|
||||
*/
|
||||
export async function createTestUser(
|
||||
overrides: ICreateTestUserOptions = {}
|
||||
overrides: ICreateTestUserOptions = {},
|
||||
): Promise<{ user: User; password: string }> {
|
||||
const uniqueId = crypto.randomUUID().slice(0, 8);
|
||||
const password = overrides.password || TEST_PASSWORD;
|
||||
@@ -61,7 +65,7 @@ export async function createAdminUser(): Promise<{ user: User; password: string
|
||||
*/
|
||||
export async function loginUser(
|
||||
email: string,
|
||||
password: string
|
||||
password: string,
|
||||
): Promise<{ accessToken: string; refreshToken: string; sessionId: string }> {
|
||||
const authService = new AuthService({
|
||||
jwtSecret: testConfig.jwt.secret,
|
||||
@@ -96,7 +100,7 @@ export interface ICreateTestApiTokenOptions {
|
||||
* Create test API token
|
||||
*/
|
||||
export async function createTestApiToken(
|
||||
options: ICreateTestApiTokenOptions
|
||||
options: ICreateTestApiTokenOptions,
|
||||
): Promise<{ rawToken: string; token: ApiToken }> {
|
||||
const tokenService = new TokenService();
|
||||
|
||||
@@ -127,7 +131,7 @@ export function createAuthHeader(token: string): { Authorization: string } {
|
||||
*/
|
||||
export function createBasicAuthHeader(
|
||||
username: string,
|
||||
password: string
|
||||
password: string,
|
||||
): { Authorization: string } {
|
||||
const credentials = btoa(`${username}:${password}`);
|
||||
return { Authorization: `Basic ${credentials}` };
|
||||
|
||||
@@ -15,7 +15,7 @@ let isConnected = false;
|
||||
|
||||
// We need to patch the global db export since models reference it
|
||||
// This is done by re-initializing with the test config
|
||||
import { initDb, closeDb } from '../../ts/models/db.ts';
|
||||
import { closeDb, initDb } from '../../ts/models/db.ts';
|
||||
|
||||
/**
|
||||
* Initialize test database with unique name per test run
|
||||
|
||||
@@ -11,10 +11,10 @@ import { Package } from '../../ts/models/package.ts';
|
||||
import { RepositoryPermission } from '../../ts/models/repository.permission.ts';
|
||||
import type {
|
||||
TOrganizationRole,
|
||||
TTeamRole,
|
||||
TRegistryProtocol,
|
||||
TRepositoryRole,
|
||||
TRepositoryVisibility,
|
||||
TRegistryProtocol,
|
||||
TTeamRole,
|
||||
} from '../../ts/interfaces/auth.interfaces.ts';
|
||||
|
||||
export interface ICreateTestOrganizationOptions {
|
||||
@@ -29,7 +29,7 @@ export interface ICreateTestOrganizationOptions {
|
||||
* Create test organization
|
||||
*/
|
||||
export async function createTestOrganization(
|
||||
options: ICreateTestOrganizationOptions
|
||||
options: ICreateTestOrganizationOptions,
|
||||
): Promise<Organization> {
|
||||
const uniqueId = crypto.randomUUID().slice(0, 8);
|
||||
|
||||
@@ -53,7 +53,7 @@ export async function createTestOrganization(
|
||||
*/
|
||||
export async function createOrgWithOwner(
|
||||
ownerId: string,
|
||||
orgOptions?: Partial<ICreateTestOrganizationOptions>
|
||||
orgOptions?: Partial<ICreateTestOrganizationOptions>,
|
||||
): Promise<{
|
||||
organization: Organization;
|
||||
membership: OrganizationMember;
|
||||
@@ -82,7 +82,7 @@ export async function addOrgMember(
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
role: TOrganizationRole = 'member',
|
||||
invitedBy?: string
|
||||
invitedBy?: string,
|
||||
): Promise<OrganizationMember> {
|
||||
const membership = await OrganizationMember.addMember({
|
||||
organizationId,
|
||||
@@ -113,7 +113,7 @@ export interface ICreateTestRepositoryOptions {
|
||||
* Create test repository
|
||||
*/
|
||||
export async function createTestRepository(
|
||||
options: ICreateTestRepositoryOptions
|
||||
options: ICreateTestRepositoryOptions,
|
||||
): Promise<Repository> {
|
||||
const uniqueId = crypto.randomUUID().slice(0, 8);
|
||||
|
||||
@@ -152,7 +152,7 @@ export async function createTestTeam(options: ICreateTestTeamOptions): Promise<T
|
||||
export async function addTeamMember(
|
||||
teamId: string,
|
||||
userId: string,
|
||||
role: TTeamRole = 'member'
|
||||
role: TTeamRole = 'member',
|
||||
): Promise<TeamMember> {
|
||||
const member = new TeamMember();
|
||||
member.id = await TeamMember.getNewId();
|
||||
@@ -176,7 +176,7 @@ export interface IGrantRepoPermissionOptions {
|
||||
* Grant repository permission
|
||||
*/
|
||||
export async function grantRepoPermission(
|
||||
options: IGrantRepoPermissionOptions
|
||||
options: IGrantRepoPermissionOptions,
|
||||
): Promise<RepositoryPermission> {
|
||||
const perm = new RepositoryPermission();
|
||||
perm.id = await RepositoryPermission.getNewId();
|
||||
|
||||
@@ -75,7 +75,7 @@ export const del = (path: string, headers?: Record<string, string>) =>
|
||||
export function assertStatus(response: ITestResponse, expected: number): void {
|
||||
if (response.status !== expected) {
|
||||
throw new Error(
|
||||
`Expected status ${expected} but got ${response.status}: ${JSON.stringify(response.body)}`
|
||||
`Expected status ${expected} but got ${response.status}: ${JSON.stringify(response.body)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export function assertBodyHas(response: ITestResponse, keys: string[]): void {
|
||||
export function assertSuccess(response: ITestResponse): void {
|
||||
if (response.status < 200 || response.status >= 300) {
|
||||
throw new Error(
|
||||
`Expected successful response but got ${response.status}: ${JSON.stringify(response.body)}`
|
||||
`Expected successful response but got ${response.status}: ${JSON.stringify(response.body)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,82 +4,82 @@
|
||||
|
||||
// Database helpers
|
||||
export {
|
||||
setupTestDb,
|
||||
cleanupTestDb,
|
||||
teardownTestDb,
|
||||
clearCollections,
|
||||
getTestDbName,
|
||||
getTestDb,
|
||||
getTestDbName,
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
} from './db.helper.ts';
|
||||
|
||||
// Auth helpers
|
||||
export {
|
||||
createTestUser,
|
||||
createAdminUser,
|
||||
loginUser,
|
||||
createTestApiToken,
|
||||
createAuthHeader,
|
||||
createBasicAuthHeader,
|
||||
createTestApiToken,
|
||||
createTestUser,
|
||||
getTestPassword,
|
||||
type ICreateTestUserOptions,
|
||||
type ICreateTestApiTokenOptions,
|
||||
type ICreateTestUserOptions,
|
||||
loginUser,
|
||||
} from './auth.helper.ts';
|
||||
|
||||
// Factory helpers
|
||||
export {
|
||||
createTestOrganization,
|
||||
createOrgWithOwner,
|
||||
addOrgMember,
|
||||
addTeamMember,
|
||||
createFullTestScenario,
|
||||
createOrgWithOwner,
|
||||
createTestOrganization,
|
||||
createTestPackage,
|
||||
createTestRepository,
|
||||
createTestTeam,
|
||||
addTeamMember,
|
||||
grantRepoPermission,
|
||||
createTestPackage,
|
||||
createFullTestScenario,
|
||||
type ICreateTestOrganizationOptions,
|
||||
type ICreateTestPackageOptions,
|
||||
type ICreateTestRepositoryOptions,
|
||||
type ICreateTestTeamOptions,
|
||||
type IGrantRepoPermissionOptions,
|
||||
type ICreateTestPackageOptions,
|
||||
} from './factory.helper.ts';
|
||||
|
||||
// HTTP helpers
|
||||
export {
|
||||
testRequest,
|
||||
get,
|
||||
post,
|
||||
put,
|
||||
patch,
|
||||
del,
|
||||
assertStatus,
|
||||
assertBodyHas,
|
||||
assertSuccess,
|
||||
assertError,
|
||||
assertStatus,
|
||||
assertSuccess,
|
||||
del,
|
||||
get,
|
||||
type ITestRequest,
|
||||
type ITestResponse,
|
||||
patch,
|
||||
post,
|
||||
put,
|
||||
testRequest,
|
||||
} from './http.helper.ts';
|
||||
|
||||
// Subprocess helpers
|
||||
export {
|
||||
runCommand,
|
||||
commandExists,
|
||||
clients,
|
||||
skipIfMissing,
|
||||
type ICommandResult,
|
||||
commandExists,
|
||||
type ICommandOptions,
|
||||
type ICommandResult,
|
||||
runCommand,
|
||||
skipIfMissing,
|
||||
} from './subprocess.helper.ts';
|
||||
|
||||
// Storage helpers
|
||||
export {
|
||||
setupTestStorage,
|
||||
checkStorageAvailable,
|
||||
objectExists,
|
||||
listObjects,
|
||||
cleanupTestStorage,
|
||||
deleteObject,
|
||||
deletePrefix,
|
||||
cleanupTestStorage,
|
||||
isStorageAvailable,
|
||||
listObjects,
|
||||
objectExists,
|
||||
setupTestStorage,
|
||||
} from './storage.helper.ts';
|
||||
|
||||
// Re-export test config
|
||||
export { testConfig, getTestConfig } from '../test.config.ts';
|
||||
export { getTestConfig, testConfig } from '../test.config.ts';
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface ICommandOptions {
|
||||
*/
|
||||
export async function runCommand(
|
||||
cmd: string[],
|
||||
options: ICommandOptions = {}
|
||||
options: ICommandOptions = {},
|
||||
): Promise<ICommandResult> {
|
||||
const { cwd, env, timeout = 60000, stdin } = options;
|
||||
|
||||
@@ -116,7 +116,7 @@ export const clients = {
|
||||
publish: (dir: string, registry: string, token: string) =>
|
||||
runCommand(
|
||||
['cargo', 'publish', '--registry', 'stack-test', '--token', token, '--allow-dirty'],
|
||||
{ cwd: dir }
|
||||
{ cwd: dir },
|
||||
),
|
||||
yank: (crate: string, version: string, token: string) =>
|
||||
runCommand([
|
||||
@@ -164,7 +164,7 @@ export const clients = {
|
||||
'--repository',
|
||||
JSON.stringify({ type: 'composer', url: repository }),
|
||||
],
|
||||
{ cwd: dir }
|
||||
{ cwd: dir },
|
||||
),
|
||||
},
|
||||
|
||||
@@ -190,7 +190,7 @@ export const clients = {
|
||||
`-Dusername=${username}`,
|
||||
`-Dpassword=${password}`,
|
||||
],
|
||||
{ cwd: dir }
|
||||
{ cwd: dir },
|
||||
),
|
||||
package: (dir: string) => runCommand(['mvn', 'package', '-DskipTests'], { cwd: dir }),
|
||||
},
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import {
|
||||
assertStatus,
|
||||
cleanupTestDb,
|
||||
createAuthHeader,
|
||||
createTestUser,
|
||||
get,
|
||||
post,
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
cleanupTestDb,
|
||||
createTestUser,
|
||||
post,
|
||||
get,
|
||||
assertStatus,
|
||||
createAuthHeader,
|
||||
} from '../helpers/index.ts';
|
||||
|
||||
describe('Auth API Integration', () => {
|
||||
@@ -126,7 +126,7 @@ describe('Auth API Integration', () => {
|
||||
// Get current user
|
||||
const meResponse = await get(
|
||||
'/api/v1/auth/me',
|
||||
createAuthHeader(loginBody.accessToken as string)
|
||||
createAuthHeader(loginBody.accessToken as string),
|
||||
);
|
||||
|
||||
assertStatus(meResponse, 200);
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import {
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
assertStatus,
|
||||
cleanupTestDb,
|
||||
createAuthHeader,
|
||||
createTestUser,
|
||||
del,
|
||||
get,
|
||||
loginUser,
|
||||
post,
|
||||
get,
|
||||
put,
|
||||
del,
|
||||
assertStatus,
|
||||
createAuthHeader,
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
} from '../helpers/index.ts';
|
||||
|
||||
describe('Organization API Integration', () => {
|
||||
@@ -48,7 +48,7 @@ describe('Organization API Integration', () => {
|
||||
displayName: 'My Organization',
|
||||
description: 'A test organization',
|
||||
},
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
assertStatus(response, 201);
|
||||
@@ -64,7 +64,7 @@ describe('Organization API Integration', () => {
|
||||
name: 'push.rocks',
|
||||
displayName: 'Push Rocks',
|
||||
},
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
assertStatus(response, 201);
|
||||
@@ -76,13 +76,13 @@ describe('Organization API Integration', () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'duplicate', displayName: 'First' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
const response = await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'duplicate', displayName: 'Second' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
assertStatus(response, 409);
|
||||
@@ -92,7 +92,7 @@ describe('Organization API Integration', () => {
|
||||
const response = await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: '.invalid', displayName: 'Invalid' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
assertStatus(response, 400);
|
||||
@@ -105,12 +105,12 @@ describe('Organization API Integration', () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'org1', displayName: 'Org 1' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'org2', displayName: 'Org 2' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
const response = await get('/api/v1/organizations', createAuthHeader(accessToken));
|
||||
@@ -126,7 +126,7 @@ describe('Organization API Integration', () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'get-me', displayName: 'Get Me' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
const response = await get('/api/v1/organizations/get-me', createAuthHeader(accessToken));
|
||||
@@ -139,7 +139,7 @@ describe('Organization API Integration', () => {
|
||||
it('should return 404 for non-existent org', async () => {
|
||||
const response = await get(
|
||||
'/api/v1/organizations/non-existent',
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
assertStatus(response, 404);
|
||||
@@ -151,13 +151,13 @@ describe('Organization API Integration', () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'update-me', displayName: 'Original' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
const response = await put(
|
||||
'/api/v1/organizations/update-me',
|
||||
{ displayName: 'Updated', description: 'New description' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
assertStatus(response, 200);
|
||||
@@ -172,7 +172,7 @@ describe('Organization API Integration', () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'delete-me', displayName: 'Delete Me' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
const response = await del('/api/v1/organizations/delete-me', createAuthHeader(accessToken));
|
||||
@@ -182,7 +182,7 @@ describe('Organization API Integration', () => {
|
||||
// Verify deleted
|
||||
const getResponse = await get(
|
||||
'/api/v1/organizations/delete-me',
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
assertStatus(getResponse, 404);
|
||||
});
|
||||
@@ -193,12 +193,12 @@ describe('Organization API Integration', () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'members-org', displayName: 'Members Org' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
const response = await get(
|
||||
'/api/v1/organizations/members-org/members',
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
assertStatus(response, 200);
|
||||
@@ -213,13 +213,13 @@ describe('Organization API Integration', () => {
|
||||
await post(
|
||||
'/api/v1/organizations',
|
||||
{ name: 'add-member-org', displayName: 'Add Member Org' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
const response = await post(
|
||||
'/api/v1/organizations/add-member-org/members',
|
||||
{ userId: newUser.id, role: 'member' },
|
||||
createAuthHeader(accessToken)
|
||||
createAuthHeader(accessToken),
|
||||
);
|
||||
|
||||
assertStatus(response, 201);
|
||||
|
||||
@@ -7,10 +7,10 @@ import { Qenv } from '@push.rocks/qenv';
|
||||
|
||||
const testQenv = new Qenv('./', '.nogit/', false);
|
||||
|
||||
const mongoUrl = await testQenv.getEnvVarOnDemand('MONGODB_URL')
|
||||
|| 'mongodb://testadmin:testpass@localhost:27117/test-registry?authSource=admin';
|
||||
const mongoName = await testQenv.getEnvVarOnDemand('MONGODB_NAME')
|
||||
|| 'test-registry';
|
||||
const mongoUrl = await testQenv.getEnvVarOnDemand('MONGODB_URL') ||
|
||||
'mongodb://testadmin:testpass@localhost:27117/test-registry?authSource=admin';
|
||||
const mongoName = await testQenv.getEnvVarOnDemand('MONGODB_NAME') ||
|
||||
'test-registry';
|
||||
|
||||
const s3Endpoint = await testQenv.getEnvVarOnDemand('S3_ENDPOINT') || 'localhost';
|
||||
const s3Port = await testQenv.getEnvVarOnDemand('S3_PORT') || '9100';
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { setupTestDb, teardownTestDb, cleanupTestDb, createTestUser } from '../../helpers/index.ts';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import { cleanupTestDb, createTestUser, setupTestDb, teardownTestDb } from '../../helpers/index.ts';
|
||||
import { ApiToken } from '../../../ts/models/apitoken.ts';
|
||||
|
||||
describe('ApiToken Model', () => {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists, assertRejects } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { setupTestDb, teardownTestDb, cleanupTestDb, createTestUser } from '../../helpers/index.ts';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import { cleanupTestDb, createTestUser, setupTestDb, teardownTestDb } from '../../helpers/index.ts';
|
||||
import { Organization } from '../../../ts/models/organization.ts';
|
||||
|
||||
describe('Organization Model', () => {
|
||||
@@ -73,7 +73,7 @@ describe('Organization Model', () => {
|
||||
});
|
||||
},
|
||||
Error,
|
||||
'lowercase alphanumeric'
|
||||
'lowercase alphanumeric',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ describe('Organization Model', () => {
|
||||
});
|
||||
},
|
||||
Error,
|
||||
'lowercase alphanumeric'
|
||||
'lowercase alphanumeric',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -101,7 +101,7 @@ describe('Organization Model', () => {
|
||||
});
|
||||
},
|
||||
Error,
|
||||
'lowercase alphanumeric'
|
||||
'lowercase alphanumeric',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -115,7 +115,7 @@ describe('Organization Model', () => {
|
||||
});
|
||||
},
|
||||
Error,
|
||||
'lowercase alphanumeric'
|
||||
'lowercase alphanumeric',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import {
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
cleanupTestDb,
|
||||
createTestUser,
|
||||
createOrgWithOwner,
|
||||
createTestRepository,
|
||||
createTestUser,
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
} from '../../helpers/index.ts';
|
||||
import { Package } from '../../../ts/models/package.ts';
|
||||
import type { IPackageVersion } from '../../../ts/interfaces/package.interfaces.ts';
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists, assertRejects } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import {
|
||||
cleanupTestDb,
|
||||
createOrgWithOwner,
|
||||
createTestUser,
|
||||
setupTestDb,
|
||||
teardownTestDb,
|
||||
cleanupTestDb,
|
||||
createTestUser,
|
||||
createOrgWithOwner,
|
||||
} from '../../helpers/index.ts';
|
||||
import { Repository } from '../../../ts/models/repository.ts';
|
||||
|
||||
@@ -103,7 +103,7 @@ describe('Repository Model', () => {
|
||||
});
|
||||
},
|
||||
Error,
|
||||
'already exists'
|
||||
'already exists',
|
||||
);
|
||||
});
|
||||
|
||||
@@ -137,7 +137,7 @@ describe('Repository Model', () => {
|
||||
});
|
||||
},
|
||||
Error,
|
||||
'lowercase alphanumeric'
|
||||
'lowercase alphanumeric',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { setupTestDb, teardownTestDb, cleanupTestDb, createTestUser } from '../../helpers/index.ts';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import { cleanupTestDb, createTestUser, setupTestDb, teardownTestDb } from '../../helpers/index.ts';
|
||||
import { Session } from '../../../ts/models/session.ts';
|
||||
|
||||
describe('Session Model', () => {
|
||||
@@ -70,9 +70,21 @@ describe('Session Model', () => {
|
||||
|
||||
describe('getUserSessions', () => {
|
||||
it('should return all valid sessions for user', async () => {
|
||||
await Session.createSession({ userId: testUserId, userAgent: 'Agent 1', ipAddress: '1.1.1.1' });
|
||||
await Session.createSession({ userId: testUserId, userAgent: 'Agent 2', ipAddress: '2.2.2.2' });
|
||||
await Session.createSession({ userId: testUserId, userAgent: 'Agent 3', ipAddress: '3.3.3.3' });
|
||||
await Session.createSession({
|
||||
userId: testUserId,
|
||||
userAgent: 'Agent 1',
|
||||
ipAddress: '1.1.1.1',
|
||||
});
|
||||
await Session.createSession({
|
||||
userId: testUserId,
|
||||
userAgent: 'Agent 2',
|
||||
ipAddress: '2.2.2.2',
|
||||
});
|
||||
await Session.createSession({
|
||||
userId: testUserId,
|
||||
userAgent: 'Agent 3',
|
||||
ipAddress: '3.3.3.3',
|
||||
});
|
||||
|
||||
const sessions = await Session.getUserSessions(testUserId);
|
||||
assertEquals(sessions.length, 3);
|
||||
@@ -110,9 +122,21 @@ describe('Session Model', () => {
|
||||
|
||||
describe('invalidateAllUserSessions', () => {
|
||||
it('should invalidate all user sessions', async () => {
|
||||
await Session.createSession({ userId: testUserId, userAgent: 'Agent 1', ipAddress: '1.1.1.1' });
|
||||
await Session.createSession({ userId: testUserId, userAgent: 'Agent 2', ipAddress: '2.2.2.2' });
|
||||
await Session.createSession({ userId: testUserId, userAgent: 'Agent 3', ipAddress: '3.3.3.3' });
|
||||
await Session.createSession({
|
||||
userId: testUserId,
|
||||
userAgent: 'Agent 1',
|
||||
ipAddress: '1.1.1.1',
|
||||
});
|
||||
await Session.createSession({
|
||||
userId: testUserId,
|
||||
userAgent: 'Agent 2',
|
||||
ipAddress: '2.2.2.2',
|
||||
});
|
||||
await Session.createSession({
|
||||
userId: testUserId,
|
||||
userAgent: 'Agent 3',
|
||||
ipAddress: '3.3.3.3',
|
||||
});
|
||||
|
||||
const count = await Session.invalidateAllUserSessions(testUserId, 'Security logout');
|
||||
assertEquals(count, 3);
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists, assertRejects } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { setupTestDb, teardownTestDb, cleanupTestDb } from '../../helpers/index.ts';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import { cleanupTestDb, setupTestDb, teardownTestDb } from '../../helpers/index.ts';
|
||||
import { User } from '../../../ts/models/user.ts';
|
||||
|
||||
describe('User Model', () => {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { setupTestDb, teardownTestDb, cleanupTestDb, createTestUser } from '../../helpers/index.ts';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import { cleanupTestDb, createTestUser, setupTestDb, teardownTestDb } from '../../helpers/index.ts';
|
||||
import { AuthService } from '../../../ts/services/auth.service.ts';
|
||||
import { Session } from '../../../ts/models/session.ts';
|
||||
import { testConfig } from '../../test.config.ts';
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
|
||||
import { assertEquals, assertExists, assertMatch } from 'jsr:@std/assert';
|
||||
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
|
||||
import { setupTestDb, teardownTestDb, cleanupTestDb, createTestUser } from '../../helpers/index.ts';
|
||||
import { afterAll, beforeAll, beforeEach, describe, it } from 'jsr:@std/testing/bdd';
|
||||
import { cleanupTestDb, createTestUser, setupTestDb, teardownTestDb } from '../../helpers/index.ts';
|
||||
import { TokenService } from '../../../ts/services/token.service.ts';
|
||||
import { ApiToken } from '../../../ts/models/apitoken.ts';
|
||||
|
||||
@@ -39,8 +39,8 @@ describe('TokenService', () => {
|
||||
assertExists(result.rawToken);
|
||||
assertExists(result.token);
|
||||
|
||||
// Check token format: srg_{prefix}_{random}
|
||||
assertMatch(result.rawToken, /^srg_[a-z0-9]+_[a-z0-9]+$/);
|
||||
// Check token format: srg_ + 64 hex chars
|
||||
assertMatch(result.rawToken, /^srg_[a-f0-9]{64}$/);
|
||||
assertEquals(result.token.name, 'test-token');
|
||||
assertEquals(result.token.protocols.includes('npm'), true);
|
||||
assertEquals(result.token.protocols.includes('oci'), true);
|
||||
@@ -111,13 +111,19 @@ describe('TokenService', () => {
|
||||
it('should reject invalid token format', async () => {
|
||||
const validation = await tokenService.validateToken('invalid-format', '127.0.0.1');
|
||||
|
||||
assertEquals(validation, null);
|
||||
assertEquals(validation.valid, false);
|
||||
assertEquals(validation.errorCode, 'INVALID_TOKEN_FORMAT');
|
||||
});
|
||||
|
||||
it('should reject non-existent token', async () => {
|
||||
const validation = await tokenService.validateToken('srg_abc123_def456', '127.0.0.1');
|
||||
// Must match srg_ prefix + 64 hex chars = 68 total
|
||||
const validation = await tokenService.validateToken(
|
||||
'srg_0000000000000000000000000000000000000000000000000000000000000000',
|
||||
'127.0.0.1',
|
||||
);
|
||||
|
||||
assertEquals(validation, null);
|
||||
assertEquals(validation.valid, false);
|
||||
assertEquals(validation.errorCode, 'TOKEN_NOT_FOUND');
|
||||
});
|
||||
|
||||
it('should reject revoked token', async () => {
|
||||
@@ -132,7 +138,9 @@ describe('TokenService', () => {
|
||||
|
||||
const validation = await tokenService.validateToken(rawToken, '127.0.0.1');
|
||||
|
||||
assertEquals(validation, null);
|
||||
assertEquals(validation.valid, false);
|
||||
// findByHash excludes revoked tokens, so the token is not found
|
||||
assertEquals(validation.errorCode, 'TOKEN_NOT_FOUND');
|
||||
});
|
||||
|
||||
it('should reject expired token', async () => {
|
||||
@@ -150,7 +158,8 @@ describe('TokenService', () => {
|
||||
|
||||
const validation = await tokenService.validateToken(rawToken, '127.0.0.1');
|
||||
|
||||
assertEquals(validation, null);
|
||||
assertEquals(validation.valid, false);
|
||||
assertEquals(validation.errorCode, 'TOKEN_EXPIRED');
|
||||
});
|
||||
|
||||
it('should record usage on validation', async () => {
|
||||
|
||||
Reference in New Issue
Block a user