Added Header, Project Model, Service, Controller and Testdata
This commit is contained in:
parent
6c71282798
commit
ffe6553990
|
@ -25,6 +25,7 @@
|
|||
"aot": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/favicon-c4po.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
|
@ -96,6 +97,7 @@
|
|||
"tsConfig": "tsconfig.spec.json",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/favicon-c4po.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
|
|
|
@ -5,10 +5,17 @@ import {AuthGuardService} from '../shared/guards/auth-guard.service';
|
|||
import {LoginGuardService} from '../shared/guards/login-guard.service';
|
||||
|
||||
export const START_PAGE = 'home';
|
||||
export const FALLBACK_PAGE = 'home';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'home', component: HomeComponent,
|
||||
path: 'home',
|
||||
component: HomeComponent,
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
path: 'dashboard',
|
||||
loadChildren: () => import('./dashboard').then(mod => mod.DashboardModule),
|
||||
canActivate: [AuthGuardService]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
<div class="content-container">
|
||||
<div class="scrollable-content">
|
||||
<nb-layout>
|
||||
<nb-layout-column>
|
||||
<nb-layout>
|
||||
<nb-layout-header *ngIf="$authState.getValue()">
|
||||
<app-header></app-header>
|
||||
</nb-layout-header>
|
||||
|
||||
<nb-layout-column>
|
||||
<div class="content-container">
|
||||
<div class="scrollable-content">
|
||||
<router-outlet></router-outlet>
|
||||
</nb-layout-column>
|
||||
</nb-layout>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nb-layout-column>
|
||||
|
||||
</nb-layout>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
@import "../assets/@theme/styles/_variables.scss";
|
||||
|
||||
.content-container {
|
||||
width: 90vw;
|
||||
height: calc(90vh - #{$header-height});
|
||||
|
||||
.scrollable-content {
|
||||
width: 100%;
|
||||
max-width: 100vw;
|
||||
height: 100%;
|
||||
max-height: calc(100vh - #{$header-height});
|
||||
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import {ThemeModule} from '../assets/@theme/theme.module';
|
|||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {SessionState} from '../shared/stores/session-state/session-state';
|
||||
import {NgxsModule} from '@ngxs/store';
|
||||
import {HeaderModule} from './header/header.module';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
|
@ -27,6 +28,7 @@ describe('AppComponent', () => {
|
|||
}),
|
||||
NbEvaIconsModule,
|
||||
ThemeModule,
|
||||
HeaderModule,
|
||||
NgxsModule.forRoot([SessionState]),
|
||||
HttpClientTestingModule
|
||||
],
|
||||
|
|
|
@ -4,16 +4,18 @@ import localeDe from '@angular/common/locales/de';
|
|||
import {registerLocale} from 'i18n-iso-countries';
|
||||
import {registerLocaleData} from '@angular/common';
|
||||
import {Store} from '@ngxs/store';
|
||||
import {BehaviorSubject, of, Subscription} from 'rxjs';
|
||||
import {SessionState} from '../shared/stores/session-state/session-state';
|
||||
import { untilDestroyed } from 'ngx-take-until-destroy';
|
||||
import {BehaviorSubject, Subscription} from 'rxjs';
|
||||
import {SessionState, SessionStateModel} from '../shared/stores/session-state/session-state';
|
||||
import {untilDestroyed} from 'ngx-take-until-destroy';
|
||||
import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
|
||||
import {filter} from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent implements OnInit, OnDestroy{
|
||||
export class AppComponent implements OnInit, OnDestroy {
|
||||
title = 'security-c4po-angular';
|
||||
|
||||
$authState: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
|
@ -27,11 +29,12 @@ export class AppComponent implements OnInit, OnDestroy{
|
|||
|
||||
ngOnInit(): void {
|
||||
// authState change handling
|
||||
of(this.store.selectSnapshot(SessionState.isAuthenticated)).pipe(
|
||||
this.authStateSubscription = this.store.select(SessionState).pipe(
|
||||
filter(isNotNullOrUndefined),
|
||||
untilDestroyed(this)
|
||||
).subscribe({
|
||||
next: (authState: boolean) => {
|
||||
this.$authState.next(authState);
|
||||
next: (state: SessionStateModel) => {
|
||||
this.$authState.next(state.isAuthenticated);
|
||||
},
|
||||
error: (err) => console.error('auth error:', err)
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
|||
import {
|
||||
NbLayoutModule,
|
||||
NbToastrModule,
|
||||
NbIconModule,
|
||||
NbIconModule, NbCardModule, NbButtonModule,
|
||||
} from '@nebular/theme';
|
||||
import {NbEvaIconsModule} from '@nebular/eva-icons';
|
||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||
|
@ -21,6 +21,8 @@ import {SessionState} from '../shared/stores/session-state/session-state';
|
|||
import {environment} from '../environments/environment';
|
||||
import {NotificationService} from '../shared/services/notification.service';
|
||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||
import {HeaderModule} from './header/header.module';
|
||||
import {HomeModule} from './home/home.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -35,7 +37,9 @@ import {ThemeModule} from '@assets/@theme/theme.module';
|
|||
BrowserAnimationsModule,
|
||||
ThemeModule.forRoot(),
|
||||
NbLayoutModule,
|
||||
NbCardModule,
|
||||
NbIconModule,
|
||||
NbButtonModule,
|
||||
NbEvaIconsModule,
|
||||
NgxsModule.forRoot([SessionState], {developmentMode: !environment.production}),
|
||||
HttpClientModule,
|
||||
|
@ -46,6 +50,8 @@ import {ThemeModule} from '@assets/@theme/theme.module';
|
|||
deps: [HttpClient]
|
||||
}
|
||||
}),
|
||||
HeaderModule,
|
||||
HomeModule
|
||||
],
|
||||
providers: [
|
||||
HttpClient,
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {DashboardComponent} from './dashboard.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DashboardComponent
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DashboardRoutingModule { }
|
|
@ -0,0 +1 @@
|
|||
<p>dashboard works!</p>
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DashboardComponent } from './dashboard.component';
|
||||
|
||||
describe('DashboardComponent', () => {
|
||||
let component: DashboardComponent;
|
||||
let fixture: ComponentFixture<DashboardComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DashboardComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DashboardComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,17 @@
|
|||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: './dashboard.component.html',
|
||||
styleUrls: ['./dashboard.component.scss']
|
||||
})
|
||||
export class DashboardComponent implements OnInit, OnDestroy {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {DashboardComponent} from './dashboard.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
DashboardComponent,
|
||||
],
|
||||
exports: [
|
||||
DashboardComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule
|
||||
]
|
||||
})
|
||||
export class DashboardModule {
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export {DashboardModule} from './dashboard.module';
|
||||
export {DashboardRoutingModule} from './dashboard-routing.module';
|
|
@ -0,0 +1,4 @@
|
|||
<div class="c4po-header">
|
||||
<p>header works!</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
@import "../../assets/@theme/styles/_variables.scss";
|
||||
|
||||
.c4po-header {
|
||||
height: $header-height;
|
||||
|
||||
.toggle-dark-mode {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HeaderComponent } from './header.component';
|
||||
|
||||
describe('HeaderComponent', () => {
|
||||
let component: HeaderComponent;
|
||||
let fixture: ComponentFixture<HeaderComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ HeaderComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HeaderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.scss']
|
||||
})
|
||||
export class HeaderComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import {HeaderComponent} from './header.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
HeaderComponent
|
||||
],
|
||||
exports: [
|
||||
HeaderComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule
|
||||
]
|
||||
})
|
||||
export class HeaderModule { }
|
|
@ -1 +1,16 @@
|
|||
<p>home works!</p>
|
||||
<nb-card>
|
||||
|
||||
<nb-card-header>
|
||||
<button (click)="onClickGetProjects()" nbButton>get Projects</button>
|
||||
</nb-card-header>
|
||||
|
||||
<nb-card-body>
|
||||
<div *ngIf="projects.getValue().length > 0, else noProjects">
|
||||
{{projects.getValue() | json}}
|
||||
</div>
|
||||
<ng-template #noProjects>
|
||||
{{'No Projects available!'}}
|
||||
</ng-template>
|
||||
</nb-card-body>
|
||||
|
||||
</nb-card>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HomeComponent } from './home.component';
|
||||
import {NbButtonModule, NbCardModule} from '@nebular/theme';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
|
||||
describe('HomeComponent', () => {
|
||||
let component: HomeComponent;
|
||||
|
@ -8,7 +10,14 @@ describe('HomeComponent', () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ HomeComponent ]
|
||||
declarations: [
|
||||
HomeComponent
|
||||
],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
NbCardModule,
|
||||
NbButtonModule
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
|
|
@ -1,15 +1,36 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
import {Project} from '../../shared/models/project.model';
|
||||
import {ProjectService} from '../../shared/services/project.service';
|
||||
import {untilDestroyed} from 'ngx-take-until-destroy';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss']
|
||||
})
|
||||
export class HomeComponent implements OnInit {
|
||||
export class HomeComponent implements OnInit, OnDestroy {
|
||||
|
||||
constructor() { }
|
||||
projects: BehaviorSubject<Project[]> = new BehaviorSubject<Project[]>([]);
|
||||
|
||||
constructor(private projectService: ProjectService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
onClickGetProjects(): void {
|
||||
this.getProjects();
|
||||
}
|
||||
|
||||
getProjects(): void {
|
||||
this.projectService.getProjects()
|
||||
.pipe(untilDestroyed(this))
|
||||
.subscribe((projects) => {
|
||||
this.projects.next(projects);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {HomeComponent} from './home.component';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {NbButtonModule, NbCardModule} from '@nebular/theme';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
HomeComponent
|
||||
],
|
||||
exports: [
|
||||
HomeComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
NbCardModule,
|
||||
NbButtonModule
|
||||
]
|
||||
})
|
||||
export class HomeModule { }
|
||||
export class HomeModule {
|
||||
}
|
||||
|
|
|
@ -51,9 +51,3 @@
|
|||
</nb-card-body>
|
||||
</nb-card>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
$header-height: 4rem;
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
@import './layout';
|
||||
@import './overrides';
|
||||
@import './variables';
|
||||
|
||||
* {
|
||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
stage: 'n/a',
|
||||
production: false,
|
||||
apiEndpoint: 'http://localhost:8443',
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 948 B After Width: | Height: | Size: 547 KiB |
|
@ -5,7 +5,7 @@
|
|||
<title>SecurityC4POAngular</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<!--<link rel="icon" type="image/x-icon" href="src/favicon.ico">-->
|
||||
</head>
|
||||
<body id="loader-wrapper">
|
||||
<app-root id="loader"></app-root>
|
||||
|
|
|
@ -24,6 +24,7 @@ export class AuthGuardService implements CanActivate {
|
|||
return canAccess;
|
||||
} else {
|
||||
this.router.navigate(['/login']);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import { v4 as UUID } from 'uuid';
|
||||
|
||||
export class Project {
|
||||
id: string;
|
||||
client: string;
|
||||
title: string;
|
||||
/* Change to Date after database integration */
|
||||
createdAt: string;
|
||||
tester: string;
|
||||
logo: string;
|
||||
|
||||
constructor(id: string,
|
||||
client: string,
|
||||
title: string,
|
||||
createdAt: string,
|
||||
tester?: string,
|
||||
logo?: string) {
|
||||
this.id = id;
|
||||
this.client = client;
|
||||
this.title = title;
|
||||
this.createdAt = createdAt;
|
||||
this.tester = tester;
|
||||
this.logo = logo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ProjectService } from './project.service';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
|
||||
describe('ProjectService', () => {
|
||||
let service: ProjectService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
BrowserAnimationsModule,
|
||||
],
|
||||
providers: []
|
||||
});
|
||||
service = TestBed.inject(ProjectService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import {environment} from '../../environments/environment';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {Project} from '../models/project.model';
|
||||
import {Observable} from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ProjectService {
|
||||
|
||||
private apiBaseURL = `${environment.apiEndpoint}/v1/projects`;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
}
|
||||
|
||||
public getProjects(): Observable<Project[]> {
|
||||
return this.http.get<Project[]>(`${this.apiBaseURL}`);
|
||||
}
|
||||
}
|
|
@ -16,8 +16,10 @@ plugins {
|
|||
id("io.spring.dependency-management") version "1.0.10.RELEASE"
|
||||
id("com.github.spotbugs") version "4.5.0"
|
||||
id("org.owasp.dependencycheck") version "6.0.0"
|
||||
id("org.asciidoctor.jvm.convert") version "2.4.0"
|
||||
kotlin("jvm") version "1.3.72"
|
||||
kotlin("plugin.spring") version "1.3.72"
|
||||
jacoco
|
||||
}
|
||||
|
||||
group = "com.security-c4po.api"
|
||||
|
@ -56,17 +58,33 @@ spotbugs {
|
|||
val snippetsDir = file("build/generated-snippets")
|
||||
|
||||
dependencies {
|
||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-joda:2.11.3")
|
||||
implementation("io.projectreactor.kotlin:reactor-kotlin-extensions:1.1.1")
|
||||
implementation("javax.websocket:javax.websocket-api:1.1")
|
||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
/*implementation("org.springframework.boot:spring-boot-starter-data-mongodb-reactive")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")*/
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||
implementation("com.github.spotbugs:spotbugs-annotations:4.1.2")
|
||||
compileOnly("org.projectlombok:lombok")
|
||||
annotationProcessor("org.projectlombok:lombok")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test") {
|
||||
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
|
||||
}
|
||||
testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
|
||||
implementation("org.modelmapper:modelmapper:2.3.2")
|
||||
|
||||
api("org.springframework.boot:spring-boot-starter-test")
|
||||
/*api("org.springframework.security:spring-security-jwt:1.0.10.RELEASE")*/
|
||||
|
||||
testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0")
|
||||
testImplementation("io.projectreactor:reactor-test")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.1")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.3.1")
|
||||
testImplementation("org.springframework.cloud:spring-cloud-contract-wiremock:2.1.0.RELEASE")
|
||||
testImplementation("org.springframework.restdocs:spring-restdocs-webtestclient")
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.8.3"
|
||||
reportsDir = file("$buildDir/reports/coverage")
|
||||
}
|
||||
|
||||
tasks.withType<Test> {
|
||||
|
@ -81,7 +99,7 @@ tasks.withType<KotlinCompile> {
|
|||
}
|
||||
|
||||
tasks.bootJar {
|
||||
dependsOn(tasks.test, tasks.dependencyCheckAnalyze)
|
||||
dependsOn(tasks.test, tasks.asciidoctor, tasks.jacocoTestReport, tasks.dependencyCheckAnalyze)
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
|
@ -89,5 +107,35 @@ tasks.test {
|
|||
}
|
||||
|
||||
tasks.dependencyCheckAnalyze {
|
||||
dependsOn(tasks.test, tasks.asciidoctor, tasks.jacocoTestReport)
|
||||
}
|
||||
|
||||
//Issue with Kotlin assignment of sourceDir and outputDir: https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues/458
|
||||
tasks.asciidoctor {
|
||||
inputs.dir(snippetsDir)
|
||||
setSourceDir(file("src/main/asciidoc"))
|
||||
setOutputDir(file("$buildDir/asciidoc"))
|
||||
sources(delegateClosureOf<PatternSet> {
|
||||
include("SecurityC4PO.adoc")
|
||||
})
|
||||
|
||||
attributes(
|
||||
mapOf(
|
||||
"snippets" to snippetsDir,
|
||||
"source-highlighter" to "coderay",
|
||||
"toc" to "left",
|
||||
"toclevels" to 3,
|
||||
"sectlinks" to true
|
||||
)
|
||||
)
|
||||
dependsOn(tasks.test)
|
||||
}
|
||||
|
||||
tasks.jacocoTestReport {
|
||||
reports {
|
||||
xml.isEnabled = true
|
||||
csv.isEnabled = false
|
||||
html.isEnabled = true
|
||||
html.destination = file("$buildDir/reports/coverage")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"info": {
|
||||
"_postman_id": "58021f5f-0ae9-4f64-990b-f09dcc2d3bc2",
|
||||
"name": "security-c4po-api",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "project",
|
||||
"item": [
|
||||
{
|
||||
"name": "getProjects",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://localhost:8443/v1/projects",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8443",
|
||||
"path": [
|
||||
"v1",
|
||||
"projects"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getHealth",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://localhost:8443/actuator/health",
|
||||
"protocol": "http",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"port": "8443",
|
||||
"path": [
|
||||
"actuator",
|
||||
"health"
|
||||
]
|
||||
}
|
||||
},
|
||||
"response": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
= SecurityC4PO REST API Documentation
|
||||
Novatec Consulting GmbH;
|
||||
:doctype: book
|
||||
:source-highlighter: highlightjs
|
||||
:icons: font
|
||||
:toc: left
|
||||
:toclevels: 4
|
||||
:sectlinks:
|
||||
:data-uri:
|
||||
|
||||
This documentation describes the REST API for the "SecurityC4PO".
|
||||
|
||||
The service tries to adhere as closely as possible to standard HTTP and REST conventions in its use of HTTP verbs and status codes.
|
||||
|
||||
== Error handling
|
||||
|
||||
You can generally expect 4xx for client errors and 5xx for server errors.
|
||||
|
||||
== Request Headers
|
||||
|
||||
The request and response snippets shown in this documentation are generated from real interactions.
|
||||
When creating requests you must not follow the examples exactly, e.g. instead of providing the Accept Header `application/json, application/javascript, text/javascript` you can also provide only one value, typically `application/json`.
|
||||
|
||||
== Project
|
||||
|
||||
=== Get projects
|
||||
|
||||
To get projects, call the GET request /v1/projects
|
||||
|
||||
==== Request example
|
||||
|
||||
#include::{snippets}/getProjects/http-request.adoc[]
|
||||
|
||||
==== Response example
|
||||
|
||||
#include::{snippets}/getProjects/http-response.adoc[]
|
||||
|
||||
==== Response structure
|
||||
|
||||
#include::{snippets}/getProjects/response-fields.adoc[]
|
||||
|
||||
== Change History
|
||||
|
||||
|===
|
||||
|Date |Change
|
||||
|2021-02-14
|
||||
|Added GET endpoint to receive Projects
|
||||
|2021-02-12
|
||||
|Initial version
|
||||
|===
|
|
@ -0,0 +1,6 @@
|
|||
package com.securityc4po.api.v1
|
||||
|
||||
abstract class BaseEntity<T>(
|
||||
var data: T
|
||||
) {
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
package com.securityc4po.api.v1
|
||||
|
||||
typealias ResponseBody = Map<String, Any?>
|
|
@ -1,4 +1,4 @@
|
|||
package com.securityc4po.api
|
||||
package com.securityc4po.api.v1
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
|
@ -0,0 +1,19 @@
|
|||
package com.securityc4po.api.v1.configuration
|
||||
|
||||
// Constants for SpotBugs warning suppressions
|
||||
const val NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR = "NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR"
|
||||
const val RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE = "RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"
|
||||
const val BC_BAD_CAST_TO_ABSTRACT_COLLECTION = "BC_BAD_CAST_TO_ABSTRACT_COLLECTION"
|
||||
const val UC_USELESS_OBJECT = "UC_USELESS_OBJECT"
|
||||
const val NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"
|
||||
const val SE_BAD_FIELD = "SE_BAD_FIELD"
|
||||
const val EI_EXPOSE_REP = "EI_EXPOSE_REP"
|
||||
const val ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"
|
||||
const val SIC_INNER_SHOULD_BE_STATIC = "SIC_INNER_SHOULD_BE_STATIC"
|
||||
const val URF_UNREAD_FIELD = "URF_UNREAD_FIELD"
|
||||
|
||||
// Messages for SpotBugs warning suppressions
|
||||
const val MESSAGE_BAD_CAST_TO_ABSTRACT_COLLECTION = "Collection is automatically casted to abstract class."
|
||||
const val MESSAGE_NOT_INITIALIZED_REDUNDANT_NULLCHECK = "Value gets automatically initialized and checked for null"
|
||||
const val MESSAGE_USELESS_OBJECT = "Objects are instantiated for code readability."
|
||||
const val MESSAGE_NULL_ON_SOME_PATH = "Null is a valid value in this case."
|
|
@ -0,0 +1,5 @@
|
|||
package com.securityc4po.api.v1.extensions
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
inline fun <reified T> getLoggerFor() = LoggerFactory.getLogger(T::class.java)!!
|
|
@ -0,0 +1,47 @@
|
|||
package com.securityc4po.api.v1.project
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat
|
||||
import com.securityc4po.api.v1.ResponseBody
|
||||
import java.time.Instant
|
||||
import java.util.UUID
|
||||
|
||||
data class Project(
|
||||
/*
|
||||
* @Indexed(background = true, unique = true)
|
||||
* Can be used after adding deps for mongodb
|
||||
*/
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
|
||||
val client: String,
|
||||
|
||||
val title: String,
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
/* Change to Instant after database integration */
|
||||
val createdAt: String,
|
||||
|
||||
val tester: String? = null,
|
||||
|
||||
val logo: String? = null
|
||||
)
|
||||
|
||||
fun Project.toProjectResponseBody(): ResponseBody {
|
||||
return kotlin.collections.mapOf(
|
||||
"id" to id,
|
||||
"client" to client,
|
||||
"title" to title,
|
||||
"createdAt" to createdAt.toString(),
|
||||
"tester" to tester,
|
||||
"logo" to logo
|
||||
)
|
||||
}
|
||||
|
||||
data class ProjectOverview(
|
||||
val projects: List<Project>
|
||||
)
|
||||
|
||||
fun ProjectOverview.toProjectOverviewResponseBody(): ResponseBody {
|
||||
return mapOf(
|
||||
"projects" to projects
|
||||
)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.securityc4po.api.v1.project
|
||||
|
||||
import com.securityc4po.api.v1.ResponseBody
|
||||
import com.securityc4po.api.v1.configuration.BC_BAD_CAST_TO_ABSTRACT_COLLECTION
|
||||
import com.securityc4po.api.v1.extensions.getLoggerFor
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.*
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v1/projects")
|
||||
@CrossOrigin(
|
||||
origins = [],
|
||||
allowCredentials = "false",
|
||||
allowedHeaders = ["*"],
|
||||
methods = [RequestMethod.GET]
|
||||
)
|
||||
@SuppressFBWarnings(BC_BAD_CAST_TO_ABSTRACT_COLLECTION)
|
||||
class ProjectController(private val projectService: ProjectService) {
|
||||
|
||||
var logger = getLoggerFor<ProjectController>()
|
||||
|
||||
@GetMapping
|
||||
fun getProjects(): List<Project> {
|
||||
return projectService.getProjects()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.securityc4po.api.v1.project
|
||||
|
||||
import com.securityc4po.api.v1.BaseEntity
|
||||
|
||||
/*
|
||||
* @Document(collection = "project")
|
||||
* Can be used after adding deps for mongodb
|
||||
*/
|
||||
open class ProjectEntity(
|
||||
data: Project
|
||||
) : BaseEntity<Project>(data)
|
|
@ -0,0 +1,40 @@
|
|||
package com.securityc4po.api.v1.project
|
||||
|
||||
import com.securityc4po.api.v1.extensions.getLoggerFor
|
||||
import org.junit.BeforeClass
|
||||
import org.springframework.stereotype.Service
|
||||
import reactor.core.publisher.Flux
|
||||
/* Remove after database is integrated */
|
||||
import java.io.File
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
|
||||
|
||||
@Service
|
||||
class ProjectService() {
|
||||
|
||||
var logger = getLoggerFor<ProjectService>()
|
||||
|
||||
/* Remove after database is integrated */
|
||||
val mapper = jacksonObjectMapper()
|
||||
|
||||
@BeforeClass
|
||||
fun init() {
|
||||
mapper.registerKotlinModule()
|
||||
mapper.registerModule(JavaTimeModule())
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all [Project]s
|
||||
*
|
||||
* @return list of [Project]
|
||||
*/
|
||||
fun getProjects(): List<Project> {
|
||||
val jsonProjectsString: String = File("./src/main/resources/mocks/projects.json").readText(Charsets.UTF_8)
|
||||
val jsonProjectList: List<Project> = mapper.readValue<List<Project>>(jsonProjectsString)
|
||||
/* After database integration the return should be Flux of ProjectEntity */
|
||||
return jsonProjectList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.securityc4po.api.v1.user
|
||||
|
||||
data class User(
|
||||
val id: String,
|
||||
|
||||
val username: String,
|
||||
|
||||
val firstName: String? = null,
|
||||
|
||||
val lastName: String? = null,
|
||||
|
||||
val email: String? = null,
|
||||
|
||||
val interfaceLang: String? = null
|
||||
)
|
|
@ -0,0 +1,11 @@
|
|||
package com.securityc4po.api.v1.user
|
||||
|
||||
import com.securityc4po.api.v1.BaseEntity
|
||||
|
||||
/*
|
||||
* @Document(collection = "user")
|
||||
* Can be used after adding deps for mongodb
|
||||
*/
|
||||
open class UserEntity(
|
||||
data: User
|
||||
) : BaseEntity<User>(data)
|
|
@ -1,4 +1,18 @@
|
|||
## General Properties ##
|
||||
spring.main.web-application-type=reactive
|
||||
spring.main.allow-bean-definition-overriding=true
|
||||
|
||||
## Server Config ##
|
||||
server.port=8443
|
||||
server.port=8443
|
||||
|
||||
## Actuator Endpoints ##
|
||||
management.endpoints.enabled-by-default=false
|
||||
management.endpoint.health.enabled=true
|
||||
management.endpoints.web.exposure.include=info, health, metrics
|
||||
|
||||
## Database (MONGODB) Config ##
|
||||
# spring.data.mongodb.database=C4PO
|
||||
# spring.data.mongodb.host=localhost
|
||||
# spring.data.mongodb.port=27017
|
||||
# spring.main.allow-bean-definition-overriding=true
|
||||
# spring.data.mongodb.auto-index-creation=true
|
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"id": "db7f247d-da43-4cbe-9fd7-c18679a2f7e7",
|
||||
"username": "ttt",
|
||||
"firstName": "test",
|
||||
"lastName": "user",
|
||||
"email": "default.user@test.de",
|
||||
"interfaceLang": "en-US"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.securityc4po.api.v1
|
||||
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.springframework.test.context.TestPropertySource
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
abstract class BaseContainerizedTest {
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.securityc4po.api.v1
|
||||
|
||||
import com.securityc4po.api.v1.configuration.MESSAGE_NOT_INITIALIZED_REDUNDANT_NULLCHECK
|
||||
import com.securityc4po.api.v1.configuration.NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR
|
||||
import com.securityc4po.api.v1.configuration.RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.web.server.LocalServerPort
|
||||
import org.springframework.restdocs.RestDocumentationContextProvider
|
||||
import org.springframework.restdocs.RestDocumentationExtension
|
||||
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.documentationConfiguration
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import java.time.Duration
|
||||
|
||||
@SuppressFBWarnings(NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR, RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE, MESSAGE_NOT_INITIALIZED_REDUNDANT_NULLCHECK)
|
||||
@ExtendWith(value = [RestDocumentationExtension::class, SpringExtension::class])
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
abstract class BaseDocumentationIntTest : BaseContainerizedTest() {
|
||||
|
||||
@LocalServerPort
|
||||
private var port = 0
|
||||
|
||||
lateinit var webTestClient: WebTestClient
|
||||
|
||||
@BeforeEach
|
||||
fun setupDocs(restDocumentation: RestDocumentationContextProvider) {
|
||||
webTestClient = WebTestClient.bindToServer()
|
||||
.baseUrl("http://localhost:$port")
|
||||
.filter(documentationConfiguration(restDocumentation))
|
||||
.responseTimeout(Duration.ofMillis(10000))
|
||||
.build()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.securityc4po.api.v1
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.test.annotation.DirtiesContext
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension
|
||||
|
||||
@ExtendWith(SpringExtension::class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@DirtiesContext
|
||||
abstract class BaseIntTest : BaseContainerizedTest() { }
|
|
@ -1,4 +1,4 @@
|
|||
package com.securityc4po.api
|
||||
package com.securityc4po.api.v1
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
|
@ -0,0 +1,109 @@
|
|||
package com.securityc4po.api.v1.project
|
||||
|
||||
import com.github.tomakehurst.wiremock.common.Json
|
||||
import com.securityc4po.api.v1.BaseDocumentationIntTest
|
||||
import com.securityc4po.api.v1.configuration.SIC_INNER_SHOULD_BE_STATIC
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock
|
||||
import org.springframework.restdocs.operation.preprocess.Preprocessors
|
||||
import org.springframework.restdocs.payload.JsonFieldType
|
||||
import org.springframework.restdocs.payload.PayloadDocumentation
|
||||
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
|
||||
|
||||
@AutoConfigureWireMock(port = 0)
|
||||
@SuppressFBWarnings(SIC_INNER_SHOULD_BE_STATIC)
|
||||
class ProjectControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||
|
||||
/*@Autowired
|
||||
lateinit var mongoTemplate: MongoTemplate*/
|
||||
|
||||
@BeforeEach
|
||||
fun init() {
|
||||
cleanUp()
|
||||
persistBasicTestScenario()
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class GetProjects {
|
||||
@Test
|
||||
fun getProjects() {
|
||||
/* Implement after the implementation of database */
|
||||
|
||||
/*webTestClient.get().uri("/v1/projects")
|
||||
.header("")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
.expectHeader().doesNotExist("")
|
||||
.expectBody().json(Json.write(getProjectsResponse()))
|
||||
.consumeWith(WebTestClientRestDocumentation.document("{methodName}",
|
||||
Preprocessors.preprocessRequest(Preprocessors.prettyPrint(),
|
||||
Preprocessors.modifyUris().removePort(),
|
||||
Preprocessors.removeHeaders("Host", "Content-Length")),
|
||||
Preprocessors.preprocessResponse(
|
||||
Preprocessors.prettyPrint()
|
||||
),
|
||||
PayloadDocumentation.relaxedResponseFields(
|
||||
PayloadDocumentation.fieldWithPath("[].id").type(JsonFieldType.STRING).description("The id of the requested Project"),
|
||||
PayloadDocumentation.fieldWithPath("[].client").type(JsonFieldType.STRING).description("The name of the client of the requested Project"),
|
||||
PayloadDocumentation.fieldWithPath("[].title").type(JsonFieldType.STRING).description("The title of the requested Project"),
|
||||
PayloadDocumentation.fieldWithPath("[].createdAt").type(JsonFieldType.STRING).description("The date where the Project was created at"),
|
||||
PayloadDocumentation.fieldWithPath("[].tester").type(JsonFieldType.STRING).description("The user that is used as a tester in the Project"),
|
||||
PayloadDocumentation.fieldWithPath("[].logo").type(JsonFieldType.STRING).description("The sensors contained in the Project")
|
||||
)
|
||||
))*/
|
||||
}
|
||||
|
||||
val projectOne = Project(
|
||||
id = "4f6567a8-76fd-487b-8602-f82d0ca4d1f9",
|
||||
client = "E Corp",
|
||||
title = "Some Mock API (v1.0) Scanning",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Novatester",
|
||||
logo = "Insert'E_Corp.png'BASE64Encoded"
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
client = "Allsafe",
|
||||
title = "CashMyData (iOS)",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Elliot",
|
||||
logo = "Insert'Allsafe.png'BASE64Encoded"
|
||||
)
|
||||
|
||||
private fun getProjectsResponse() = listOf(
|
||||
projectOne.toProjectResponseBody(),
|
||||
projectTwo.toProjectResponseBody()
|
||||
)
|
||||
}
|
||||
|
||||
private fun cleanUp() {
|
||||
/*mongoTemplate.findAllAndRemove(Query(), Project::class.java)*/
|
||||
}
|
||||
|
||||
private fun persistBasicTestScenario() {
|
||||
// setup test data
|
||||
val projectOne = Project(
|
||||
id = "260aa538-0873-43fc-84de-3a09b008646d",
|
||||
client = "",
|
||||
title = "",
|
||||
createdAt = "",
|
||||
tester = "",
|
||||
logo = ""
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "260aa538-0873-43fc-84de-3a09b008646d",
|
||||
client = "",
|
||||
title = "",
|
||||
createdAt = "",
|
||||
tester = "",
|
||||
logo = ""
|
||||
)
|
||||
cleanUp()
|
||||
/*mongoTemplate.save(ProjectEntity(projectOne))
|
||||
mongoTemplate.save(ProjectEntity(projectTwo))*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package com.securityc4po.api.v1.project
|
||||
|
||||
import com.github.tomakehurst.wiremock.common.Json
|
||||
import com.securityc4po.api.v1.BaseIntTest
|
||||
import com.securityc4po.api.v1.configuration.SIC_INNER_SHOULD_BE_STATIC
|
||||
import com.securityc4po.api.v1.configuration.URF_UNREAD_FIELD
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.web.server.LocalServerPort
|
||||
import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import java.time.Duration
|
||||
|
||||
@AutoConfigureWireMock(port = 0)
|
||||
@SuppressFBWarnings(SIC_INNER_SHOULD_BE_STATIC, URF_UNREAD_FIELD, "Unread field will become used after database implementation")
|
||||
class ProjectControllerIntTest : BaseIntTest() {
|
||||
|
||||
@LocalServerPort
|
||||
private var port = 0
|
||||
|
||||
private lateinit var webTestClient: WebTestClient
|
||||
|
||||
@BeforeEach
|
||||
fun setupWebClient() {
|
||||
webTestClient = WebTestClient.bindToServer()
|
||||
.baseUrl("http://localhost:$port")
|
||||
.responseTimeout(Duration.ofMillis(10000))
|
||||
.build()
|
||||
}
|
||||
|
||||
/*@Autowired
|
||||
lateinit var mongoTemplate: MongoTemplate*/
|
||||
|
||||
@BeforeEach
|
||||
fun init() {
|
||||
cleanUp()
|
||||
persistBasicTestScenario()
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class GetProjects {
|
||||
@Test
|
||||
fun `requesting projects successfully`() {
|
||||
/* Implement after the implementation of database */
|
||||
|
||||
/*webTestClient.get().uri("/v1/projects")
|
||||
.header("")
|
||||
.exchange()
|
||||
.expectStatus().isOk
|
||||
.expectHeader().doesNotExist("")
|
||||
.expectBody().json(Json.write(getProjects()))*/
|
||||
}
|
||||
|
||||
val projectOne = Project(
|
||||
id = "4f6567a8-76fd-487b-8602-f82d0ca4d1f9",
|
||||
client = "E Corp",
|
||||
title = "Some Mock API (v1.0) Scanning",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Novatester",
|
||||
logo = "Insert'E_Corp.png'BASE64Encoded"
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
client = "Allsafe",
|
||||
title = "CashMyData (iOS)",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Elliot",
|
||||
logo = "Insert'Allsafe.png'BASE64Encoded"
|
||||
)
|
||||
|
||||
private fun getProjects() = listOf(
|
||||
projectOne.toProjectResponseBody(),
|
||||
projectTwo.toProjectResponseBody()
|
||||
)
|
||||
}
|
||||
|
||||
private fun cleanUp() {
|
||||
/*mongoTemplate.findAllAndRemove(Query(), Project::class.java)*/
|
||||
}
|
||||
|
||||
private fun persistBasicTestScenario() {
|
||||
// setup test data
|
||||
val projectOne = Project(
|
||||
id = "4f6567a8-76fd-487b-8602-f82d0ca4d1f9",
|
||||
client = "E Corp",
|
||||
title = "Some Mock API (v1.0) Scanning",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Novatester",
|
||||
logo = "Insert'E_Corp.png'BASE64Encoded"
|
||||
)
|
||||
val projectTwo = Project(
|
||||
id = "61360a47-796b-4b3f-abf9-c46c668596c5",
|
||||
client = "Allsafe",
|
||||
title = "CashMyData (iOS)",
|
||||
createdAt = "2021-01-10T18:05:00Z",
|
||||
tester = "Elliot",
|
||||
logo = "Insert'Allsafe.png'BASE64Encoded"
|
||||
)
|
||||
cleanUp()
|
||||
/*mongoTemplate.save(ProjectEntity(projectOne))
|
||||
mongoTemplate.save(ProjectEntity(projectTwo))*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.securityc4po.api.v1.project
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.securityc4po.api.v1.configuration.SIC_INNER_SHOULD_BE_STATIC
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.slf4j.Logger
|
||||
|
||||
@SuppressFBWarnings(SIC_INNER_SHOULD_BE_STATIC)
|
||||
class ProjectServiceTest {
|
||||
|
||||
private val log = mock<Logger>()
|
||||
|
||||
private val cut = ProjectService().apply {
|
||||
this.logger = log
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class GetProjects {
|
||||
@Test
|
||||
fun `happy path - getProjects successfully`() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue