mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
[CST-5535] test cases added.
This commit is contained in:
@@ -57,6 +57,7 @@
|
||||
"@angular/core": "~11.2.14",
|
||||
"@angular/forms": "~11.2.14",
|
||||
"@angular/localize": "11.2.14",
|
||||
"@angular/material": "9.2.0",
|
||||
"@angular/platform-browser": "~11.2.14",
|
||||
"@angular/platform-browser-dynamic": "~11.2.14",
|
||||
"@angular/platform-server": "~11.2.14",
|
||||
|
@@ -210,8 +210,8 @@ import { ServerCheckGuard } from './core/server-check/server-check.guard';
|
||||
},
|
||||
{
|
||||
path: 'health',
|
||||
loadChildren: () => import('./health-page/health.routing.module')
|
||||
.then((m) => m.HealthPageRoutingModule)
|
||||
loadChildren: () => import('./health-page/health.module')
|
||||
.then((m) => m.HealthModule)
|
||||
},
|
||||
{
|
||||
path: ACCESS_CONTROL_MODULE_PATH,
|
||||
|
32
src/app/health-page/health-data.service.ts
Normal file
32
src/app/health-page/health-data.service.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { DspaceRestService } from '../core/dspace-rest/dspace-rest.service';
|
||||
import { RawRestResponse } from '../core/dspace-rest/raw-rest-response.model';
|
||||
import { HALEndpointService } from '../core/shared/hal-endpoint.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class HealthDataService {
|
||||
constructor(protected halService: HALEndpointService,
|
||||
protected restService: DspaceRestService) {
|
||||
}
|
||||
/**
|
||||
* @returns health data
|
||||
*/
|
||||
getHealth(): Observable<RawRestResponse> {
|
||||
return this.halService.getEndpoint('/actuator').pipe(
|
||||
map((restURL: string) => restURL + '/health'),
|
||||
switchMap((endpoint: string) => this.restService.get(endpoint)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns information of server
|
||||
*/
|
||||
getInfo(): Observable<RawRestResponse> {
|
||||
return this.halService.getEndpoint('/actuator').pipe(
|
||||
map((restURL: string) => restURL + '/info'),
|
||||
switchMap((endpoint: string) => this.restService.get(endpoint)));
|
||||
}
|
||||
}
|
@@ -1,12 +1,23 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { HealthPageRoutingModule } from './health.routing.module';
|
||||
import { HealthComponent } from './health/health.component';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
HealthPageRoutingModule,
|
||||
MatExpansionModule,
|
||||
NgbModule,
|
||||
TranslateModule
|
||||
],
|
||||
declarations: [
|
||||
HealthComponent
|
||||
]
|
||||
})
|
||||
export class HealthModule {
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -2,12 +2,15 @@ import { RouterModule } from '@angular/router';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
||||
import { HealthComponent } from './health/health.component';
|
||||
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
resolve: { breadcrumb: I18nBreadcrumbResolver },
|
||||
data: { breadcrumbKey: 'health' },
|
||||
canActivate: [AuthenticatedGuard],
|
||||
children: [
|
||||
{
|
||||
|
@@ -1 +1,39 @@
|
||||
<p>health works!</p>
|
||||
<div class="container">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="activeId" class="nav-tabs">
|
||||
<li [ngbNavItem]="'Health'">
|
||||
<a ngbNavLink>{{'health-page.health' | translate}}</a>
|
||||
<ng-template ngbNavContent>
|
||||
<div id="health">
|
||||
{{'health-page.status' | translate}} : <i [ngClass]="getHealthIconClass(healthGlobalStatus)"> </i>
|
||||
<mat-accordion multi="true">
|
||||
<mat-expansion-panel *ngFor="let health of healthArr">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title> {{ health.components }} <i [ngClass]="getHealthIconClass(health.status)"></i></mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
<ng-template matExpansionPanelContent>
|
||||
<div *ngFor="let item of health.details | keyvalue">
|
||||
{{ item.key }} : {{item.value}}
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
<li [ngbNavItem]="'Info'">
|
||||
<a ngbNavLink>{{'health-page.info' | translate}}</a>
|
||||
<ng-template ngbNavContent>
|
||||
<div id="info">
|
||||
<small [ngStyle]="serverInfo.style" *ngFor="let serverInfo of serverInfoArr; let index = index">
|
||||
{{ serverInfo.value }} <br>
|
||||
</small>
|
||||
</div>
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
<div [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -0,0 +1,8 @@
|
||||
.mat-expansion-panel-header {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.circle-red {
|
||||
color:red;
|
||||
align-items: center;
|
||||
}
|
@@ -1,14 +1,138 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { of } from 'rxjs';
|
||||
import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock';
|
||||
import { HealthDataService } from '../health-data.service';
|
||||
import { HealthPageRoutingModule } from '../health.routing.module';
|
||||
import { HealthComponent } from './health.component';
|
||||
|
||||
describe('HealthComponent', () => {
|
||||
function getHealth() {
|
||||
return of({
|
||||
'payload':{
|
||||
'status':'UP_WITH_ISSUES',
|
||||
'components':{
|
||||
'db':{
|
||||
'status':'UP',
|
||||
'components':{
|
||||
'dataSource':{
|
||||
'status':'UP',
|
||||
'details':{
|
||||
'database':'PostgreSQL',
|
||||
'result':1,
|
||||
'validationQuery':'SELECT 1'
|
||||
}
|
||||
},
|
||||
'dspaceDataSource':{
|
||||
'status':'UP',
|
||||
'details':{
|
||||
'database':'PostgreSQL',
|
||||
'result':1,
|
||||
'validationQuery':'SELECT 1'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'geoIp':{
|
||||
'status':'UP_WITH_ISSUES',
|
||||
'details':{
|
||||
'reason':'The GeoLite Database file is missing (/var/lib/GeoIP/GeoLite2-City.mmdb)! Solr Statistics cannot generate location based reports! Please see the DSpace installation instructions for instructions to install this file.'
|
||||
}
|
||||
},
|
||||
'solrOaiCore':{
|
||||
'status':'UP',
|
||||
'details':{
|
||||
'status':0,
|
||||
'detectedPathType':'particular core'
|
||||
}
|
||||
},
|
||||
'solrSearchCore':{
|
||||
'status':'UP',
|
||||
'details':{
|
||||
'status':0,
|
||||
'detectedPathType':'particular core'
|
||||
}
|
||||
},
|
||||
'solrStatisticsCore':{
|
||||
'status':'UP',
|
||||
'details':{
|
||||
'status':0,
|
||||
'detectedPathType':'particular core'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'statusCode':200,
|
||||
'statusText':'OK'
|
||||
});
|
||||
}
|
||||
|
||||
function getInfo() {
|
||||
return of({
|
||||
'payload':{
|
||||
'app':{
|
||||
'name':'DSpace at My University',
|
||||
'version':'7.3',
|
||||
'dir':'/Users/pratikrajkotiya/Documents/Project/FrontEnd/dspace-cris-install',
|
||||
'url':'http://localhost:8080/server',
|
||||
'db':'jdbc:postgresql://localhost:5432/4science',
|
||||
'solr':{
|
||||
'server':'http://localhost:8983/solr',
|
||||
'prefix':''
|
||||
},
|
||||
'mail':{
|
||||
'server':'smtp.example.com',
|
||||
'from-address':'dspace-noreply@myu.edu',
|
||||
'feedback-recipient':'dspace-help@myu.edu',
|
||||
'mail-admin':'dspace-help@myu.edu',
|
||||
'mail-helpdesk':'dspace-help@myu.edu',
|
||||
'alert-recipient':'dspace-help@myu.edu'
|
||||
},
|
||||
'cors':{
|
||||
'allowed-origins':'http://localhost:4000'
|
||||
},
|
||||
'ui':{
|
||||
'url':'http://localhost:4000'
|
||||
}
|
||||
}
|
||||
},
|
||||
'statusCode':200,
|
||||
'statusText':'OK'
|
||||
});
|
||||
}
|
||||
|
||||
function getMockHealthDataService() {
|
||||
return jasmine.createSpyObj('healthDataService', {
|
||||
getHealth: getHealth(),
|
||||
getInfo: getInfo()
|
||||
});
|
||||
}
|
||||
|
||||
fdescribe('HealthComponent', () => {
|
||||
let component: HealthComponent;
|
||||
let fixture: ComponentFixture<HealthComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ HealthComponent ]
|
||||
imports: [
|
||||
NgbNavModule,
|
||||
CommonModule,
|
||||
HealthPageRoutingModule,
|
||||
MatExpansionModule,
|
||||
BrowserAnimationsModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
useClass: TranslateLoaderMock
|
||||
}
|
||||
}),
|
||||
],
|
||||
declarations: [ HealthComponent ],
|
||||
providers:[{ provide: HealthDataService, useValue: getMockHealthDataService() }]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
@@ -22,4 +146,15 @@ describe('HealthComponent', () => {
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render health tab.', () => {
|
||||
const healthTab = fixture.debugElement.query(By.css('#health'));
|
||||
expect(healthTab).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render info tab.', () => {
|
||||
const infoTab = fixture.debugElement.query(By.css('#info'));
|
||||
expect(infoTab).toBeFalsy();
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -1,26 +1,100 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { DspaceRestService } from '../../core/dspace-rest/dspace-rest.service';
|
||||
import { HALEndpointService } from '../../core/shared/hal-endpoint.service';
|
||||
import { HealthDataService } from '../health-data.service';
|
||||
|
||||
|
||||
enum HealthStatus {
|
||||
UP = 'UP',
|
||||
UP_WITH_ISSUES = 'UP_WITH_ISSUES',
|
||||
DOWN = 'DOWN'
|
||||
}
|
||||
@Component({
|
||||
selector: 'ds-health',
|
||||
templateUrl: './health.component.html',
|
||||
styleUrls: ['./health.component.scss']
|
||||
})
|
||||
export class HealthComponent implements OnInit {
|
||||
|
||||
constructor(protected halService: HALEndpointService,
|
||||
protected restService: DspaceRestService) {
|
||||
}
|
||||
healthArr: string[];
|
||||
serverInfoArr: string[];
|
||||
healthGlobalStatus: string;
|
||||
activeId ='Health';
|
||||
constructor(private healthDataService: HealthDataService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.halService.getRootHref();
|
||||
console.log('this.halService.getRootHref()',);
|
||||
this.restService.get(this.halService.getRootHref() + '/actuator' + '/health').subscribe((data)=>{
|
||||
console.log(data);
|
||||
|
||||
})
|
||||
|
||||
this.healthDataService.getHealth().subscribe((data) => {
|
||||
this.healthArr = this.getHealth(data.payload.components);
|
||||
this.healthGlobalStatus = data.payload.status;
|
||||
});
|
||||
|
||||
this.healthDataService.getInfo().subscribe((data) => {
|
||||
this.serverInfoArr = this.getInfo(data.payload, null, []);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj represents a info
|
||||
* @param key represents a nested key of info
|
||||
* @param arr represents a key value pair or only key
|
||||
* @returns {{arr}} of key value pair or only key
|
||||
*/
|
||||
getInfo(obj, key, arr) {
|
||||
if (typeof obj === 'object' && key !== null) {
|
||||
arr.push({style: {'font-weight': 'bold' ,'font-size.px': key === 'app' ? '30' : '20' }, value: key});
|
||||
}
|
||||
if (typeof obj !== 'object') {
|
||||
arr.push({style: {'font-size.px': '15'}, value: `${key} = ${obj}`});
|
||||
return obj;
|
||||
}
|
||||
// tslint:disable-next-line: forin
|
||||
for (const objKey in obj) {
|
||||
this.getInfo(obj[objKey], objKey, arr);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param subCompObj represent nested sub component
|
||||
* @param superCompkey represents a key of super component
|
||||
* @returns linear components array
|
||||
*/
|
||||
getHealthSubComponents(subCompObj, superCompkey) {
|
||||
const subCompArr = [];
|
||||
// tslint:disable-next-line: forin
|
||||
for (const key in subCompObj) {
|
||||
subCompArr.push({ ...subCompObj[key], components: superCompkey + '.' + key });
|
||||
}
|
||||
return subCompArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param componentsObj represent health data
|
||||
* @returns linear components array
|
||||
*/
|
||||
getHealth(componentsObj) {
|
||||
let componentsArr = [];
|
||||
for (const key in componentsObj) {
|
||||
if (componentsObj[key].hasOwnProperty('components')) {
|
||||
componentsArr.push({ ...componentsObj[key], components: key });
|
||||
// tslint:disable-next-line: no-string-literal
|
||||
componentsArr = [...componentsArr, ...this.getHealthSubComponents(componentsObj[key]['components'], key)];
|
||||
} else {
|
||||
componentsArr.push({ ...componentsObj[key], components: key });
|
||||
}
|
||||
}
|
||||
return componentsArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param status of perticular block
|
||||
* @returns {{ string }} class respective status
|
||||
*/
|
||||
getHealthIconClass(status: string): string {
|
||||
if (status === HealthStatus.UP) {
|
||||
return 'fa fa-check-circle text-success ml-2 mt-1';
|
||||
} else if (status === HealthStatus.UP_WITH_ISSUES) {
|
||||
return 'fa fa-exclamation-triangle text-warning ml-2 mt-1';
|
||||
} else {
|
||||
return 'fa fa-times-circle circle-red ml-2 mt-1';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2909,7 +2909,13 @@
|
||||
|
||||
"profile.title": "Update Profile",
|
||||
|
||||
"health.breadcrumbs": "Health",
|
||||
|
||||
"health-page.health" : "Health",
|
||||
|
||||
"health-page.info" : "Info",
|
||||
|
||||
"health-page.status" : "Status",
|
||||
|
||||
"project.listelement.badge": "Research Project",
|
||||
|
||||
|
@@ -397,6 +397,11 @@
|
||||
glob "7.1.2"
|
||||
yargs "^16.2.0"
|
||||
|
||||
"@angular/material@9.2.0":
|
||||
version "9.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@angular/material/-/material-9.2.0.tgz#1b6f0a2e115f93885d7fc2dc4b258d8c9cf6821f"
|
||||
integrity sha512-KKzEIVh6/m56m+Ao8p4PK0SyEr0574l3VP2swj1qPag3u+FYgemmXCGTaChrKdDsez+zeTCPXImBGXzE6NQ80Q==
|
||||
|
||||
"@angular/platform-browser-dynamic@~11.2.14":
|
||||
version "11.2.14"
|
||||
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.2.14.tgz#3c7fff1a1daacba5390acf033d28c377ec281166"
|
||||
|
Reference in New Issue
Block a user