|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 576 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 344 KiB |
@ -0,0 +1,52 @@ |
|||||
|
using System.Threading; |
||||
|
using Microsoft.Data.Sqlite; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace Volo.Abp.EntityFrameworkCore.Sqlite; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// This class is for unit testing purposes.
|
||||
|
/// It prevents exceptions in concurrent testing because Sqlite is not thread-safe.
|
||||
|
/// </summary>
|
||||
|
public class AbpUnitTestSqliteConnection : SqliteConnection |
||||
|
{ |
||||
|
public AbpUnitTestSqliteConnection(string connectionString) |
||||
|
: base(connectionString) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override SqliteCommand CreateCommand() |
||||
|
{ |
||||
|
return new AbpSqliteCommand |
||||
|
{ |
||||
|
Connection = this, |
||||
|
CommandTimeout = DefaultTimeout, |
||||
|
Transaction = Transaction |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
internal class AbpSqliteCommand : SqliteCommand |
||||
|
{ |
||||
|
private readonly static SemaphoreSlim Semaphore = new SemaphoreSlim(1, 1); |
||||
|
|
||||
|
public override SqliteConnection? Connection |
||||
|
{ |
||||
|
get => base.Connection; |
||||
|
set |
||||
|
{ |
||||
|
using (Semaphore.Lock()) |
||||
|
{ |
||||
|
base.Connection = value; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override void Dispose(bool disposing) |
||||
|
{ |
||||
|
using (Semaphore.Lock()) |
||||
|
{ |
||||
|
base.Dispose(disposing); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,121 @@ |
|||||
|
import { createServiceFactory, SpectatorService } from '@ngneat/spectator'; |
||||
|
import { OAuthErrorFilterService } from '../services'; |
||||
|
import { AuthErrorEvent, AuthErrorFilter } from '@abp/ng.core'; |
||||
|
import { OAuthErrorEvent } from 'angular-oauth2-oidc'; |
||||
|
|
||||
|
const ids = { |
||||
|
firstFilter: 'firstFilter', |
||||
|
secondFilter: 'secondFilter', |
||||
|
}; |
||||
|
type Reason = object & { error: { grant_type: string | undefined; }; }; |
||||
|
|
||||
|
|
||||
|
describe('AuthService', () => { |
||||
|
let spectator: SpectatorService<OAuthErrorFilterService>; |
||||
|
let oAuthErrorFilterService: OAuthErrorFilterService; |
||||
|
const createService = createServiceFactory(OAuthErrorFilterService); |
||||
|
|
||||
|
let firstFilter: AuthErrorFilter = { |
||||
|
id: '', |
||||
|
executable: Boolean(), |
||||
|
execute: () => Boolean(), |
||||
|
}; |
||||
|
let secondFilter: AuthErrorFilter = { |
||||
|
id: '', |
||||
|
executable: Boolean(), |
||||
|
execute: () => Boolean(), |
||||
|
}; |
||||
|
|
||||
|
beforeEach(() => { |
||||
|
spectator = createService(); |
||||
|
oAuthErrorFilterService = spectator.inject(OAuthErrorFilterService); |
||||
|
firstFilter = { |
||||
|
id: ids.firstFilter, |
||||
|
executable: true, |
||||
|
execute: (event: AuthErrorEvent) => { |
||||
|
const { reason } = event; |
||||
|
const { |
||||
|
error: { grant_type }, |
||||
|
} = <Reason>(reason || {}); |
||||
|
|
||||
|
return !!grant_type && grant_type === ids.firstFilter; |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
secondFilter = { |
||||
|
id: ids.secondFilter, |
||||
|
executable: true, |
||||
|
execute: (event: AuthErrorEvent) => { |
||||
|
const { reason } = event; |
||||
|
const { |
||||
|
error: { grant_type }, |
||||
|
} = <Reason>(reason || {}); |
||||
|
|
||||
|
return !!grant_type && grant_type === ids.secondFilter; |
||||
|
}, |
||||
|
}; |
||||
|
}); |
||||
|
|
||||
|
it('should add filter to filter service', () => { |
||||
|
oAuthErrorFilterService.add(firstFilter); |
||||
|
|
||||
|
expect(oAuthErrorFilterService.filters()).toContain(firstFilter); |
||||
|
expect(oAuthErrorFilterService.filters()).toHaveLength(1); |
||||
|
|
||||
|
oAuthErrorFilterService.add(secondFilter); |
||||
|
expect(oAuthErrorFilterService.filters()).toHaveLength(2); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to get item by id', () => { |
||||
|
oAuthErrorFilterService.add(firstFilter); |
||||
|
|
||||
|
expect(oAuthErrorFilterService.get(ids.firstFilter)).toBe(firstFilter); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to patch item', () => { |
||||
|
oAuthErrorFilterService.add(firstFilter); |
||||
|
oAuthErrorFilterService.patch({ id: ids.firstFilter, executable: false }); |
||||
|
|
||||
|
expect(oAuthErrorFilterService.get(ids.firstFilter)?.executable).toBe(false); |
||||
|
}); |
||||
|
|
||||
|
it('should be able to remove item', () => { |
||||
|
oAuthErrorFilterService.add(firstFilter); |
||||
|
oAuthErrorFilterService.add(secondFilter); |
||||
|
|
||||
|
oAuthErrorFilterService.remove(ids.firstFilter); |
||||
|
expect(oAuthErrorFilterService.filters()).not.toContain(firstFilter); |
||||
|
expect(oAuthErrorFilterService.filters()).toContain(secondFilter); |
||||
|
expect(oAuthErrorFilterService.filters()).toHaveLength(1); |
||||
|
}); |
||||
|
|
||||
|
it('if any execute method returns true, it should return the true value.', () => { |
||||
|
oAuthErrorFilterService.add(firstFilter); |
||||
|
oAuthErrorFilterService.add(secondFilter); |
||||
|
|
||||
|
const event = { |
||||
|
reason: { |
||||
|
error: { |
||||
|
grant_type: ids.secondFilter, |
||||
|
}, |
||||
|
}, |
||||
|
} as OAuthErrorEvent; |
||||
|
|
||||
|
expect(oAuthErrorFilterService.run(event)).toBe(true); |
||||
|
}); |
||||
|
|
||||
|
it('if none of execute method returns true, it should return the false.', () => { |
||||
|
oAuthErrorFilterService.add(firstFilter); |
||||
|
oAuthErrorFilterService.add(secondFilter); |
||||
|
|
||||
|
const event = { |
||||
|
reason: { |
||||
|
error: { |
||||
|
grant_type: 'random-event', |
||||
|
}, |
||||
|
}, |
||||
|
} as OAuthErrorEvent; |
||||
|
|
||||
|
expect(oAuthErrorFilterService.run(event)).toBe(false); |
||||
|
}); |
||||
|
}); |
||||