diff --git a/Jenkinsfile b/Jenkinsfile index 06c2b68cf5db6f76963578a7c2a01e69d5064c52..81dffd261fd106e1d2409174199cb7c31aa7ab2a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -210,13 +210,18 @@ pipeline { } steps { script { - FAILED_STAGE = env.STAGE_NAME - - checkoutProvisioningRepo() - - setNewGoofyProvisioningVersion('dev') - - pushNewProvisioningVersion('dev') + if(currentBuild.changeSets.size() > 0) { + FAILED_STAGE = env.STAGE_NAME + + checkoutProvisioningRepo() + + setNewGoofyProvisioningVersion('dev') + + pushNewProvisioningVersion('dev') + } + else { + sh 'echo "no code changes found"' + } } } } @@ -234,7 +239,9 @@ pipeline { def testResult = runTests(stageName, bezeichner, 'einheitlicher-ansprechpartner') - deleteKopStack(bezeichner, stageName) + if (env.BRANCH_NAME != 'master') { + deleteKopStack(bezeichner, stageName) + } if(!testResult) { E2E_FAILED += "${stageName}, " @@ -260,7 +267,9 @@ pipeline { def testResult = runTests(stageName, bezeichner, 'main-tests') - deleteKopStack(bezeichner, stageName) + if (env.BRANCH_NAME != 'master') { + deleteKopStack(bezeichner, stageName) + } if(!testResult) { E2E_FAILED += "${stageName}, " diff --git a/goofy-client/apps/goofy-e2e/README.md b/goofy-client/apps/goofy-e2e/README.md new file mode 100644 index 0000000000000000000000000000000000000000..91f6661fd994ba8a64809bc50a80a876fd8dcc42 --- /dev/null +++ b/goofy-client/apps/goofy-e2e/README.md @@ -0,0 +1,13 @@ +# E2E + +## Gegen ein bestehenden Namespace testen + +Beispiel Namespace: sh-mastere2emain-dev + +1. Umleiten der Datenbank: `kubectl port-forward pluto-database-0 27017:27017 -n sh-mastere2emain-dev` + +2. Umleiten des Elastic Search: `kubectl port-forward ozg-search-cluster-es-ozg-search-0 9200:9200 -n elastic-system` + +3. Host Eintrag ergänzen: In `/etc/hosts` folgenden Eintrag ergänzen: `127.0.0.1 pluto-database-0.pluto-database-svc.sh-mastere2emain-dev.svc.cluster.local` + +4. Cypress mit entsprechender config starten: `npm run cypress:open -- --config-file cypress-master-main.json` diff --git a/goofy-client/apps/goofy-e2e/cypress-master-ea.json b/goofy-client/apps/goofy-e2e/cypress-master-ea.json new file mode 100644 index 0000000000000000000000000000000000000000..336cd383bcbf1faa53a03a09f36e75a4fec1447a --- /dev/null +++ b/goofy-client/apps/goofy-e2e/cypress-master-ea.json @@ -0,0 +1,40 @@ +{ + "baseUrl": "https://mastere2eea.dev.ozg-sh.de/", + "env": { + "dbUrl": "mongodb://pluto-database-user:XnHhfznNWg65NNd@localhost/admin?ssl=false", + "database": "pluto-database", + "keycloakRealm": "sh-mastere2eea-dev", + "keycloakUrl": "https://sso.dev.ozg-sh.de/", + "keycloakClient": "sh-mastere2eea-dev-goofy", + "sabineUuid": "c2e95389-a86d-49b7-993d-12105b1a5408", + "search": { + "url": "https://localhost:9200", + "index": "sh-mastere2eea-dev", + "user": "sh-mastere2eea-dev", + "password": "VtMqdo0ctphHkDH" + }, + "userManager": { + "dbUrl":"mongodb://user-manager-database-user:Er5CuXV6eBmYPy7@localhost/admin?ssl=false", + "database":"user-manager-database" + } + }, + "fileServerFolder": ".", + "fixturesFolder": "./src/fixtures", + "integrationFolder": "./src/integration", + "modifyObstructiveCode": false, + "pluginsFile": "./src/plugins/index", + "supportFile": "./src/support/index.ts", + "video": true, + "videosFolder": "./reports/videos", + "screenshotsFolder": "./reports/screenshots", + "chromeWebSecurity": false, + "reporter": "../../node_modules/cypress-mochawesome-reporter", + "defaultCommandTimeout": 10000, + "reporterOptions": { + "html": false, + "json": true, + "reportDir": "./reports/mochawesome-report", + "reportFilename": "report", + "overwrite": true + } +} \ No newline at end of file diff --git a/goofy-client/apps/goofy-e2e/cypress-master-main.json b/goofy-client/apps/goofy-e2e/cypress-master-main.json new file mode 100644 index 0000000000000000000000000000000000000000..6575029056e9d5d73fc2cfc395d6f64d60b6d186 --- /dev/null +++ b/goofy-client/apps/goofy-e2e/cypress-master-main.json @@ -0,0 +1,40 @@ +{ + "baseUrl": "https://mastere2emain.dev.ozg-sh.de/", + "env": { + "dbUrl": "mongodb://pluto-database-user:XnHhfznNWg65NNd@localhost/admin?ssl=false", + "database": "pluto-database", + "keycloakRealm": "sh-mastere2emain-dev", + "keycloakUrl": "https://sso.dev.ozg-sh.de/", + "keycloakClient": "sh-mastere2emain-dev-goofy", + "sabineUuid": "5f2efd21-250a-4c0a-ab7d-f324764a5d69", + "search": { + "url": "https://localhost:9200", + "index": "sh-mastere2emain-dev", + "user": "sh-mastere2emain-dev", + "password": "bea5hCA2RTsJupP" + }, + "userManager": { + "dbUrl":"mongodb://user-manager-database-user:7eDJTX397PytrOk@localhost/admin?ssl=false", + "database":"user-manager-database" + } + }, + "fileServerFolder": ".", + "fixturesFolder": "./src/fixtures", + "integrationFolder": "./src/integration", + "modifyObstructiveCode": false, + "pluginsFile": "./src/plugins/index", + "supportFile": "./src/support/index.ts", + "video": true, + "videosFolder": "./reports/videos", + "screenshotsFolder": "./reports/screenshots", + "chromeWebSecurity": false, + "reporter": "../../node_modules/cypress-mochawesome-reporter", + "defaultCommandTimeout": 10000, + "reporterOptions": { + "html": false, + "json": true, + "reportDir": "./reports/mochawesome-report", + "reportFilename": "report", + "overwrite": true + } +} \ No newline at end of file diff --git a/goofy-client/apps/goofy-e2e/src/components/user-profile/current-user-profile.component.e2e.ts b/goofy-client/apps/goofy-e2e/src/components/user-profile/current-user-profile.component.e2e.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8576004728ef910895cefaa6807368eeb50756f --- /dev/null +++ b/goofy-client/apps/goofy-e2e/src/components/user-profile/current-user-profile.component.e2e.ts @@ -0,0 +1,30 @@ +import { UserProfileE2EComponent } from './user-profile.component.e2e'; + +export class CurrentUserProfileE2EComponent { + + private readonly locatorUserIconButton: string = 'user-icon-button'; + private readonly locatorLogoutButton: string = 'logout-button'; + + private readonly locatorRoot: string = 'current-user'; + + public getRoot() { + return cy.getTestElement(this.locatorRoot); + } + + public getUserProfile(): UserProfileE2EComponent { + return new UserProfileE2EComponent(this.locatorRoot); + } + + public logout(): void { + this.getUserIconButton().click(); + this.getLogoutButton().click(); + } + + private getUserIconButton() { + return cy.getTestElement(this.locatorUserIconButton); + } + + private getLogoutButton() { + return cy.getTestElement(this.locatorLogoutButton); + } +} \ No newline at end of file diff --git a/goofy-client/apps/goofy-e2e/src/integration/einheitlicher-ansprechpartner/navigation/navigation.e2e-spec.ts b/goofy-client/apps/goofy-e2e/src/integration/einheitlicher-ansprechpartner/navigation/navigation.e2e-spec.ts index c0fcd0535bd473b973157f8a0d997b311fcc572c..a55d8226aa0c071050d0393d7676bdf517c2454b 100644 --- a/goofy-client/apps/goofy-e2e/src/integration/einheitlicher-ansprechpartner/navigation/navigation.e2e-spec.ts +++ b/goofy-client/apps/goofy-e2e/src/integration/einheitlicher-ansprechpartner/navigation/navigation.e2e-spec.ts @@ -13,15 +13,20 @@ describe('Navigation', () => { before(() => { loginAsEmil(); - - waitForSpinnerToDisappear(); - exist(vorgangList.getRoot()); }) after(() => { dropCollections(); }) + describe('after login', () => { + + it('should show vorgangList', { defaultCommandTimeout: 30000 }, () => { + waitForSpinnerToDisappear(); + exist(vorgangList.getRoot()); + }) + }) + describe('navigation item myVorgaenge', () => { it('should not exists', () => { diff --git a/goofy-client/apps/goofy-e2e/src/integration/main-tests/app/buildinfo.e2e-spec.ts b/goofy-client/apps/goofy-e2e/src/integration/main-tests/app/buildinfo.e2e-spec.ts index 2173435c27c08c68e83d7ef4d58916348b7bc964..a0cfd2fa7e995a0b6f247501830e46c8483b3d9a 100644 --- a/goofy-client/apps/goofy-e2e/src/integration/main-tests/app/buildinfo.e2e-spec.ts +++ b/goofy-client/apps/goofy-e2e/src/integration/main-tests/app/buildinfo.e2e-spec.ts @@ -12,15 +12,20 @@ describe('Buildinfo', () => { before(() => { loginAsSabine(); - - waitForSpinnerToDisappear(); - exist(vorgangList.getRoot()); }) after(() => { dropCollections(); }) + describe('after login', () => { + + it('should show vorgangList', { defaultCommandTimeout: 30000 }, () => { + waitForSpinnerToDisappear(); + exist(vorgangList.getRoot()); + }) + }) + describe('buildinfo', () => { it('should show version', () => { diff --git a/goofy-client/apps/goofy-e2e/src/integration/main-tests/app/login-logout.e2e-spec.ts b/goofy-client/apps/goofy-e2e/src/integration/main-tests/app/login-logout.e2e-spec.ts index f3cca66e65178ddd12d7504fa2ffb8310649a7e3..0223e6b2cf65832b7027f9abf4d1b21c9fdff722 100644 --- a/goofy-client/apps/goofy-e2e/src/integration/main-tests/app/login-logout.e2e-spec.ts +++ b/goofy-client/apps/goofy-e2e/src/integration/main-tests/app/login-logout.e2e-spec.ts @@ -1,13 +1,16 @@ +import { App } from 'apps/goofy-e2e/src/model/app'; +import { getApp } from 'apps/goofy-e2e/src/support/app-util'; import { UserE2E } from '../../../model/user'; import { HeaderE2EComponent } from '../../../page-objects/header.po'; import { MainPage } from '../../../page-objects/main.po'; import { exist, haveText } from '../../../support/cypress.util'; import { getUserSabine } from '../../../support/user-util'; -const mainFixture = require('../../../fixtures/main.json'); -const user: UserE2E = getUserSabine(); - describe('Login and Logout', () => { + + const app: App = getApp(); + const user: UserE2E = getUserSabine(); + const mainPage: MainPage = new MainPage(); const header: HeaderE2EComponent = mainPage.getHeader(); @@ -24,11 +27,11 @@ describe('Login and Logout', () => { }) it('should display Goofy', () => { - haveText(header.getTitle(), mainFixture.title); + haveText(header.getTitle(), app.title); }) - it.skip('FIXME(OZG-2950 UserManager) should logout', () => { - header.logout(); + it('should logout', () => { + header.getCurrentUserProfile().logout(); exist(cy.get('#kc-login')); }) diff --git a/goofy-client/apps/goofy-e2e/src/integration/main-tests/navigation/navigation.e2e-spec.ts b/goofy-client/apps/goofy-e2e/src/integration/main-tests/navigation/navigation.e2e-spec.ts index bee58f155197c4b2e473ca055d281a15b85cc168..4862efcb5eedb309e308af3645f6a5972df5c791 100644 --- a/goofy-client/apps/goofy-e2e/src/integration/main-tests/navigation/navigation.e2e-spec.ts +++ b/goofy-client/apps/goofy-e2e/src/integration/main-tests/navigation/navigation.e2e-spec.ts @@ -5,7 +5,7 @@ import { VorgangE2E } from 'apps/goofy-e2e/src/model/vorgang'; import { MainPage, waitForSpinnerToDisappear } from 'apps/goofy-e2e/src/page-objects/main.po'; import { dropCollections } from 'apps/goofy-e2e/src/support/cypress-helper'; import { CypressKeyboardActions, exist, notExist } from 'apps/goofy-e2e/src/support/cypress.util'; -import { getUserManagerUserEmil, getUserManagerUserPeter, getUserManagerUserSabine, initUsermanagerUsers, loginAsSabine } from 'apps/goofy-e2e/src/support/user-util'; +import { getUserManagerUserEmil, getUserManagerUserPeter, getUserManagerUserSabine, getUserSabineInternalId, initUsermanagerUsers, loginAsSabine } from 'apps/goofy-e2e/src/support/user-util'; import { buildVorgang, createVorgang, initSearchIndex, initVorgaenge, objectIds } from 'apps/goofy-e2e/src/support/vorgang-util'; describe('Navigation', () => { @@ -18,8 +18,8 @@ describe('Navigation', () => { const vorgang: VorgangE2E = createVorgang(); const vorgangNotBeFiltered: VorgangE2E = { ...buildVorgang(objectIds[0], 'vorgangNotBeFiltered') }; - const vorgangAssigned: VorgangE2E = { ...buildVorgang(objectIds[1], 'vorgangAssigned'), assignedTo: usermanagerUserSabine.externalId }; - const vorgangAssignedNotBeFiltered: VorgangE2E = { ...buildVorgang(objectIds[2], 'vorgangAssignedNotBeFiltered'), assignedTo: usermanagerUserSabine.externalId }; + const vorgangAssigned: VorgangE2E = { ...buildVorgang(objectIds[1], 'vorgangAssigned'), assignedTo: getUserSabineInternalId() }; + const vorgangAssignedNotBeFiltered: VorgangE2E = { ...buildVorgang(objectIds[2], 'vorgangAssignedNotBeFiltered'), assignedTo: getUserSabineInternalId() }; const searchString: string = 'NotBeFiltered'; diff --git a/goofy-client/apps/goofy-e2e/src/integration/main-tests/user-profile/user-profile-current-user-icon.e2e-spec.ts b/goofy-client/apps/goofy-e2e/src/integration/main-tests/user-profile/user-profile-current-user-icon.e2e-spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0d340d4fd447a77ae64b9ed69327d22376d8075 --- /dev/null +++ b/goofy-client/apps/goofy-e2e/src/integration/main-tests/user-profile/user-profile-current-user-icon.e2e-spec.ts @@ -0,0 +1,44 @@ +import { CurrentUserProfileE2EComponent } from "apps/goofy-e2e/src/components/user-profile/current-user-profile.component.e2e"; +import { UserE2E } from "apps/goofy-e2e/src/model/user"; +import { HeaderE2EComponent } from "apps/goofy-e2e/src/page-objects/header.po"; +import { MainPage, waitForSpinnerToDisappear } from "apps/goofy-e2e/src/page-objects/main.po"; +import { dropCollections } from "apps/goofy-e2e/src/support/cypress-helper"; +import { exist, haveText } from "apps/goofy-e2e/src/support/cypress.util"; +import { getUserManagerUserSabine, getUserSabine, initUsermanagerUsers, loginAsSabine } from "apps/goofy-e2e/src/support/user-util"; + +describe('Current User Profile', () => { + const mainPage: MainPage = new MainPage(); + + const header: HeaderE2EComponent = mainPage.getHeader(); + const currentUserProfile: CurrentUserProfileE2EComponent = header.getCurrentUserProfile(); + + const userSabine: UserE2E = getUserSabine(); + + describe('for sabine', () => { + + before(() => { + initUsermanagerUsers([getUserManagerUserSabine()]); + + loginAsSabine(); + + waitForSpinnerToDisappear(); + exist(header.getRoot()); + }) + + after(() => { + dropCollections(); + }) + + it('should show current user profile', () => { + exist(currentUserProfile.getRoot()); + }) + + it('should show assigned icon', () => { + exist(currentUserProfile.getUserProfile().getIconContainer().getAssignedIcon()); + }) + + it('should show initials', () => { + haveText(currentUserProfile.getUserProfile().getIconContainer().getAssignedIcon(), userSabine.initials) + }) + }) +}) \ No newline at end of file diff --git a/goofy-client/apps/goofy-e2e/src/model/app.ts b/goofy-client/apps/goofy-e2e/src/model/app.ts new file mode 100644 index 0000000000000000000000000000000000000000..5e0f1e90ea345f6b76080b78940354133b09f16e --- /dev/null +++ b/goofy-client/apps/goofy-e2e/src/model/app.ts @@ -0,0 +1,3 @@ +export class App { + title: string +} \ No newline at end of file diff --git a/goofy-client/apps/goofy-e2e/src/page-objects/header.po.ts b/goofy-client/apps/goofy-e2e/src/page-objects/header.po.ts index b2527afde30ccc7d93e5b2680044509d7f24261d..96a927b8f6022e8610dc9bd0c885b1fc4f0ab839 100644 --- a/goofy-client/apps/goofy-e2e/src/page-objects/header.po.ts +++ b/goofy-client/apps/goofy-e2e/src/page-objects/header.po.ts @@ -1,31 +1,27 @@ +import { CurrentUserProfileE2EComponent } from "../components/user-profile/current-user-profile.component.e2e"; import { UserSettingsE2EComponent } from "../components/user-settings/user-settings.component.e2e"; export class HeaderE2EComponent { - private readonly locatorUserIconButton: string = 'user-icon-button'; - private readonly locatorLogoutButton: string = 'logout-button'; private readonly locatorTitle: string = 'title'; + private readonly locatorRoot: string = 'header'; private readonly userSettings: UserSettingsE2EComponent = new UserSettingsE2EComponent(); + private readonly currentUserProfile: CurrentUserProfileE2EComponent = new CurrentUserProfileE2EComponent(); - public getTitle() { - return cy.getTestElement(this.locatorTitle); - } - - public logout(): void { - this.getUserIconButton().click(); - this.getLogoutButton().click(); - } - - private getUserIconButton() { - return cy.getTestElement(this.locatorUserIconButton); + public getRoot() { + return cy.getTestElement(this.locatorRoot); } - private getLogoutButton() { - return cy.getTestElement(this.locatorLogoutButton); + public getTitle() { + return cy.getTestElement(this.locatorTitle); } public getUserSettings(): UserSettingsE2EComponent { return this.userSettings; } + + public getCurrentUserProfile(): CurrentUserProfileE2EComponent { + return this.currentUserProfile; + } } \ No newline at end of file diff --git a/goofy-client/apps/goofy-e2e/src/plugins/index.js b/goofy-client/apps/goofy-e2e/src/plugins/index.js index 232ec66bc71746d07c117e46debd59c555aa59ad..0ca7f2013436776942e95db051a1e5d1576d229b 100644 --- a/goofy-client/apps/goofy-e2e/src/plugins/index.js +++ b/goofy-client/apps/goofy-e2e/src/plugins/index.js @@ -56,6 +56,11 @@ module.exports = (on, config) => { console.log('dropCollections: ', collections); dropCollectionsFromDatabase(config, collections); return 0; + }, + dropUserManagerCollections(collections) { + console.log('dropUserManagerCollections: ', collections); + dropUserManagerCollectionsFromDatabase(config, collections); + return 0; } }); @@ -215,11 +220,19 @@ function createNumberLong(numberValue){ } function insertIntoDatabase(config, collection, data) { - MongoClient.connect(buildDatabaseUrl(config), (error, connection) => { + insert(getDatabaseUrl(config), getDatabase(config), collection, data); +} + +function insertIntoUserManagerDatabase(config, collection, data){ + insert(getUserManagerDatabaseUrl(config), getUserManagerDatabase(config), collection, data); +} + +function insert(databaseUrl, databaseName, collection, data){ + MongoClient.connect(databaseUrl, (error, connection) => { console.log('connect to database...') if (!error) { console.log('success'); - var db = connection.db(config.env.database); + var db = connection.db(databaseName); db.collection(collection).drop(() => { db.createCollection(collection, (error) => handleCreateCollection(db, connection, collection, data, error)); @@ -253,12 +266,37 @@ function handleInsertMany(connection, error) { } function dropCollectionsFromDatabase(config, collections) { - MongoClient.connect(buildDatabaseUrl(config), (error, connection) => { + dropCollections(getDatabaseUrl(config), getDatabase(config), collections); +} + +function getDatabaseUrl(config){ + return config.env.dbUrl; +} + +function getDatabase(config){ + return config.env.database +} + +function dropUserManagerCollectionsFromDatabase(config, collections){ + dropCollections(getUserManagerDatabaseUrl(config), getUserManagerDatabase(config), collections); +} + +function getUserManagerDatabaseUrl(config){ + return config.env.userManager.dbUrl; +} + +function getUserManagerDatabase(config){ + return config.env.userManager.database; +} + +function dropCollections(databaseUrl, databaseName, collections){ + MongoClient.connect(databaseUrl, (error, connection) => { if (!error) { - var db = connection.db(config.env.database); + var db = connection.db(databaseName); collections.forEach((oneCollection, index) => { console.log('drop collection', oneCollection); db.collection(oneCollection).drop(() => { + //CHECKME Ist die Abfrage notwendig? if(index == collections.length){ console.log('close connection'); connection.close(); @@ -267,28 +305,4 @@ function dropCollectionsFromDatabase(config, collections) { }); } }); -} - -function buildDatabaseUrl(config) { - return config.env.dbUrl; -} - -function insertIntoUserManagerDatabase(config, collection, data){ - MongoClient.connect(buildUsermanagerDatabaseUrl(config), (error, connection) => { - console.log('connect to database...') - if (!error) { - console.log('success'); - var db = connection.db(config.env.userManager.database); - - db.collection(collection).drop(() => { - db.createCollection(collection, (error) => handleCreateCollection(db, connection, collection, data, error)); - }); - } else { - console.log('fail', error); - } - }); -} - -function buildUsermanagerDatabaseUrl(config){ - return config.env.userManager.dbUrl; } \ No newline at end of file diff --git a/goofy-client/apps/goofy-e2e/src/support/app-util.ts b/goofy-client/apps/goofy-e2e/src/support/app-util.ts new file mode 100644 index 0000000000000000000000000000000000000000..98758452698ecf8a460ebc892b31a3d6da4dc427 --- /dev/null +++ b/goofy-client/apps/goofy-e2e/src/support/app-util.ts @@ -0,0 +1,8 @@ +import { App } from '../model/app'; + +//TODO main.json in app.json umbenennen +const appFixture: App = require('../fixtures/main.json'); + +export function getApp(): App { + return appFixture; +} \ No newline at end of file diff --git a/goofy-client/apps/goofy-e2e/src/support/cypress-helper.ts b/goofy-client/apps/goofy-e2e/src/support/cypress-helper.ts index 91b16ab54160f3518505c814c09cd44ebdf7ea50..20642b9371085595d0e1fdeb3acb8cff1ccc4d48 100644 --- a/goofy-client/apps/goofy-e2e/src/support/cypress-helper.ts +++ b/goofy-client/apps/goofy-e2e/src/support/cypress-helper.ts @@ -6,8 +6,8 @@ import { VorgangE2E } from '../model/vorgang'; import { VorgangAttachedItemE2E } from '../model/vorgang-attached-item'; enum CypressTasks { - DROP_COLLECTION = 'dropCollection', DROP_COLLECTIONS = 'dropCollections', + DROP_USER_MANAGER_COLLECTIONS = 'dropUserManagerCollections', INIT_COMMAND_DATA = 'initCommandData', INIT_GRID_FS_FILE_DATA = 'initGridFsFileData', INIT_GRID_FS_CHUNK_DATA = 'initGridFsChunkData', @@ -80,7 +80,8 @@ export function initUsermanagerData(data: UsermanagerUserE2E[]): void { } export function dropCollections() { - cy.task(CypressTasks.DROP_COLLECTIONS, [MongoCollections.COMMAND, MongoCollections.VORGANG, MongoCollections.VORGANG_ATTACHED_ITEM, MongoCollections.FS_FILES, MongoCollections.FS_CHUNKS, MongoCollections.USER]); + cy.task(CypressTasks.DROP_COLLECTIONS, [MongoCollections.COMMAND, MongoCollections.VORGANG, MongoCollections.VORGANG_ATTACHED_ITEM, MongoCollections.FS_FILES, MongoCollections.FS_CHUNKS]); + cy.task(CypressTasks.DROP_USER_MANAGER_COLLECTIONS, [MongoCollections.USER]); } export function scrollToWindowBottom(): void { diff --git a/goofy-client/apps/goofy-e2e/start-e2e-environment.sh b/goofy-client/apps/goofy-e2e/start-e2e-environment.sh index cb35b1ea66542ef9e83406a11383b95847581ce6..7007869b39a5897d87749d22ec5439672935fcd0 100755 --- a/goofy-client/apps/goofy-e2e/start-e2e-environment.sh +++ b/goofy-client/apps/goofy-e2e/start-e2e-environment.sh @@ -13,7 +13,7 @@ echo if [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then - DOCKER_GATEWAY_HOST=172.17.0.1 + export DOCKER_GATEWAY_HOST=172.17.0.1 fi docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d ozg-mongodb ozg-usermanager ozg-elastic diff --git a/goofy-client/libs/navigation/src/lib/header-container/header/header.component.html b/goofy-client/libs/navigation/src/lib/header-container/header/header.component.html index 44beeb8de47346ca9eec1d8d6b1a7fcaf239c197..d1a44c1627d422a791c7aa862ab0be58cd7e2e97 100644 --- a/goofy-client/libs/navigation/src/lib/header-container/header/header.component.html +++ b/goofy-client/libs/navigation/src/lib/header-container/header/header.component.html @@ -1,4 +1,4 @@ -<header> +<header data-test-id="header"> <div class="left"> <goofy-client-icon-button-with-spinner icon="menu" toolTip="Hauptmenü umschalten" (clickEmitter)="toggleMenuEvent.emit(!this.navigationCollapse)"> </goofy-client-icon-button-with-spinner> @@ -16,7 +16,7 @@ <div class="right"> <goofy-client-user-settings-container data-test-id="user-settings"></goofy-client-user-settings-container> - <goofy-client-user-profile-in-header-container></goofy-client-user-profile-in-header-container> + <goofy-client-user-profile-in-header-container data-test-id="current-user"></goofy-client-user-profile-in-header-container> </div> </header> diff --git a/goofy-server/pom.xml b/goofy-server/pom.xml index 448ed43101e28e88ac34279e06b115598f8da8f6..9c68b482b0988f999a7cb1385bee185836eb7e44 100644 --- a/goofy-server/pom.xml +++ b/goofy-server/pom.xml @@ -89,6 +89,10 @@ <groupId>de.itvsh.ozg.pluto</groupId> <artifactId>pluto-utils</artifactId> </dependency> + <dependency> + <groupId>de.itvsh.kop.common</groupId> + <artifactId>kop-common-pdf</artifactId> + </dependency> <!-- tools --> <dependency> diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteService.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteService.java index 8e3b0f26ed6515492f4e0a3b51f7421eade65025..dff48916a6ec2ec09c17bf9c30582c2a322d481c 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteService.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteService.java @@ -1,18 +1,13 @@ package de.itvsh.goofy.common.binaryfile; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -30,7 +25,6 @@ import de.itvsh.ozg.pluto.grpc.binaryFile.GrpcGetBinaryFileDataRequest; import de.itvsh.ozg.pluto.grpc.binaryFile.GrpcUploadBinaryFileMetaData; import de.itvsh.ozg.pluto.grpc.binaryFile.GrpcUploadBinaryFileRequest; import de.itvsh.ozg.pluto.grpc.file.GrpcOzgFile; -import io.grpc.stub.CallStreamObserver; import net.devh.boot.grpc.client.inject.GrpcClient; @Service @@ -69,23 +63,17 @@ class BinaryFileRemoteService { public CompletableFuture<FileId> uploadFile(UploadBinaryFileRequest uploadBinaryFileRequest) { var fileIdFuture = new CompletableFuture<FileId>(); - var responseObserver = createUploadBinaryFileObserver(fileIdFuture); + var responseObserver = createUploadBinaryFileObserver(fileIdFuture, uploadBinaryFileRequest); - var requestObserver = (CallStreamObserver<GrpcUploadBinaryFileRequest>) asyncServiceStub.uploadBinaryFileAsStream(responseObserver); - - sendBinaryFile(requestObserver, uploadBinaryFileRequest); + asyncServiceStub.uploadBinaryFileAsStream(responseObserver); return fileIdFuture; } - BinaryFileUploadStreamObserver createUploadBinaryFileObserver(CompletableFuture<FileId> fileIdFuture) { - return new BinaryFileUploadStreamObserver(fileIdFuture); - } - - void sendBinaryFile(CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver, UploadBinaryFileRequest uploadBinaryFileRequest) { - requestObserver.onNext(buildMetaDataRequest(uploadBinaryFileRequest)); - sendAsChunks(requestObserver, uploadBinaryFileRequest.getUploadStream()); - requestObserver.onCompleted(); + BinaryFileUploadStreamObserver createUploadBinaryFileObserver(CompletableFuture<FileId> fileIdFuture, UploadBinaryFileRequest uploadBinaryFileRequest) { + var metadataRequest = buildMetaDataRequest(uploadBinaryFileRequest); + var streamer = new ChunkedFileSender<>(uploadBinaryFileRequest.getUploadStream(), CHUNK_SIZE, this::buildChunkRequest, metadataRequest); + return new BinaryFileUploadStreamObserver(fileIdFuture, streamer); } GrpcUploadBinaryFileRequest buildMetaDataRequest(UploadBinaryFileRequest uploadBinaryFileRequest) { @@ -100,44 +88,6 @@ class BinaryFileRemoteService { .build(); } - void sendAsChunks(CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver, InputStream uploadStream) { - try (var bufferUploadStream = getAsBufferedStream(uploadStream)) { - while (hasDataToRead(bufferUploadStream)) { - sendNextChunk(requestObserver, bufferUploadStream); - } - } catch (IOException e) { - throw new TechnicalException("Error on closing input file stream", e); - } - } - - BufferedInputStream getAsBufferedStream(InputStream uploadStream) { - return IOUtils.buffer(uploadStream); - } - - boolean hasDataToRead(BufferedInputStream uploadStream) throws IOException { - return uploadStream.available() > 0; - } - - void sendNextChunk(CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver, BufferedInputStream uploadStream) { - if (requestObserver.isReady()) { - sendChunk(requestObserver, uploadStream); - } - } - - void sendChunk(CallStreamObserver<GrpcUploadBinaryFileRequest> streamObserver, BufferedInputStream uploadStream) { - byte[] content = readFromStream(uploadStream, CHUNK_SIZE); - - streamObserver.onNext(buildChunkRequest(content)); - } - - private byte[] readFromStream(BufferedInputStream uploadStream, int size) { - try { - return uploadStream.readNBytes(size); - } catch (IOException e) { - throw new TechnicalException("Error on sending a single chunk", e); - } - } - GrpcUploadBinaryFileRequest buildChunkRequest(byte[] bytes) { return GrpcUploadBinaryFileRequest.newBuilder().setFileContent((ByteString.copyFrom(bytes))).build(); } @@ -160,7 +110,7 @@ class BinaryFileRemoteService { } private List<String> mapFileIds(List<FileId> fileIds) { - return fileIds.stream().map(fileIdMapper::toString).collect(Collectors.toList()); + return fileIds.stream().map(fileIdMapper::toString).toList(); } public void writeFileContent(FileId fileId, OutputStream out) { @@ -183,10 +133,6 @@ class BinaryFileRemoteService { } } - void throwTechnicalException(Exception e) { - throw new TechnicalException("Error completing download future on grpc", e); - } - BinaryFileDownloadStreamObserver createDownloadBinaryFileObserver(CompletableFuture<Boolean> streamFuture, OutputStream out) { return new BinaryFileDownloadStreamObserver(streamFuture, out); } diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileUploadStreamObserver.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileUploadStreamObserver.java index cf13566064d7341b7f3bc86a5c5ab013f0044844..889056aba1da2ff7c02aecd31ad98056cf4fd45a 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileUploadStreamObserver.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/BinaryFileUploadStreamObserver.java @@ -2,19 +2,30 @@ package de.itvsh.goofy.common.binaryfile; import java.util.concurrent.CompletableFuture; +import de.itvsh.ozg.pluto.grpc.binaryFile.GrpcUploadBinaryFileRequest; import de.itvsh.ozg.pluto.grpc.binaryFile.GrpcUploadBinaryFileResponse; -import io.grpc.stub.StreamObserver; +import io.grpc.stub.ClientCallStreamObserver; +import io.grpc.stub.ClientResponseObserver; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor(access = AccessLevel.PROTECTED) -class BinaryFileUploadStreamObserver implements StreamObserver<GrpcUploadBinaryFileResponse> { +class BinaryFileUploadStreamObserver implements ClientResponseObserver<GrpcUploadBinaryFileRequest, GrpcUploadBinaryFileResponse> { private final CompletableFuture<FileId> fileIdFuture; + private final ChunkedFileSender<GrpcUploadBinaryFileRequest> fileStreamer; + @Getter private String fileId; + private ClientCallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver; + + @Override + public void beforeStart(ClientCallStreamObserver<GrpcUploadBinaryFileRequest> requestStream) { + this.requestObserver = requestStream; + requestObserver.setOnReadyHandler(() -> fileStreamer.sendChunkTo(requestObserver)); + } @Override public void onNext(GrpcUploadBinaryFileResponse response) { fileId = response.getFileId(); diff --git a/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/ChunkedFileSender.java b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/ChunkedFileSender.java new file mode 100644 index 0000000000000000000000000000000000000000..263948a45e2dc4b131c65d87b672a7f632e9bd4e --- /dev/null +++ b/goofy-server/src/main/java/de/itvsh/goofy/common/binaryfile/ChunkedFileSender.java @@ -0,0 +1,61 @@ +package de.itvsh.goofy.common.binaryfile; + +import de.itvsh.kop.common.errorhandling.TechnicalException; +import io.grpc.stub.CallStreamObserver; +import lombok.AllArgsConstructor; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +@AllArgsConstructor +class ChunkedFileSender<T> { + + private final AtomicBoolean hasUploadFile = new AtomicBoolean(true); + private final InputStream uploadStream; + private final int chunkSize; + private final Function<byte[], T> buildChunkRequest; + private T requestMetadata; + + public void sendChunkTo(CallStreamObserver<T> streamObserver) { + if (hasUploadFile.get()) { + sendMetadata(streamObserver); + int size = sendNextChunk(streamObserver); + if (size < chunkSize) { + handleFileEndReached(streamObserver); + } + } + } + + private void sendMetadata(CallStreamObserver<T> streamObserver) { + if(requestMetadata != null) { + streamObserver.onNext(requestMetadata); + requestMetadata = null; + } + } + + private int sendNextChunk(CallStreamObserver<T> streamObserver) { + byte[] content = readFromStream(); + var size = content.length; + if (size > 0) { + streamObserver.onNext(buildChunkRequest.apply(content)); + } + return size; + } + + private byte[] readFromStream() { + try { + return uploadStream.readNBytes(chunkSize); + } catch (IOException e) { + throw new TechnicalException("Error on sending a single chunk", e); + } + } + + private void handleFileEndReached(CallStreamObserver<T> streamObserver) { + IOUtils.closeQuietly(uploadStream); + streamObserver.onCompleted(); + hasUploadFile.getAndSet(false); + } +} diff --git a/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailController.java b/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailController.java index 16fffe84d057e6bcd731f2a7964a6f1d441b9796..b4a05600b45ab52eeb402efc62a70856490e5d49 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailController.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailController.java @@ -2,6 +2,8 @@ package de.itvsh.goofy.postfach; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.Optional; import java.util.stream.Stream; @@ -9,6 +11,8 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -17,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import de.itvsh.goofy.common.binaryfile.BinaryFileController; import de.itvsh.goofy.common.command.CommandController; @@ -35,6 +40,9 @@ public class PostfachMailController { public static final String PARAM_VORGANG_ID = "vorgangId"; + static final String PDF_NAME_TEMPLATE = "%s_%s_Nachrichten.pdf"; + static final SimpleDateFormat PDF_NAME_DATE_FORMATTER = new SimpleDateFormat("YYYYMMDD"); + @Autowired private PostfachMailService service; @Autowired @@ -52,6 +60,28 @@ public class PostfachMailController { return assembler.toCollectionModel(sort(service.getAll(vorgangId)), vorgang, getPostfachId(vorgang)); } + @GetMapping(params = PARAM_VORGANG_ID, produces = MediaType.APPLICATION_PDF_VALUE) + public ResponseEntity<StreamingResponseBody> getAllAsPdf(@RequestParam String vorgangId) { + var vorgang = getVorgang(vorgangId); + + return buildResponseEntity(vorgang, createDownloadStreamingBody(vorgang)); + } + + StreamingResponseBody createDownloadStreamingBody(VorgangWithEingang vorgang) { + return out -> service.getAllAsPdf(vorgang, out); + } + + ResponseEntity<StreamingResponseBody> buildResponseEntity(VorgangWithEingang vorgang, StreamingResponseBody responseBody) { + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, buildPdfName(vorgang)) + .contentType(MediaType.APPLICATION_PDF) + .body(responseBody); + } + + private String buildPdfName(VorgangWithEingang vorgang) { + return String.format(PDF_NAME_TEMPLATE, vorgang.getNummer(), PDF_NAME_DATE_FORMATTER.format(new Date())); + } + private VorgangWithEingang getVorgang(String vorgangId) { return vorgangController.getVorgang(vorgangId); } diff --git a/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailPdfService.java b/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailPdfService.java new file mode 100644 index 0000000000000000000000000000000000000000..db7b191919a5658a4b2558d4336b00871cd7fda9 --- /dev/null +++ b/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailPdfService.java @@ -0,0 +1,44 @@ +package de.itvsh.goofy.postfach; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.stereotype.Service; + +import de.itvsh.goofy.common.errorhandling.FunctionalException; +import de.itvsh.goofy.vorgang.VorgangWithEingang; +import de.itvsh.kop.common.pdf.PdfService; + +@Service +class PostfachMailPdfService { + + static final String PDF_TEMPLATE_PATH = "classpath:postfach_nachrichten_template.xsl"; + + @Autowired + private PdfService pdfService; + + @Value(PostfachMailPdfService.PDF_TEMPLATE_PATH) + private Resource pdfTemplate; + + public OutputStream getAllAsPdf(VorgangWithEingang vorgang, OutputStream out) { + return pdfService.createPdf(getTemplate(), out, buildModel(vorgang)); + } + + InputStream getTemplate() { + try { + return pdfTemplate.getInputStream(); + } catch (IOException e) { + // TODO Exception definieren + throw new FunctionalException(() -> "Pdf Template for postfach nachrichten not found"); + } + } + + PostfachNachrichtenPdfModel buildModel(VorgangWithEingang vorgang) { + // TODO Setzen der Werte + return new PostfachNachrichtenPdfModel(); + } +} \ No newline at end of file diff --git a/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailService.java b/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailService.java index 93dadb6cc66b19d0ef41318fb960a171e1152ba9..eca9c0c669d6d5dd651d82d1297803a926a681d3 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailService.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachMailService.java @@ -1,5 +1,6 @@ package de.itvsh.goofy.postfach; +import java.io.OutputStream; import java.util.Objects; import java.util.stream.Stream; @@ -7,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import de.itvsh.goofy.common.errorhandling.ResourceNotFoundException; +import de.itvsh.goofy.vorgang.VorgangWithEingang; import lombok.extern.log4j.Log4j2; @Log4j2 @@ -15,6 +17,9 @@ class PostfachMailService { private Boolean isPostfachConfigured = null; + @Autowired + private PostfachMailPdfService pdfService; + @Autowired private PostfachMailRemoteService remoteService; @@ -45,4 +50,8 @@ class PostfachMailService { } return isPostfachConfigured; } + + public OutputStream getAllAsPdf(VorgangWithEingang vorgang, OutputStream out) { + return pdfService.getAllAsPdf(vorgang, out); + } } \ No newline at end of file diff --git a/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachNachrichtenPdfModel.java b/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachNachrichtenPdfModel.java new file mode 100644 index 0000000000000000000000000000000000000000..2dc015b3a66fbeb2d2771db1e1e0b9ce808c018f --- /dev/null +++ b/goofy-server/src/main/java/de/itvsh/goofy/postfach/PostfachNachrichtenPdfModel.java @@ -0,0 +1,17 @@ +package de.itvsh.goofy.postfach; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import lombok.Getter; + +@Getter +@XmlRootElement +class PostfachNachrichtenPdfModel { + + @XmlElement + private String vorgangsTyp = "VorgangsTypTestValue"; + + @XmlElement + private String vorgangsNummer = "VorgangsNummerTestValue"; +} \ No newline at end of file diff --git a/goofy-server/src/main/resources/fop/postfach-nachrichten.xsl b/goofy-server/src/main/resources/fop/postfach-nachrichten.xsl new file mode 100644 index 0000000000000000000000000000000000000000..3daed3ceb700089f666fd47c403464e99267b2e1 --- /dev/null +++ b/goofy-server/src/main/resources/fop/postfach-nachrichten.xsl @@ -0,0 +1,43 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.1"> + + <xsl:template name="functional-template" match="/testModel"> + <fo:flow flow-name="xsl-region-body"> + + <fo:block font-size="14pt"> + <fo:table> + <fo:table-column column-width="50mm" /> + <fo:table-column column-width="100%"/> + <fo:table-body> + <fo:table-row> + <fo:table-cell> + <fo:block>Vorgangsname</fo:block> + </fo:table-cell> + <fo:table-cell> + <fo:block>Versammlungsanzeige</fo:block> + </fo:table-cell> + </fo:table-row> + + <fo:table-row> + <fo:table-cell> + <fo:block>Vorgangsnummer</fo:block> + </fo:table-cell> + <fo:table-cell> + <fo:block>12345</fo:block> + </fo:table-cell> + </fo:table-row> + </fo:table-body> + </fo:table> + </fo:block> + + <fo:block-container font-size="11pt" margin-top="1cm"> + <fo:block font-size="14pt">Nachrichten</fo:block> + + <xsl:apply-templates select="nachricht"/> + </fo:block-container> + </fo:flow> + </xsl:template> + + <xsl:template name="nachricht"> + <fo:block>nachricht</fo:block> + </xsl:template> +</xsl:stylesheet> \ No newline at end of file diff --git a/goofy-server/src/main/resources/postfach_nachrichten_template.xsl b/goofy-server/src/main/resources/postfach_nachrichten_template.xsl new file mode 100644 index 0000000000000000000000000000000000000000..c4517419babe8caf02a71fa8e4680d7ab2ab1948 --- /dev/null +++ b/goofy-server/src/main/resources/postfach_nachrichten_template.xsl @@ -0,0 +1,10 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.1"> + + <xsl:template name="functional-template" match="/postfachNachrichtenPdfModel"> + <fo:flow flow-name="xsl-region-body"> + <fo:block> + <xsl:value-of select="postfachNachrichtenPdfModel/vorgangsTyp" /> <xsl:value-of select="postfachNachrichtenPdfModel/vorgangsNummer" /> + </fo:block> + </fo:flow> + </xsl:template> +</xsl:stylesheet> \ No newline at end of file diff --git a/goofy-server/src/test/java/de/itvsh/goofy/GoofyServerApplicationTest.java b/goofy-server/src/test/java/de/itvsh/goofy/GoofyServerApplicationTest.java index 866895e17ae1db2cb667a4b871289df5725f9003..27aaa54bc095e9d9c49ecfe31698ae07a02d445a 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/GoofyServerApplicationTest.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/GoofyServerApplicationTest.java @@ -7,6 +7,6 @@ import org.springframework.boot.test.context.SpringBootTest; class GoofyServerApplicationTest { @Test - void contextLoads() { + void contextLoads() { // NOSONAR } } \ No newline at end of file diff --git a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteServiceTest.java b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteServiceTest.java index 18a1c9dda77ff36ce45a22d7d65ee2b5e3f497bb..a15b2b4da9c50db348361a30ce8c5912db427f87 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteServiceTest.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/BinaryFileRemoteServiceTest.java @@ -5,9 +5,6 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -81,82 +78,30 @@ class BinaryFileRemoteServiceTest { @BeforeEach void initMocks() { when(serviceAsyncStub.uploadBinaryFileAsStream(any())).thenReturn(requestObserver); - doNothing().when(remoteService).sendBinaryFile(any(), any()); } @Test void shouldCreateStreamObserver() { callService(); - verify(remoteService).createUploadBinaryFileObserver(ArgumentMatchers.<CompletableFuture<FileId>>any()); + verify(remoteService).createUploadBinaryFileObserver(ArgumentMatchers.<CompletableFuture<FileId>>any(), any()); + verify(remoteService).buildMetaDataRequest(uploadBinaryFile); } @Test void shouldCallUploadBinaryFileOnServiceAsyncStub() { - doReturn(responseObserver).when(remoteService).createUploadBinaryFileObserver(any()); + doReturn(responseObserver).when(remoteService).createUploadBinaryFileObserver(any(), any()); callService(); verify(serviceAsyncStub).uploadBinaryFileAsStream(responseObserver); } - @Test - void shouldCallSendBinaryFile() { - callService(); - - verify(remoteService).sendBinaryFile(requestObserver, uploadBinaryFile); - } - private void callService() { remoteService.uploadFile(uploadBinaryFile); } } - @Nested - class TestSendBinaryFile { - - @Mock - private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver; - private UploadBinaryFileRequest uploadBinaryFile = UploadBinaryFileTestFactory.create(); - - @BeforeEach - void mockSendAsChunks() { - doNothing().when(remoteService).sendAsChunks(any(), any()); - } - - @Test - void shouldBuildMetaData() { - callService(); - - verify(remoteService).buildMetaDataRequest(uploadBinaryFile); - } - - @Test - void shouldCallNextWithMetaData() { - callService(); - - verify(requestObserver).onNext(any(GrpcUploadBinaryFileRequest.class)); - } - - @Test - void shouldSendChunks() { - callService(); - - verify(remoteService).sendAsChunks(requestObserver, UploadBinaryFileTestFactory.UPLOAD_STREAM); - } - - @Test - void shouldCallOnComplete() { - callService(); - - verify(requestObserver).onCompleted(); - } - - private void callService() { - remoteService.sendBinaryFile(requestObserver, uploadBinaryFile); - } - } - @Nested class TestBuildMetaDataRequest { @@ -208,119 +153,6 @@ class BinaryFileRemoteServiceTest { } } - @Nested - class TestSendAsChunks { - - @Mock - private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver; - @Mock - private BufferedInputStream bufferedUploadStream; - - @BeforeEach - void mock() { - doReturn(bufferedUploadStream).when(remoteService).getAsBufferedStream(any(InputStream.class)); - } - - @Test - void shouldCallHasDataToRead() throws IOException { - callService(); - - verify(remoteService).hasDataToRead(bufferedUploadStream); - } - - @Test - void shouldSendNextChunk() throws IOException { - doNothing().when(remoteService).sendNextChunk(any(), any()); - doReturn(true, false).when(remoteService).hasDataToRead(any()); - - callService(); - - verify(remoteService, atLeastOnce()).sendNextChunk(requestObserver, bufferedUploadStream); - } - - @Test - void shouldThrowException() throws IOException { - doThrow(IOException.class).when(remoteService).hasDataToRead(any()); - - assertThrows(TechnicalException.class, () -> callService()); - } - - private void callService() { - remoteService.sendAsChunks(requestObserver, UploadBinaryFileTestFactory.UPLOAD_STREAM); - } - } - - @Nested - class TestSendNextChunk { - - @Mock - private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver; - @Mock - private BufferedInputStream bufferedUploadStream; - - @Test - void shouldSendNextChunk() { - doNothing().when(remoteService).sendChunk(any(), any()); - when(requestObserver.isReady()).thenReturn(true); - - callService(); - - verify(remoteService).sendChunk(requestObserver, bufferedUploadStream); - } - - @Test - void shouldNotSendNextChunkWhenNotReady() { - when(requestObserver.isReady()).thenReturn(false); - - callService(); - - verify(remoteService, never()).sendChunk(requestObserver, bufferedUploadStream); - } - - private void callService() { - remoteService.sendNextChunk(requestObserver, bufferedUploadStream); - } - } - - @Nested - class TestSendChunk { - - @Mock - private BufferedInputStream uploadStream; - @Mock - private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver; - private final byte[] chunkPart = BinaryFileTestFactory.DATA; - - @Test - void shouldBuildChunk() throws IOException { - doReturn(chunkPart).when(uploadStream).readNBytes(anyInt()); - - callService(); - - verify(remoteService).buildChunkRequest(chunkPart); - } - - @Test - void shouldCallOnNext() throws IOException { - doReturn(chunkPart).when(uploadStream).readNBytes(anyInt()); - - callService(); - - verify(requestObserver).onNext(any(GrpcUploadBinaryFileRequest.class)); - } - - @Test - void shouldThrowException() throws IOException { - doThrow(IOException.class).when(uploadStream).readNBytes(anyInt()); - - assertThrows(TechnicalException.class, () -> callService()); - } - - private void callService() { - remoteService.sendChunk(requestObserver, uploadStream); - } - } - @Nested class TestBuildChunkRequest { diff --git a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/ChunkedFileSenderTest.java b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/ChunkedFileSenderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9fd462cb12bcbf9f9ea36582ce2488e282798d25 --- /dev/null +++ b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/ChunkedFileSenderTest.java @@ -0,0 +1,101 @@ +package de.itvsh.goofy.common.binaryfile; + +import de.itvsh.kop.common.errorhandling.TechnicalException; +import de.itvsh.ozg.pluto.grpc.binaryFile.GrpcUploadBinaryFileRequest; +import io.grpc.stub.CallStreamObserver; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +class ChunkedFileSenderTest { + + private CallStreamObserver<GrpcUploadBinaryFileRequest> requestObserver = mock(CallStreamObserver.class); + private InputStream uploadStream = mock(InputStream.class); + + private int chunkSize = BinaryFileTestFactory.DATA.length; + private GrpcUploadBinaryFileRequest uploadBinaryFileRequest = GrpcUploadBinaryFileRequestTestFactory.createDataRequest(); + private Function<byte[], GrpcUploadBinaryFileRequest> buildUploadBinaryFileRequest = when(mock(Function.class).apply(any())).thenReturn(uploadBinaryFileRequest).getMock(); + private GrpcUploadBinaryFileRequest metadataRequest = GrpcUploadBinaryFileRequestTestFactory.createMetadataRequest(); + + private ChunkedFileSender<GrpcUploadBinaryFileRequest> streamer = new ChunkedFileSender<>(uploadStream, chunkSize, buildUploadBinaryFileRequest, metadataRequest); + + @Nested + class TestSendBinaryFile { + + @Test + void shouldNotSendWhenDone() { + ReflectionTestUtils.setField(streamer, "hasUploadFile", new AtomicBoolean(false)); + + streamer.sendChunkTo(requestObserver); + + verify(requestObserver, never()).onNext(any()); + } + + @SneakyThrows + @Test + void shouldCloseUploadStream() { + when(uploadStream.readNBytes(anyInt())).thenReturn(new byte[]{}); + + streamer.sendChunkTo(requestObserver); + + verify(uploadStream).close(); + } + + @SneakyThrows + @Test + void shouldCallOnCompleted() { + when(uploadStream.readNBytes(anyInt())).thenReturn(new byte[]{}); + + streamer.sendChunkTo(requestObserver); + + verify(requestObserver).onCompleted(); + } + + @SneakyThrows + @Test + void shouldCallOnNext(){ + when(uploadStream.readNBytes(anyInt())).thenReturn(BinaryFileTestFactory.DATA); + + streamer.sendChunkTo(requestObserver); + + verify(requestObserver).onNext(uploadBinaryFileRequest); + } + + @SneakyThrows + @Test + void shouldThrowException() { + doThrow(IOException.class).when(uploadStream).readNBytes(anyInt()); + + assertThrows(TechnicalException.class, () -> streamer.sendChunkTo(requestObserver)); + } + + @SneakyThrows + @Test + void shouldBuildRequest() { + when(uploadStream.readNBytes(anyInt())).thenReturn(BinaryFileTestFactory.DATA); + + streamer.sendChunkTo(requestObserver); + + verify(buildUploadBinaryFileRequest).apply(BinaryFileTestFactory.DATA); + } + + @SneakyThrows + @Test + void shouldSendMetadata() { + when(uploadStream.readNBytes(anyInt())).thenReturn(BinaryFileTestFactory.DATA); + + streamer.sendChunkTo(requestObserver); + + verify(requestObserver).onNext(metadataRequest); + } + } +} \ No newline at end of file diff --git a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/GrpcUploadBinaryFileMetaDataTestFactory.java b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/GrpcUploadBinaryFileMetaDataTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..f393e5880fd7bb6d87fe8ed969f871cc88edcc63 --- /dev/null +++ b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/GrpcUploadBinaryFileMetaDataTestFactory.java @@ -0,0 +1,20 @@ +package de.itvsh.goofy.common.binaryfile; + +import de.itvsh.goofy.common.file.OzgFileTestFactory; +import de.itvsh.ozg.pluto.grpc.binaryFile.GrpcUploadBinaryFileMetaData; + +public class GrpcUploadBinaryFileMetaDataTestFactory { + + public static GrpcUploadBinaryFileMetaData create() { + return createBuilder().build(); + } + + private static GrpcUploadBinaryFileMetaData.Builder createBuilder() { + return GrpcUploadBinaryFileMetaData.newBuilder() + .setVorgangId(UploadBinaryFileTestFactory.VORGANG_ID) + .setField(UploadBinaryFileTestFactory.FIELD) + .setContentType(OzgFileTestFactory.CONTENT_TYPE) + .setSize(OzgFileTestFactory.SIZE) + .setFileName(OzgFileTestFactory.NAME); + } +} diff --git a/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/GrpcUploadBinaryFileRequestTestFactory.java b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/GrpcUploadBinaryFileRequestTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..6bac8903ba9d15f428626dd8ab67450857126e93 --- /dev/null +++ b/goofy-server/src/test/java/de/itvsh/goofy/common/binaryfile/GrpcUploadBinaryFileRequestTestFactory.java @@ -0,0 +1,20 @@ +package de.itvsh.goofy.common.binaryfile; + +import com.google.protobuf.ByteString; +import de.itvsh.ozg.pluto.grpc.binaryFile.GrpcUploadBinaryFileRequest; +import de.itvsh.ozg.pluto.grpc.binaryFile.GrpcUploadBinaryFileRequest.Builder; + +public class GrpcUploadBinaryFileRequestTestFactory { + + public static GrpcUploadBinaryFileRequest createDataRequest() { + return createBuilder().setFileContent(ByteString.copyFrom(BinaryFileTestFactory.DATA)).build(); + } + + public static GrpcUploadBinaryFileRequest createMetadataRequest() { + return createBuilder().setMetadata(GrpcUploadBinaryFileMetaDataTestFactory.create()).build(); + } + + public static Builder createBuilder() { + return GrpcUploadBinaryFileRequest.newBuilder(); + } +} diff --git a/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailControllerTest.java b/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailControllerTest.java index dde850aa32d006dfc55c10ed003d3524249058bf..4423d22786638e5c079cdb650624b02fb7e463e6 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailControllerTest.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailControllerTest.java @@ -6,20 +6,27 @@ import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import java.io.OutputStream; +import java.util.Date; import java.util.Optional; import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import de.itvsh.goofy.common.binaryfile.BinaryFileController; import de.itvsh.goofy.vorgang.Antragsteller; @@ -31,6 +38,7 @@ import de.itvsh.goofy.vorgang.VorgangWithEingangTestFactory; class PostfachMailControllerTest { + @Spy @InjectMocks // NOSONAR private PostfachMailController controller; @Mock @@ -49,8 +57,9 @@ class PostfachMailControllerTest { mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); } + @DisplayName("Get all") @Nested - class TestPostfachMailGetAll { + class TestGetAll { @BeforeEach void mockVorgangController() { @@ -79,15 +88,73 @@ class PostfachMailControllerTest { ArgumentMatchers.<Optional<String>>any()); } - void doRequest() throws Exception { + private void doRequest() throws Exception { mockMvc.perform(get(PostfachMailController.PATH + "?" + PostfachMailController.PARAM_VORGANG_ID + "=" + VorgangHeaderTestFactory.ID)) .andExpect(status().isOk()); } } + @Disabled("FIXME OZG-2966") + @DisplayName("Get all as pdf") + @Nested + class TestGetAllAsPdf { + + @Mock + private StreamingResponseBody streamingBody; + private VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + + @BeforeEach + void mockService() { + when(vorgangController.getVorgang(anyString())).thenReturn(vorgang); + } + + @Test + void shouldGetVorgang() throws Exception { + doRequest(); + + verify(vorgangController).getVorgang(VorgangHeaderTestFactory.ID); + } + + @Test + void shouldCallService() throws Exception { + doRequest(); + + verify(service).getAllAsPdf(eq(vorgang), any(OutputStream.class)); + } + + @Test + void shouldBuildResponseEntity() throws Exception { + doReturn(streamingBody).when(controller).createDownloadStreamingBody(vorgang); + + doRequest(); + + verify(controller).buildResponseEntity(vorgang, streamingBody); + } + + @Test + void shouldReturnResponse() throws Exception { + doReturn(streamingBody).when(controller).createDownloadStreamingBody(vorgang); + + doRequest() + .andExpect(header().string(HttpHeaders.CONTENT_DISPOSITION, + String.format(PostfachMailController.PDF_NAME_TEMPLATE, VorgangHeaderTestFactory.NUMMER, + PostfachMailController.PDF_NAME_DATE_FORMATTER.format(new Date())))) + .andExpect(content().contentType(MediaType.APPLICATION_PDF)); + } + + private ResultActions doRequest() throws Exception { + return mockMvc + .perform(get(PostfachMailController.PATH + "?" + PostfachMailController.PARAM_VORGANG_ID + "=" + VorgangHeaderTestFactory.ID) + .accept(MediaType.APPLICATION_PDF_VALUE)) + .andExpect(status().isOk()); + } + } + + @DisplayName("Get postfachId") @Nested class TestGetPostfachId { + @DisplayName("without antragsteller") @Nested class TestWithoutAntragsteller { @@ -103,6 +170,7 @@ class PostfachMailControllerTest { } } + @DisplayName("with empty postfachId") @Nested class TestWithEmptyPostfachId { @@ -124,6 +192,7 @@ class PostfachMailControllerTest { } } + @DisplayName("Find postfach attachments") @Nested class TestFindPostfachAttachments { @@ -156,6 +225,7 @@ class PostfachMailControllerTest { } } + @DisplayName("Is postfach configured") @Nested class TestIsPostfachConfigured { diff --git a/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailPdfServiceTest.java b/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailPdfServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..70ed8e9febad707b40e49eee8d3d5177f75f692f --- /dev/null +++ b/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailPdfServiceTest.java @@ -0,0 +1,120 @@ +package de.itvsh.goofy.postfach; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.core.io.Resource; +import org.springframework.util.ReflectionUtils; + +import de.itvsh.goofy.common.errorhandling.FunctionalException; +import de.itvsh.goofy.vorgang.VorgangWithEingangTestFactory; +import de.itvsh.kop.common.pdf.PdfService; +import lombok.SneakyThrows; + +class PostfachMailPdfServiceTest { + + @Spy + @InjectMocks + private PostfachMailPdfService service; + @Mock + private PdfService pdfService; + + @DisplayName("Get all as pdf") + @Nested + class TestGetAllAsPdf { + + @Mock + private OutputStream output; + + @DisplayName("on getting template") + @Nested + class TestGetTemplate { + + @Mock + private Resource pdfTemplate; + + @BeforeEach + void mockPdfTemplate() { + var field = ReflectionUtils.findField(PostfachMailPdfService.class, "pdfTemplate"); + field.setAccessible(true); + ReflectionUtils.setField(field, service, pdfTemplate); + } + + @SneakyThrows + @Test + void shouldGetInputStreamFromResource() { + when(pdfTemplate.getInputStream()).thenReturn(InputStream.nullInputStream()); + + service.getTemplate(); + + verify(pdfTemplate).getInputStream(); + } + + @SneakyThrows + @Test + void shouldReturnIfExists() { + var inputStream = InputStream.nullInputStream(); + when(pdfTemplate.getInputStream()).thenReturn(inputStream); + + var templateInputStream = service.getTemplate(); + + assertThat(templateInputStream).isEqualTo(inputStream); + } + + @SneakyThrows + @Test + void shouldThrowExceptionIfMissing() { + when(pdfTemplate.getInputStream()).thenThrow(IOException.class); + + assertThrows(FunctionalException.class, () -> service.getTemplate()); + } + } + + @DisplayName("build model") + @Nested + class TestBuildModel { + + @Test + void shouldContainsVorgangsNummer() { + var model = buildModel(); + + // assertThat(model.getVorgangsNummer()).isEqualTo(VorgangHeaderTestFactory.NUMMER); + assertThat(model.getVorgangsNummer()).isEqualTo("VorgangsNummerTestValue"); + } + + @Test + void shouldContainsVorgangsTyp() { + var model = buildModel(); + + // assertThat(model.getVorgangsTyp()).isEqualTo(VorgangHeaderTestFactory.NAME); + assertThat(model.getVorgangsTyp()).isEqualTo("VorgangsTypTestValue"); + } + + private PostfachNachrichtenPdfModel buildModel() { + return service.buildModel(VorgangWithEingangTestFactory.create()); + } + } + + @Test + void shouldCallPdfService() { + doReturn(InputStream.nullInputStream()).when(service).getTemplate(); + + service.getAllAsPdf(VorgangWithEingangTestFactory.create(), output); + + verify(pdfService).createPdf(any(InputStream.class), any(OutputStream.class), any(PostfachNachrichtenPdfModel.class)); + } + } +} \ No newline at end of file diff --git a/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailServiceTest.java b/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailServiceTest.java index 4e14e58beb7119298c477c241417a81cf375a985..54198f4649c50df4264c9e03967a3663c99e4977 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailServiceTest.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/postfach/PostfachMailServiceTest.java @@ -1,9 +1,11 @@ package de.itvsh.goofy.postfach; +import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; +import java.io.OutputStream; import java.util.Optional; import org.junit.jupiter.api.BeforeEach; @@ -13,19 +15,22 @@ import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.assertj.core.api.Assertions.*; - import de.itvsh.goofy.common.command.CommandTestFactory; import de.itvsh.goofy.common.errorhandling.ResourceNotFoundException; import de.itvsh.goofy.vorgang.VorgangHeaderTestFactory; +import de.itvsh.goofy.vorgang.VorgangWithEingang; +import de.itvsh.goofy.vorgang.VorgangWithEingangTestFactory; class PostfachMailServiceTest { @InjectMocks // NOSONAR private PostfachMailService service; @Mock + private PostfachMailPdfService pdfService; + @Mock private PostfachMailRemoteService remoteService; + @DisplayName("Get all") @Nested class TestGetAll { @@ -37,6 +42,7 @@ class PostfachMailServiceTest { } } + @DisplayName("Find by id") @Nested class TestFindById { @@ -69,6 +75,7 @@ class PostfachMailServiceTest { } } + @DisplayName("Resend postfach mail") @Nested class TestResendPostfachMail { @@ -80,19 +87,19 @@ class PostfachMailServiceTest { } } + @DisplayName("Is postfach configured") @Nested class TestIsPostfachConfigured { @Test - void shouldCallRemoteService() { + void shouldCallRemoteServiceOnMissingProperty() { service.isPostfachConfigured(); verify(remoteService).isPostfachConfigured(); } - @DisplayName("if property is already set, no remoteservice call should be done") @Test - void shouldNotCallRemoteService() throws Exception { + void shouldNotCallRemoteServiceOnExistingProperty() throws Exception { setIsConfigured(); service.isPostfachConfigured(); @@ -106,4 +113,21 @@ class PostfachMailServiceTest { isPostfachConfigured.set(service, true); } } + + @DisplayName("Get all as pdf") + @Nested + class TestGetAllAsPdf { + + @Mock + private OutputStream outputStream; + + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + + @Test + void shouldCallPdfService() { + service.getAllAsPdf(vorgang, outputStream); + + verify(pdfService).getAllAsPdf(vorgang, outputStream); + } + } } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7d7e2bc18e7acd6d87a9149b7b061cf3f54d01d5..ce17122232f4c322c304d199cb1bbcaa0915c6a8 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ <parent> <groupId>de.itvsh.kop.common</groupId> <artifactId>kop-common-parent</artifactId> - <version>1.2.1</version> + <version>1.3.0-SNAPSHOT</version> </parent> <modules> @@ -26,6 +26,7 @@ <pluto.version>1.1.0-SNAPSHOT</pluto.version> <jsoup.version>1.15.1</jsoup.version> + <kop-common-pdf.version>1.3.0-SNAPSHOT</kop-common-pdf.version> </properties> <dependencyManagement> @@ -40,6 +41,11 @@ <artifactId>pluto-utils</artifactId> <version>${pluto.version}</version> </dependency> + <dependency> + <groupId>de.itvsh.kop.common</groupId> + <artifactId>kop-common-pdf</artifactId> + <version>${kop-common-pdf.version}</version> + </dependency> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId>