71429: Feature and Authorization tests

This commit is contained in:
Kristof De Langhe
2020-06-19 15:55:25 +02:00
parent 89afaaa4a5
commit 72381f4083
5 changed files with 250 additions and 1 deletions

View File

@@ -33,6 +33,9 @@ import { NotificationsServiceStub } from '../../../../shared/testing/notificatio
import { TranslateLoaderMock } from '../../../../shared/mocks/translate-loader.mock';
import { AuthService } from '../../../../core/auth/auth.service';
import { AuthServiceStub } from '../../../../shared/testing/auth-service.stub';
import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service';
import { GroupDataService } from '../../../../core/eperson/group-data.service';
import { createPaginatedList } from '../../../../shared/testing/utils.test';
describe('EPersonFormComponent', () => {
let component: EPersonFormComponent;
@@ -43,6 +46,8 @@ describe('EPersonFormComponent', () => {
let mockEPeople;
let ePersonDataServiceStub: any;
let authService: AuthServiceStub;
let authorizationService: AuthorizationDataService;
let groupsDataService: GroupDataService;
beforeEach(async(() => {
mockEPeople = [EPersonMock, EPersonMock2];
@@ -108,6 +113,13 @@ describe('EPersonFormComponent', () => {
builderService = getMockFormBuilderService();
translateService = getMockTranslateService();
authService = new AuthServiceStub();
authorizationService = jasmine.createSpyObj('authorizationService', {
isAuthenticated: observableOf(true)
});
groupsDataService = jasmine.createSpyObj('groupsDataService', {
findAllByHref: createSuccessfulRemoteDataObject$(createPaginatedList([])),
getGroupRegistryRouterLink: ''
});
TestBed.configureTestingModule({
imports: [CommonModule, NgbModule, FormsModule, ReactiveFormsModule, BrowserModule,
TranslateModule.forRoot({
@@ -130,6 +142,8 @@ describe('EPersonFormComponent', () => {
{ provide: RemoteDataBuildService, useValue: {} },
{ provide: HALEndpointService, useValue: {} },
{ provide: AuthService, useValue: authService },
{ provide: AuthorizationDataService, useValue: authorizationService },
{ provide: GroupDataService, useValue: groupsDataService },
EPeopleRegistryComponent
],
schemas: [NO_ERRORS_SCHEMA]

View File

@@ -245,7 +245,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
});
}));
this.canImpersonate$ = this.epersonService.getActiveEPerson().pipe(
switchMap((eperson) => this.authorizationService.isAuthenticated(FeatureType.LoginOnBehalfOf, eperson.self))
switchMap((eperson) => this.authorizationService.isAuthenticated(FeatureType.LoginOnBehalfOf, hasValue(eperson) ? eperson.self : undefined))
);
});
}

View File

@@ -15,13 +15,18 @@ import { By } from '@angular/platform-browser';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { RouterTestingModule } from '@angular/router/testing';
import { ActivatedRoute } from '@angular/router';
import { AuthorizationDataService } from '../../core/data/feature-authorization/authorization-data.service';
describe('AdminSidebarComponent', () => {
let comp: AdminSidebarComponent;
let fixture: ComponentFixture<AdminSidebarComponent>;
const menuService = new MenuServiceStub();
let authorizationService: AuthorizationDataService;
beforeEach(async(() => {
authorizationService = jasmine.createSpyObj('authorizationService', {
isAuthenticated: observableOf(true)
});
TestBed.configureTestingModule({
imports: [TranslateModule.forRoot(), NoopAnimationsModule, RouterTestingModule],
declarations: [AdminSidebarComponent],
@@ -31,6 +36,7 @@ describe('AdminSidebarComponent', () => {
{ provide: CSSVariableService, useClass: CSSVariableServiceStub },
{ provide: AuthService, useClass: AuthServiceStub },
{ provide: ActivatedRoute, useValue: {} },
{ provide: AuthorizationDataService, useValue: authorizationService },
{
provide: NgbModal, useValue: {
open: () => {/*comment*/}

View File

@@ -0,0 +1,162 @@
import { AuthorizationDataService } from './authorization-data.service';
import { SiteDataService } from '../site-data.service';
import { AuthService } from '../../auth/auth.service';
import { Site } from '../../shared/site.model';
import { EPerson } from '../../eperson/models/eperson.model';
import { of as observableOf } from 'rxjs';
import { FindListOptions } from '../request.models';
import { FeatureType } from './feature-type';
import { hasValue } from '../../../shared/empty.util';
import { RequestParam } from '../../cache/models/request-param.model';
import { Authorization } from '../../shared/authorization.model';
import { RemoteData } from '../remote-data';
import { createSuccessfulRemoteDataObject$ } from '../../../shared/remote-data.utils';
import { createPaginatedList } from '../../../shared/testing/utils.test';
describe('AuthorizationDataService', () => {
let service: AuthorizationDataService;
let siteService: SiteDataService;
let authService: AuthService;
let site: Site;
let ePerson: EPerson;
function init() {
site = Object.assign(new Site(), {
id: 'test-site',
_links: {
self: { href: 'test-site-href' }
}
});
ePerson = Object.assign(new EPerson(), {
id: 'test-eperson',
uuid: 'test-eperson'
});
siteService = jasmine.createSpyObj('siteService', {
find: observableOf(site)
});
authService = {
isAuthenticated: () => observableOf(true),
getAuthenticatedUserFromStore: () => observableOf(ePerson)
} as AuthService;
service = new AuthorizationDataService(undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, authService, siteService);
}
beforeEach(() => {
init();
spyOn(service, 'searchBy').and.returnValue(observableOf(undefined));
});
describe('searchByObject', () => {
const objectUrl = 'fake-object-url';
const ePersonUuid = 'fake-eperson-uuid';
function createExpected(objectUrl: string, ePersonUuid?: string, featureId?: FeatureType): FindListOptions {
const searchParams = [new RequestParam('uri', objectUrl)];
if (hasValue(featureId)) {
searchParams.push(new RequestParam('feature', featureId));
}
if (hasValue(ePersonUuid)) {
searchParams.push(new RequestParam('eperson', ePersonUuid));
}
return Object.assign(new FindListOptions(), { searchParams });
}
describe('when no arguments are provided and a user is authenticated', () => {
beforeEach(() => {
service.searchByObject().subscribe();
});
it('should call searchBy with the site\'s url and authenticated user\'s uuid', () => {
expect(service.searchBy).toHaveBeenCalledWith('object', createExpected(site.self, ePerson.uuid));
});
});
describe('when no arguments except for a feature are provided and a user is authenticated', () => {
beforeEach(() => {
service.searchByObject(FeatureType.LoginOnBehalfOf).subscribe();
});
it('should call searchBy with the site\'s url, authenticated user\'s uuid and the feature', () => {
expect(service.searchBy).toHaveBeenCalledWith('object', createExpected(site.self, ePerson.uuid, FeatureType.LoginOnBehalfOf));
});
});
describe('when a feature and object url are provided, but no user uuid and a user is authenticated', () => {
beforeEach(() => {
service.searchByObject(FeatureType.LoginOnBehalfOf, objectUrl).subscribe();
});
it('should call searchBy with the object\'s url, authenticated user\'s uuid and the feature', () => {
expect(service.searchBy).toHaveBeenCalledWith('object', createExpected(objectUrl, ePerson.uuid, FeatureType.LoginOnBehalfOf));
});
});
describe('when all arguments are provided', () => {
beforeEach(() => {
service.searchByObject(FeatureType.LoginOnBehalfOf, objectUrl, ePersonUuid).subscribe();
});
it('should call searchBy with the object\'s url, user\'s uuid and the feature', () => {
expect(service.searchBy).toHaveBeenCalledWith('object', createExpected(objectUrl, ePersonUuid, FeatureType.LoginOnBehalfOf));
});
});
describe('when no arguments are provided and no user is authenticated', () => {
beforeEach(() => {
spyOn(authService, 'isAuthenticated').and.returnValue(observableOf(false));
service.searchByObject().subscribe();
});
it('should call searchBy with the site\'s url', () => {
expect(service.searchBy).toHaveBeenCalledWith('object', createExpected(site.self));
});
});
});
describe('isAuthenticated', () => {
const validPayload = [
Object.assign(new Authorization())
]
const emptyPayload = [];
describe('when searchByObject returns a 401', () => {
beforeEach(() => {
spyOn(service, 'searchByObject').and.returnValue(observableOf(new RemoteData(false, false, true, undefined, undefined, 401)));
});
it('should return false', (done) => {
service.isAuthenticated().subscribe((result) => {
expect(result).toEqual(false);
done();
});
});
});
describe('when searchByObject returns an empty list', () => {
beforeEach(() => {
spyOn(service, 'searchByObject').and.returnValue(createSuccessfulRemoteDataObject$(createPaginatedList(emptyPayload)));
});
it('should return false', (done) => {
service.isAuthenticated().subscribe((result) => {
expect(result).toEqual(false);
done();
});
});
});
describe('when searchByObject returns a valid list', () => {
beforeEach(() => {
spyOn(service, 'searchByObject').and.returnValue(createSuccessfulRemoteDataObject$(createPaginatedList(validPayload)));
});
it('should return true', (done) => {
service.isAuthenticated().subscribe((result) => {
expect(result).toEqual(true);
done();
});
});
});
});
});

View File

@@ -0,0 +1,67 @@
import { FeatureAuthorizationGuard } from './feature-authorization.guard';
import { AuthorizationDataService } from '../authorization-data.service';
import { FeatureType } from '../feature-type';
import { of as observableOf } from 'rxjs';
/**
* Test implementation of abstract class FeatureAuthorizationGuard
* Provide the return values of the overwritten getters as constructor arguments
*/
class FeatureAuthorizationGuardImpl extends FeatureAuthorizationGuard {
constructor(protected authorizationService: AuthorizationDataService,
protected featureType: FeatureType,
protected objectUrl: string,
protected ePersonUuid: string) {
super(authorizationService);
}
getFeatureType(): FeatureType {
return this.featureType;
}
getObjectUrl(): string {
return this.objectUrl;
}
getEPersonUuid(): string {
return this.ePersonUuid;
}
}
describe('FeatureAuthorizationGuard', () => {
let guard: FeatureAuthorizationGuard;
let authorizationService: AuthorizationDataService;
let featureType: FeatureType;
let objectUrl: string;
let ePersonUuid: string;
function init() {
featureType = FeatureType.LoginOnBehalfOf;
objectUrl = 'fake-object-url';
ePersonUuid = 'fake-eperson-uuid';
authorizationService = jasmine.createSpyObj('authorizationService', {
isAuthenticated: observableOf(true)
});
guard = new FeatureAuthorizationGuardImpl(authorizationService, featureType, objectUrl, ePersonUuid);
}
beforeEach(() => {
init();
});
describe('canActivate', () => {
it('should call authorizationService.isAuthenticated with the appropriate arguments', () => {
guard.canActivate(undefined, undefined).subscribe();
expect(authorizationService.isAuthenticated).toHaveBeenCalledWith(featureType, objectUrl, ePersonUuid);
});
});
describe('canLoad', () => {
it('should call authorizationService.isAuthenticated with the appropriate arguments', () => {
guard.canLoad(undefined, undefined).subscribe();
expect(authorizationService.isAuthenticated).toHaveBeenCalledWith(featureType, objectUrl, ePersonUuid);
});
});
});