Skip to content

Commit ce5cb40

Browse files
committed
code review fixes
1 parent 965f2dd commit ce5cb40

8 files changed

Lines changed: 103 additions & 103 deletions

File tree

service/src/app-models/identity/actions/register-action.spec.ts

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
import type { IncomingMessage, ServerResponse } from 'http'
22
import { Injector } from '@furystack/inject'
3-
import { StoreManager } from '@furystack/core'
43
import { RequestError } from '@furystack/rest'
54
import { HttpUserContext } from '@furystack/rest-service'
6-
import { PasswordAuthenticator, PasswordCredential } from '@furystack/security'
5+
import { PasswordAuthenticator } from '@furystack/security'
76
import { usingAsync } from '@furystack/utils'
87
import { describe, expect, it, vi } from 'vitest'
9-
import { User } from 'common'
108
import { RegisterAction } from './register-action.js'
119

12-
// Mock getLogger
1310
vi.mock('@furystack/logging', () => ({
1411
getLogger: () => ({
1512
withScope: () => ({
@@ -20,27 +17,32 @@ vi.mock('@furystack/logging', () => ({
2017
}),
2118
}))
2219

23-
describe('RegisterAction', () => {
24-
const createTestInjector = () => {
25-
const injector = new Injector()
20+
const mockUserDataSet = {
21+
get: vi.fn(),
22+
add: vi.fn(),
23+
remove: vi.fn(),
24+
}
2625

27-
const mockUserStore = {
28-
get: vi.fn(),
29-
add: vi.fn(),
30-
remove: vi.fn(),
31-
}
26+
const mockCredentialDataSet = {
27+
add: vi.fn(),
28+
}
3229

33-
const mockCredentialStore = {
34-
add: vi.fn(),
35-
}
30+
vi.mock('@furystack/core', () => ({
31+
useSystemIdentityContext: ({ injector }: { injector: unknown }) => injector,
32+
}))
3633

37-
const mockStoreManager = {
38-
getStoreFor: vi.fn((model: { name: string }) => {
39-
if (model === User || model.name === 'User') return mockUserStore
40-
if (model === PasswordCredential || model.name === 'PasswordCredential') return mockCredentialStore
41-
throw new Error(`Unknown model: ${model.name}`)
42-
}),
43-
}
34+
vi.mock('@furystack/repository', () => ({
35+
getDataSetFor: (_injector: unknown, model: { name?: string } | ((...args: unknown[]) => unknown)) => {
36+
const name = typeof model === 'function' ? model.name : ''
37+
if (name === 'User') return mockUserDataSet
38+
if (name === 'PasswordCredential') return mockCredentialDataSet
39+
throw new Error(`Unknown model: ${name}`)
40+
},
41+
}))
42+
43+
describe('RegisterAction', () => {
44+
const createTestInjector = () => {
45+
const injector = new Injector()
4446

4547
const mockHasher = {
4648
createCredential: vi.fn().mockResolvedValue({
@@ -59,19 +61,18 @@ describe('RegisterAction', () => {
5961
cookieLogin: vi.fn().mockResolvedValue(undefined),
6062
}
6163

62-
injector.setExplicitInstance(mockStoreManager as unknown as StoreManager, StoreManager)
6364
injector.setExplicitInstance(mockAuthenticator as unknown as PasswordAuthenticator, PasswordAuthenticator)
6465
injector.setExplicitInstance(mockUserContext as unknown as HttpUserContext, HttpUserContext)
6566

66-
return { injector, mockUserStore, mockCredentialStore, mockHasher, mockUserContext }
67+
return { injector, mockHasher, mockUserContext }
6768
}
6869

6970
it('should register a new user successfully', async () => {
70-
const { injector, mockUserStore, mockCredentialStore, mockUserContext } = createTestInjector()
71+
const { injector, mockUserContext } = createTestInjector()
7172

72-
mockUserStore.get.mockResolvedValue(null) // User doesn't exist
73-
mockUserStore.add.mockResolvedValue(undefined)
74-
mockCredentialStore.add.mockResolvedValue(undefined)
73+
mockUserDataSet.get.mockResolvedValue(null)
74+
mockUserDataSet.add.mockResolvedValue(undefined)
75+
mockCredentialDataSet.add.mockResolvedValue(undefined)
7576

7677
await usingAsync(injector, async (i) => {
7778
const result = await RegisterAction({
@@ -81,24 +82,25 @@ describe('RegisterAction', () => {
8182
request: {} as IncomingMessage,
8283
})
8384

84-
expect(mockUserStore.get).toHaveBeenCalledWith('newuser')
85-
expect(mockUserStore.add).toHaveBeenCalledWith(
85+
expect(mockUserDataSet.get).toHaveBeenCalledWith(i, 'newuser')
86+
expect(mockUserDataSet.add).toHaveBeenCalledWith(
87+
i,
8688
expect.objectContaining({
8789
username: 'newuser',
8890
roles: [],
8991
}),
9092
)
91-
expect(mockCredentialStore.add).toHaveBeenCalled()
93+
expect(mockCredentialDataSet.add).toHaveBeenCalled()
9294
expect(mockUserContext.authenticateUser).toHaveBeenCalledWith('newuser', 'password123')
9395
expect(mockUserContext.cookieLogin).toHaveBeenCalled()
9496
expect(result.chunk).toEqual({ username: 'newuser', roles: [] })
9597
})
9698
})
9799

98100
it('should throw 409 when user already exists', async () => {
99-
const { injector, mockUserStore } = createTestInjector()
101+
const { injector } = createTestInjector()
100102

101-
mockUserStore.get.mockResolvedValue({ username: 'existinguser', roles: [] })
103+
mockUserDataSet.get.mockResolvedValue({ username: 'existinguser', roles: [] })
102104

103105
await usingAsync(injector, async (i) => {
104106
try {
@@ -118,9 +120,9 @@ describe('RegisterAction', () => {
118120
})
119121

120122
it('should throw 400 when credential creation fails', async () => {
121-
const { injector, mockUserStore, mockHasher } = createTestInjector()
123+
const { injector, mockHasher } = createTestInjector()
122124

123-
mockUserStore.get.mockResolvedValue(null)
125+
mockUserDataSet.get.mockResolvedValue(null)
124126
mockHasher.createCredential.mockRejectedValue(new Error('Invalid password'))
125127

126128
await usingAsync(injector, async (i) => {
@@ -141,12 +143,12 @@ describe('RegisterAction', () => {
141143
})
142144

143145
it('should cleanup user when registration fails after user creation', async () => {
144-
const { injector, mockUserStore, mockCredentialStore } = createTestInjector()
146+
const { injector } = createTestInjector()
145147

146-
mockUserStore.get.mockResolvedValue(null)
147-
mockUserStore.add.mockResolvedValue(undefined)
148-
mockCredentialStore.add.mockRejectedValue(new Error('Credential store error'))
149-
mockUserStore.remove.mockResolvedValue(undefined)
148+
mockUserDataSet.get.mockResolvedValue(null)
149+
mockUserDataSet.add.mockResolvedValue(undefined)
150+
mockCredentialDataSet.add.mockRejectedValue(new Error('Credential store error'))
151+
mockUserDataSet.remove.mockResolvedValue(undefined)
150152

151153
await usingAsync(injector, async (i) => {
152154
try {
@@ -159,19 +161,18 @@ describe('RegisterAction', () => {
159161
expect.fail('Expected RequestError to be thrown')
160162
} catch (error) {
161163
expect(error).toBeInstanceOf(RequestError)
162-
// Verify cleanup was attempted
163-
expect(mockUserStore.remove).toHaveBeenCalledWith('newuser')
164+
expect(mockUserDataSet.remove).toHaveBeenCalledWith(i, 'newuser')
164165
}
165166
})
166167
})
167168

168169
it('should not fail if cleanup fails', async () => {
169-
const { injector, mockUserStore, mockCredentialStore } = createTestInjector()
170+
const { injector } = createTestInjector()
170171

171-
mockUserStore.get.mockResolvedValue(null)
172-
mockUserStore.add.mockResolvedValue(undefined)
173-
mockCredentialStore.add.mockRejectedValue(new Error('Credential store error'))
174-
mockUserStore.remove.mockRejectedValue(new Error('Cleanup failed'))
172+
mockUserDataSet.get.mockResolvedValue(null)
173+
mockUserDataSet.add.mockResolvedValue(undefined)
174+
mockCredentialDataSet.add.mockRejectedValue(new Error('Credential store error'))
175+
mockUserDataSet.remove.mockRejectedValue(new Error('Cleanup failed'))
175176

176177
await usingAsync(injector, async (i) => {
177178
try {
@@ -185,8 +186,7 @@ describe('RegisterAction', () => {
185186
} catch (error) {
186187
expect(error).toBeInstanceOf(RequestError)
187188
expect((error as RequestError).responseCode).toBe(400)
188-
// Cleanup was attempted even though it failed
189-
expect(mockUserStore.remove).toHaveBeenCalledWith('newuser')
189+
expect(mockUserDataSet.remove).toHaveBeenCalledWith(i, 'newuser')
190190
}
191191
})
192192
})

service/src/app-models/media/actions/scan-for-movies-action.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { useSystemIdentityContext } from '@furystack/core'
12
import { getLogger } from '@furystack/logging'
23
import { getDataSetFor } from '@furystack/repository'
34
import { RequestError } from '@furystack/rest'
@@ -11,17 +12,18 @@ export const ScanForMoviesAction: RequestAction<ScanForMoviesEndpoint> = async (
1112
const { root, autoExtractSubtitles } = await getBody()
1213

1314
const logger = getLogger(injector).withScope('ScanForMoviesAction')
15+
const systemInjector = useSystemIdentityContext({ injector, username: 'scan-movies' })
1416

1517
const maintainer = injector.getInstance(MovieMaintainerService)
1618
const driveDataSet = getDataSetFor(injector, Drive, 'letter')
17-
const drive = await driveDataSet.get(injector, root.driveLetter)
19+
const drive = await driveDataSet.get(systemInjector, root.driveLetter)
1820

1921
if (!drive) {
2022
throw new RequestError(`Drive ${root.driveLetter} not found`, 400)
2123
}
2224

2325
const movieFileDataSet = getDataSetFor(injector, MovieFile, 'id')
24-
const alreadyAddedMovieFiles = await movieFileDataSet.find(injector, {})
26+
const alreadyAddedMovieFiles = await movieFileDataSet.find(systemInjector, {})
2527

2628
await logger.verbose({
2729
message: `Scanning for movie files in ${root.path} on drive ${drive.letter}`,
@@ -39,13 +41,13 @@ export const ScanForMoviesAction: RequestAction<ScanForMoviesEndpoint> = async (
3941
for (const file of toBeAdded) {
4042
try {
4143
const addedMovieFile = await linkMovie({
42-
injector,
44+
injector: systemInjector,
4345
file,
4446
})
4547

4648
if (autoExtractSubtitles) {
4749
await extractSubtitles({
48-
injector,
50+
injector: systemInjector,
4951
file,
5052
})
5153
}

service/src/app-models/media/services/stream-file-action-caches.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Cache } from '@furystack/cache'
22
import { useSystemIdentityContext } from '@furystack/core'
3-
import { Injectable, type Injector } from '@furystack/inject'
3+
import { Injected, Injectable, type Injector } from '@furystack/inject'
44
import { getDataSetFor } from '@furystack/repository'
55
import { Config, Drive, type MoviesConfig, type PiRatFile, type StreamQueryParams } from 'common'
66
import { join } from 'path'
@@ -12,14 +12,8 @@ import { FfprobeService } from '../../../ffprobe-service.js'
1212
export class StreamFileActionCaches {
1313
declare public injector: Injector
1414

15-
private get systemInjector() {
16-
if (!this._systemInjector) {
17-
this._systemInjector = useSystemIdentityContext({ injector: this.injector, username: 'stream-cache' })
18-
}
19-
return this._systemInjector
20-
}
21-
22-
private _systemInjector?: Injector
15+
@Injected((injector) => useSystemIdentityContext({ injector, username: 'stream-cache' }))
16+
declare private systemInjector: Injector
2317

2418
public driveCache = new Cache({
2519
load: async (key: string) => {

service/src/app-models/media/utils/ensure-movie-exists.spec.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,13 @@ import { describe, expect, it, vi } from 'vitest'
44
import type { OmdbMovieMetadata } from 'common'
55
import { ensureMovieExists } from './ensure-movie-exists.js'
66

7-
// Mock getStoreManager
87
const mockMovieStoreGet = vi.fn()
98
const mockMovieStoreAdd = vi.fn()
109

11-
vi.mock('@furystack/core', () => ({
12-
getStoreManager: () => ({
13-
getStoreFor: () => ({
14-
get: (...args: unknown[]) => mockMovieStoreGet(...args) as unknown,
15-
add: (...args: unknown[]) => mockMovieStoreAdd(...args) as unknown,
16-
}),
10+
vi.mock('@furystack/repository', () => ({
11+
getDataSetFor: () => ({
12+
get: (...args: unknown[]) => mockMovieStoreGet(...args) as unknown,
13+
add: (...args: unknown[]) => mockMovieStoreAdd(...args) as unknown,
1714
}),
1815
}))
1916

@@ -56,7 +53,7 @@ describe('ensureMovieExists', () => {
5653
await usingAsync(new Injector(), async (injector) => {
5754
const result = await ensureMovieExists(createOmdbMeta(), injector)
5855

59-
expect(mockMovieStoreGet).toHaveBeenCalledWith('tt1234567')
56+
expect(mockMovieStoreGet).toHaveBeenCalledWith(injector, 'tt1234567')
6057
expect(mockMovieStoreAdd).not.toHaveBeenCalled()
6158
expect(result).toBe(existingMovie)
6259
})
@@ -74,8 +71,9 @@ describe('ensureMovieExists', () => {
7471
await usingAsync(new Injector(), async (injector) => {
7572
const result = await ensureMovieExists(createOmdbMeta(), injector)
7673

77-
expect(mockMovieStoreGet).toHaveBeenCalledWith('tt1234567')
74+
expect(mockMovieStoreGet).toHaveBeenCalledWith(injector, 'tt1234567')
7875
expect(mockMovieStoreAdd).toHaveBeenCalledWith(
76+
injector,
7977
expect.objectContaining({
8078
imdbId: 'tt1234567',
8179
title: 'Test Movie',
@@ -111,6 +109,7 @@ describe('ensureMovieExists', () => {
111109
await ensureMovieExists(omdbMeta, injector)
112110

113111
expect(mockMovieStoreAdd).toHaveBeenCalledWith(
112+
injector,
114113
expect.objectContaining({
115114
imdbId: 'tt9999999',
116115
season: 1,
@@ -132,6 +131,7 @@ describe('ensureMovieExists', () => {
132131
await ensureMovieExists(omdbMeta, injector)
133132

134133
expect(mockMovieStoreAdd).toHaveBeenCalledWith(
134+
injector,
135135
expect.objectContaining({
136136
duration: undefined,
137137
}),

service/src/app-models/media/utils/link-movie.spec.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,26 @@ import { FfprobeService } from '../../../ffprobe-service.js'
77
import { OmdbClientService } from '../metadata-services/omdb-client-service.js'
88
import { linkMovie } from './link-movie.js'
99

10-
// Mock getStoreManager
1110
const mockMovieFileStoreFind = vi.fn()
1211
const mockMovieFileStoreAdd = vi.fn()
1312
const mockOmdbStoreFind = vi.fn()
1413

15-
vi.mock('@furystack/core', () => ({
16-
getStoreManager: () => ({
17-
getStoreFor: (model: { name: string }) => {
18-
if (model.name === 'MovieFile') {
19-
return {
20-
find: (...args: unknown[]) => mockMovieFileStoreFind(...args) as unknown,
21-
add: (...args: unknown[]) => mockMovieFileStoreAdd(...args) as unknown,
22-
}
14+
vi.mock('@furystack/repository', () => ({
15+
getDataSetFor: (_injector: unknown, model: { name?: string } | ((...args: unknown[]) => unknown)) => {
16+
const name = typeof model === 'function' ? model.name : ''
17+
if (name === 'MovieFile') {
18+
return {
19+
find: (...args: unknown[]) => mockMovieFileStoreFind(...args) as unknown,
20+
add: (...args: unknown[]) => mockMovieFileStoreAdd(...args) as unknown,
2321
}
24-
if (model.name === 'OmdbMovieMetadata') {
25-
return {
26-
find: (...args: unknown[]) => mockOmdbStoreFind(...args) as unknown,
27-
}
22+
}
23+
if (name === 'OmdbMovieMetadata') {
24+
return {
25+
find: (...args: unknown[]) => mockOmdbStoreFind(...args) as unknown,
2826
}
29-
return {}
30-
},
31-
}),
27+
}
28+
return {}
29+
},
3230
}))
3331

3432
// Mock getLogger

0 commit comments

Comments
 (0)