11import { HttpStatus } from '@nestjs/common'
2+ import { HttpService } from '@nestjs/axios'
23import { Test , TestingModule } from '@nestjs/testing'
34import {
45 authorizationCodeGrant ,
@@ -10,8 +11,13 @@ import {
1011 randomState
1112} from 'openid-client'
1213import { USER_ROLE } from '../../../applications/users/constants/user'
14+ import { UserModel } from '../../../applications/users/models/user.model'
1315import { AdminUsersManager } from '../../../applications/users/services/admin-users-manager.service'
1416import { UsersManager } from '../../../applications/users/services/users-manager.service'
17+ import * as avatarUtils from '../../../applications/users/utils/avatar'
18+ import * as filesUtils from '../../../applications/files/utils/files'
19+ import * as downloadFileUtils from '../../../applications/files/utils/download-file'
20+ import * as imageUtils from '../../../common/image'
1521import { OAuthCookie } from './auth-oidc.constants'
1622import { AuthProviderOIDC } from './auth-provider-oidc.service'
1723
@@ -85,6 +91,9 @@ describe(AuthProviderOIDC.name, () => {
8591 createUserOrGuest : jest . Mock
8692 updateUserOrGuest : jest . Mock
8793 }
94+ let httpService : {
95+ axiosRef : jest . Mock
96+ }
8897
8998 const makeConfig = ( supportsPKCE = true ) => ( {
9099 serverMetadata : ( ) => ( {
@@ -110,9 +119,17 @@ describe(AuthProviderOIDC.name, () => {
110119 createUserOrGuest : jest . fn ( ) ,
111120 updateUserOrGuest : jest . fn ( )
112121 }
122+ httpService = {
123+ axiosRef : jest . fn ( )
124+ }
113125
114126 const module : TestingModule = await Test . createTestingModule ( {
115- providers : [ { provide : UsersManager , useValue : usersManager } , { provide : AdminUsersManager , useValue : adminUsersManager } , AuthProviderOIDC ]
127+ providers : [
128+ { provide : HttpService , useValue : httpService } ,
129+ { provide : UsersManager , useValue : usersManager } ,
130+ { provide : AdminUsersManager , useValue : adminUsersManager } ,
131+ AuthProviderOIDC
132+ ]
116133 } ) . compile ( )
117134
118135 module . useLogger ( [ 'fatal' ] )
@@ -261,4 +278,87 @@ describe(AuthProviderOIDC.name, () => {
261278 )
262279 expect ( result . role ) . toBe ( USER_ROLE . ADMINISTRATOR )
263280 } )
281+
282+ describe ( 'updatePictureUrl' , ( ) => {
283+ const oidcUser = { login : 'alice' , tmpPath : '/tmp/sync-in/alice/tmp' } as UserModel
284+ const userInfo = ( picture = 'https://cdn.example.test/avatar.jpg' ) => ( { picture } ) as any
285+
286+ it ( 'returns when picture url is invalid' , async ( ) => {
287+ const downloadSpy = jest . spyOn ( downloadFileUtils , 'downloadFile' )
288+
289+ await ( service as any ) . updatePictureUrl ( oidcUser , userInfo ( 'not-a-url' ) )
290+
291+ expect ( downloadSpy ) . not . toHaveBeenCalled ( )
292+ } )
293+
294+ it ( 'stops when content type is not an image' , async ( ) => {
295+ const downloadSpy = jest . spyOn ( downloadFileUtils , 'downloadFile' ) . mockResolvedValueOnce ( {
296+ contentType : 'text/plain' ,
297+ contentLength : 123 ,
298+ lastModified : 'Mon, 01 Jan 2024 00:00:00 GMT'
299+ } as any )
300+ const convertSpy = jest . spyOn ( imageUtils , 'convertTempImageToPng' ) . mockResolvedValue ( undefined )
301+
302+ await ( service as any ) . updatePictureUrl ( oidcUser , userInfo ( ) )
303+
304+ expect ( downloadSpy ) . toHaveBeenCalledTimes ( 1 )
305+ expect ( convertSpy ) . not . toHaveBeenCalled ( )
306+ } )
307+
308+ it ( 'skips update when avatar metadata is unchanged' , async ( ) => {
309+ const downloadSpy = jest . spyOn ( downloadFileUtils , 'downloadFile' ) . mockResolvedValueOnce ( {
310+ contentType : 'image/png' ,
311+ contentLength : 128 ,
312+ lastModified : 'Mon, 01 Jan 2024 00:00:00 GMT'
313+ } as any )
314+ jest . spyOn ( avatarUtils , 'isAvatarMetadataUnchanged' ) . mockResolvedValue ( true )
315+ const convertSpy = jest . spyOn ( imageUtils , 'convertTempImageToPng' ) . mockResolvedValue ( undefined )
316+
317+ await ( service as any ) . updatePictureUrl ( oidcUser , userInfo ( ) )
318+
319+ expect ( downloadSpy ) . toHaveBeenCalledTimes ( 1 )
320+ expect ( convertSpy ) . not . toHaveBeenCalled ( )
321+ } )
322+
323+ it ( 'downloads and converts avatar when checks pass' , async ( ) => {
324+ const downloadSpy = jest
325+ . spyOn ( downloadFileUtils , 'downloadFile' )
326+ . mockResolvedValueOnce ( {
327+ contentType : 'image/png' ,
328+ contentLength : 128 ,
329+ lastModified : 'Mon, 01 Jan 2024 00:00:00 GMT'
330+ } as any )
331+ . mockResolvedValueOnce ( undefined as any )
332+ jest . spyOn ( avatarUtils , 'isAvatarMetadataUnchanged' ) . mockResolvedValue ( false )
333+ jest . spyOn ( filesUtils , 'fileSize' ) . mockResolvedValue ( 1024 )
334+ jest . spyOn ( UserModel , 'getHomePath' ) . mockReturnValue ( '/tmp/sync-in/users/alice' )
335+ const convertSpy = jest . spyOn ( imageUtils , 'convertTempImageToPng' ) . mockResolvedValue ( undefined )
336+ const metadataSpy = jest . spyOn ( avatarUtils , 'saveAvatarMetadata' ) . mockResolvedValue ( undefined )
337+
338+ await ( service as any ) . updatePictureUrl ( oidcUser , userInfo ( ) )
339+
340+ expect ( downloadSpy ) . toHaveBeenCalledTimes ( 2 )
341+ expect ( convertSpy ) . toHaveBeenCalledWith ( '/tmp/sync-in/alice/tmp/avatar.png' , '/tmp/sync-in/users/alice/avatar.png' )
342+ expect ( metadataSpy ) . toHaveBeenCalledWith ( 'alice' , 'https://cdn.example.test/avatar.jpg' , 128 , 'Mon, 01 Jan 2024 00:00:00 GMT' )
343+ } )
344+
345+ it ( 'stops after download when avatar size exceeds limit' , async ( ) => {
346+ const downloadSpy = jest
347+ . spyOn ( downloadFileUtils , 'downloadFile' )
348+ . mockResolvedValueOnce ( {
349+ contentType : 'image/png' ,
350+ contentLength : 128 ,
351+ lastModified : 'Mon, 01 Jan 2024 00:00:00 GMT'
352+ } as any )
353+ . mockResolvedValueOnce ( undefined as any )
354+ jest . spyOn ( avatarUtils , 'isAvatarMetadataUnchanged' ) . mockResolvedValue ( false )
355+ jest . spyOn ( filesUtils , 'fileSize' ) . mockResolvedValue ( avatarUtils . USER_AVATAR_MAX_UPLOAD_SIZE + 1 )
356+ const convertSpy = jest . spyOn ( imageUtils , 'convertTempImageToPng' ) . mockResolvedValue ( undefined )
357+
358+ await ( service as any ) . updatePictureUrl ( oidcUser , userInfo ( ) )
359+
360+ expect ( downloadSpy ) . toHaveBeenCalledTimes ( 2 )
361+ expect ( convertSpy ) . not . toHaveBeenCalled ( )
362+ } )
363+ } )
264364} )
0 commit comments