feature/use-case-acceptance-tests-2 (#117)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: #117 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
parent
3b94f117fb
commit
63af33d003
36
Jenkinsfile
vendored
36
Jenkinsfile
vendored
@ -26,9 +26,35 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage ('Compile & Test') {
|
stage ('Compile') {
|
||||||
steps {
|
steps {
|
||||||
sh './gradlew clean check --no-daemon -x pitest -x dependencyCheckAnalyze'
|
sh './gradlew clean processSpring compileJava compileTestJava --no-daemon'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage ('Tests') {
|
||||||
|
parallel {
|
||||||
|
stage('Unit-/Integration/Acceptance-Tests') {
|
||||||
|
steps {
|
||||||
|
sh './gradlew check --no-daemon -x pitest -x dependencyCheckAnalyze -x importOfficeData -x importHostingAssets'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('Import-Tests') {
|
||||||
|
steps {
|
||||||
|
sh './gradlew importOfficeData importHostingAssets --no-daemon'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage ('Scenario-Tests') {
|
||||||
|
steps {
|
||||||
|
sh './gradlew scenarioTests --no-daemon'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage ('Check') {
|
||||||
|
steps {
|
||||||
|
sh './gradlew check -x pitest -x dependencyCheckAnalyze --no-daemon'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,6 +71,12 @@ pipeline {
|
|||||||
sourcePattern: 'src/main/java'
|
sourcePattern: 'src/main/java'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// archive scenario-test reports in HTML format
|
||||||
|
sh '''
|
||||||
|
./gradlew convertMarkdownToHtml
|
||||||
|
'''
|
||||||
|
archiveArtifacts artifacts: 'doc/scenarios/*.html', allowEmptyArchive: true
|
||||||
|
|
||||||
// cleanup workspace
|
// cleanup workspace
|
||||||
cleanWs()
|
cleanWs()
|
||||||
}
|
}
|
||||||
|
55
build.gradle
55
build.gradle
@ -255,7 +255,7 @@ test {
|
|||||||
'net.hostsharing.hsadminng.**.generated.**',
|
'net.hostsharing.hsadminng.**.generated.**',
|
||||||
]
|
]
|
||||||
useJUnitPlatform {
|
useJUnitPlatform {
|
||||||
excludeTags 'import'
|
excludeTags 'importOfficeData', 'importHostingData', 'scenarioTest'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jacocoTestReport {
|
jacocoTestReport {
|
||||||
@ -344,6 +344,17 @@ tasks.register('importHostingAssets', Test) {
|
|||||||
mustRunAfter spotlessJava
|
mustRunAfter spotlessJava
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register('scenarioTests', Test) {
|
||||||
|
useJUnitPlatform {
|
||||||
|
includeTags 'scenarioTest'
|
||||||
|
}
|
||||||
|
|
||||||
|
group 'verification'
|
||||||
|
description 'run the import jobs as tests'
|
||||||
|
|
||||||
|
mustRunAfter spotlessJava
|
||||||
|
}
|
||||||
|
|
||||||
// pitest mutation testing
|
// pitest mutation testing
|
||||||
pitest {
|
pitest {
|
||||||
targetClasses = ['net.hostsharing.hsadminng.**']
|
targetClasses = ['net.hostsharing.hsadminng.**']
|
||||||
@ -391,3 +402,45 @@ tasks.named("dependencyUpdates").configure {
|
|||||||
isNonStable(it.candidate.version)
|
isNonStable(it.candidate.version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Generate HTML from Markdown scenario-test-reports using Pandoc:
|
||||||
|
tasks.register('convertMarkdownToHtml') {
|
||||||
|
description = 'Generates HTML from Markdown scenario-test-reports using Pandoc.'
|
||||||
|
group = 'Conversion'
|
||||||
|
|
||||||
|
// Define the template file and input directory
|
||||||
|
def templateFile = file('doc/scenarios/template.html')
|
||||||
|
|
||||||
|
// Task configuration and execution
|
||||||
|
doFirst {
|
||||||
|
// Check if pandoc is installed
|
||||||
|
try {
|
||||||
|
exec {
|
||||||
|
commandLine 'pandoc', '--version'
|
||||||
|
}
|
||||||
|
} catch (Exception) {
|
||||||
|
throw new GradleException("Pandoc is not installed or not found in the system path.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the template file exists
|
||||||
|
if (!templateFile.exists()) {
|
||||||
|
throw new GradleException("Template file 'doc/scenarios/template.html' not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
// Gather all Markdown files in the current directory
|
||||||
|
fileTree(dir: '.', include: 'doc/scenarios/*.md').each { file ->
|
||||||
|
// Corrected way to create the output file path
|
||||||
|
def outputFile = new File(file.parent, file.name.replaceAll(/\.md$/, '.html'))
|
||||||
|
|
||||||
|
// Execute pandoc for each markdown file
|
||||||
|
exec {
|
||||||
|
commandLine 'pandoc', file.absolutePath, '--template', templateFile.absolutePath, '-o', outputFile.absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
println "Converted ${file.name} to ${outputFile.name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
124
doc/scenarios/template.html
Normal file
124
doc/scenarios/template.html
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html $if(lang)$ lang="$lang$" $endif$>
|
||||||
|
<head>
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="http://css3-mediaqueries-js.googlecode.com/svn/trunk/css3-mediaqueries.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
<meta http-equiv="Content-Style-Type" content="text/css" />
|
||||||
|
|
||||||
|
<!-- <link rel="stylesheet" type="text/css" href="template.css" /> -->
|
||||||
|
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/diversen/pandoc-bootstrap-adaptive-template@959c3622/template.css" />
|
||||||
|
|
||||||
|
<link href="https://vjs.zencdn.net/5.4.4/video-js.css" rel="stylesheet" />
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-2.2.1.min.js"></script>
|
||||||
|
<!-- <script type='text/javascript' src='menu/js/jquery.cookie.js'></script> -->
|
||||||
|
<!-- <script type='text/javascript' src='menu/js/jquery.hoverIntent.minified.js'></script> -->
|
||||||
|
<!-- <script type='text/javascript' src='menu/js/jquery.dcjqaccordion.2.7.min.js'></script> -->
|
||||||
|
|
||||||
|
<!-- <link href="menu/css/skins/blue.css" rel="stylesheet" type="text/css" /> -->
|
||||||
|
<!-- <link href="menu/css/skins/graphite.css" rel="stylesheet" type="text/css" /> -->
|
||||||
|
<!-- <link href="menu/css/skins/grey.css" rel="stylesheet" type="text/css" /> -->
|
||||||
|
|
||||||
|
<!-- <script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <script src="script.js"></script> -->
|
||||||
|
|
||||||
|
<!-- <script src="jquery.sticky-kit.js "></script> -->
|
||||||
|
<script type='text/javascript' src='https://cdn.jsdelivr.net/gh/diversen/pandoc-bootstrap-adaptive-template@959c3622/menu/js/jquery.cookie.js'></script>
|
||||||
|
<script type='text/javascript' src='https://cdn.jsdelivr.net/gh/diversen/pandoc-bootstrap-adaptive-template@959c3622/menu/js/jquery.hoverIntent.minified.js'></script>
|
||||||
|
<script type='text/javascript' src='https://cdn.jsdelivr.net/gh/diversen/pandoc-bootstrap-adaptive-template@959c3622/menu/js/jquery.dcjqaccordion.2.7.min.js'></script>
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/gh/diversen/pandoc-bootstrap-adaptive-template@959c3622/menu/css/skins/blue.css" rel="stylesheet" type="text/css" />
|
||||||
|
<link href="https://cdn.jsdelivr.net/gh/diversen/pandoc-bootstrap-adaptive-template@959c3622/menu/css/skins/graphite.css" rel="stylesheet" type="text/css" />
|
||||||
|
<link href="https://cdn.jsdelivr.net/gh/diversen/pandoc-bootstrap-adaptive-template@959c3622/menu/css/skins/grey.css" rel="stylesheet" type="text/css" />
|
||||||
|
<link href="https://cdn.jsdelivr.net/gh/ryangrose/easy-pandoc-templates@948e28e5/css/elegant_bootstrap.css" rel="stylesheet" type="text/css" />
|
||||||
|
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/gh/diversen/pandoc-bootstrap-adaptive-template@959c3622/script.js"></script>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/gh/diversen/pandoc-bootstrap-adaptive-template@959c3622/jquery.sticky-kit.js"></script>
|
||||||
|
<meta name="generator" content="pandoc" />
|
||||||
|
$for(author-meta)$
|
||||||
|
<meta name="author" content="$author-meta$" />
|
||||||
|
$endfor$
|
||||||
|
$if(date-meta)$
|
||||||
|
<meta name="date" content="$date-meta$" />
|
||||||
|
$endif$
|
||||||
|
<title>$if(title-prefix)$$title-prefix$ - $endif$$pagetitle$</title>
|
||||||
|
<style type="text/css">code{white-space: pre;}</style>
|
||||||
|
$if(quotes)$
|
||||||
|
<style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
|
||||||
|
$endif$
|
||||||
|
$if(highlighting-css)$
|
||||||
|
<style type="text/css">
|
||||||
|
$highlighting-css$
|
||||||
|
</style>
|
||||||
|
$endif$
|
||||||
|
$for(css)$
|
||||||
|
<link rel="stylesheet" href="$css$" $if(html5)$$else$type="text/css" $endif$/>
|
||||||
|
$endfor$
|
||||||
|
$if(math)$
|
||||||
|
$math$
|
||||||
|
$endif$
|
||||||
|
$for(header-includes)$
|
||||||
|
$header-includes$
|
||||||
|
$endfor$
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
$if(title)$
|
||||||
|
<div class="navbar navbar-static-top">
|
||||||
|
<div class="navbar-inner">
|
||||||
|
<div class="container">
|
||||||
|
<span class="doc-title">$title$</span>
|
||||||
|
<ul class="nav pull-right doc-info">
|
||||||
|
$for(author)$
|
||||||
|
<li><p class="navbar-text">$author$</p></li>
|
||||||
|
$endfor$
|
||||||
|
$if(date)$
|
||||||
|
<li><p class="navbar-text">$date$</p></li>
|
||||||
|
$endif$
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
$endif$
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
$if(toc)$
|
||||||
|
<div id="$idprefix$TOC" class="span3">
|
||||||
|
<div class="well toc">
|
||||||
|
|
||||||
|
$toc$
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
$endif$
|
||||||
|
<div class="span$if(toc)$9$else$12$endif$">
|
||||||
|
|
||||||
|
$if(abstract)$
|
||||||
|
<H1>$abstract-title$</H1>
|
||||||
|
$abstract$
|
||||||
|
$endif$
|
||||||
|
|
||||||
|
$for(include-before)$
|
||||||
|
$include-before$
|
||||||
|
$endfor$
|
||||||
|
$body$
|
||||||
|
$for(include-after)$
|
||||||
|
$include-after$
|
||||||
|
$endfor$
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="https://vjs.zencdn.net/5.4.4/video.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,10 +1,6 @@
|
|||||||
FROM eclipse-temurin:21-jdk
|
FROM eclipse-temurin:21-jdk
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y bind9-utils && \
|
apt-get install -y bind9-utils pandoc && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
||||||
# RUN mkdir /opt/app
|
|
||||||
# COPY japp.jar /opt
|
|
||||||
# CMD ["java", "-jar", "/opt/app/japp.jar"]
|
|
||||||
|
@ -7,7 +7,7 @@ get:
|
|||||||
parameters:
|
parameters:
|
||||||
- $ref: 'auth.yaml#/components/parameters/currentSubject'
|
- $ref: 'auth.yaml#/components/parameters/currentSubject'
|
||||||
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
||||||
- name: name
|
- name: iban
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.scenarios;
|
package net.hostsharing.hsadminng.hs.office.scenarios;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.HsadminNgApplication;
|
import net.hostsharing.hsadminng.HsadminNgApplication;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.contact.AddPhoneNumberToContactData;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.contact.AmendContactData;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.contact.RemovePhoneNumberFromContactData;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.contact.ReplaceContactData;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateExternalDebitorForPartner;
|
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateExternalDebitorForPartner;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSelfDebitorForPartner;
|
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSelfDebitorForPartner;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSepaMandateForDebitor;
|
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.CreateSepaMandateForDebitor;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.DeleteSepaMandateForDebitor;
|
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.FinallyDeleteSepaMandateForDebitor;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.DontDeleteDefaultDebitor;
|
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.DontDeleteDefaultDebitor;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.InvalidateSepaMandateForDebitor;
|
import net.hostsharing.hsadminng.hs.office.scenarios.debitor.InvalidateSepaMandateForDebitor;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.membership.CreateMembership;
|
import net.hostsharing.hsadminng.hs.office.scenarios.membership.CreateMembership;
|
||||||
@ -43,14 +47,39 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(1010)
|
@Order(1010)
|
||||||
@Produces(explicitly = "Partner: Test AG", implicitly = {"Person: Test AG", "Contact: Test AG - Board of Directors"})
|
@Produces(explicitly = "Partner: Test AG", implicitly = {"Person: Test AG", "Contact: Test AG - Hamburg"})
|
||||||
void shouldCreatePartner() {
|
void shouldCreateLegalPersonAsPartner() {
|
||||||
new CreatePartner(this)
|
new CreatePartner(this)
|
||||||
.given("partnerNumber", 31010)
|
.given("partnerNumber", 31010)
|
||||||
.given("personType", "LEGAL_PERSON")
|
.given("personType", "LEGAL_PERSON")
|
||||||
.given("tradeName", "Test AG")
|
.given("tradeName", "Test AG")
|
||||||
.given("contactCaption", "Test AG - Board of Directors")
|
.given("contactCaption", "Test AG - Hamburg")
|
||||||
.given("emailAddress", "board-of-directors@test-ag.example.org")
|
.given("postalAddress", """
|
||||||
|
Shanghai-Allee 1
|
||||||
|
20123 Hamburg
|
||||||
|
""")
|
||||||
|
.given("officePhoneNumber", "+49 40 654321-0")
|
||||||
|
.given("emailAddress", "hamburg@test-ag.example.org")
|
||||||
|
.doRun()
|
||||||
|
.keep();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1011)
|
||||||
|
@Produces(explicitly = "Partner: Michelle Matthieu", implicitly = {"Person: Michelle Matthieu", "Contact: Michelle Matthieu"})
|
||||||
|
void shouldCreateNaturalPersonAsPartner() {
|
||||||
|
new CreatePartner(this)
|
||||||
|
.given("partnerNumber", 31011)
|
||||||
|
.given("personType", "NATURAL_PERSON")
|
||||||
|
.given("givenName", "Michelle")
|
||||||
|
.given("familyName", "Matthieu")
|
||||||
|
.given("contactCaption", "Michelle Matthieu")
|
||||||
|
.given("postalAddress", """
|
||||||
|
An der Wandse 34
|
||||||
|
22123 Hamburg
|
||||||
|
""")
|
||||||
|
.given("officePhoneNumber", "+49 40 123456")
|
||||||
|
.given("emailAddress", "michelle.matthieu@example.org")
|
||||||
.doRun()
|
.doRun()
|
||||||
.keep();
|
.keep();
|
||||||
}
|
}
|
||||||
@ -106,6 +135,53 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
|||||||
.doRun();
|
.doRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1100)
|
||||||
|
@Requires("Partner: Michelle Matthieu")
|
||||||
|
void shouldAmendContactData() {
|
||||||
|
new AmendContactData(this)
|
||||||
|
.given("partnerName", "Matthieu")
|
||||||
|
.given("newEmailAddress", "michelle@matthieu.example.org")
|
||||||
|
.doRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1101)
|
||||||
|
@Requires("Partner: Michelle Matthieu")
|
||||||
|
void shouldAddPhoneNumberToContactData() {
|
||||||
|
new AddPhoneNumberToContactData(this)
|
||||||
|
.given("partnerName", "Matthieu")
|
||||||
|
.given("phoneNumberKeyToAdd", "mobile")
|
||||||
|
.given("phoneNumberToAdd", "+49 152 1234567")
|
||||||
|
.doRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1102)
|
||||||
|
@Requires("Partner: Michelle Matthieu")
|
||||||
|
void shouldRemovePhoneNumberFromContactData() {
|
||||||
|
new RemovePhoneNumberFromContactData(this)
|
||||||
|
.given("partnerName", "Matthieu")
|
||||||
|
.given("phoneNumberKeyToRemove", "office")
|
||||||
|
.doRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1103)
|
||||||
|
@Requires("Partner: Test AG")
|
||||||
|
void shouldReplaceContactData() {
|
||||||
|
new ReplaceContactData(this)
|
||||||
|
.given("partnerName", "Test AG")
|
||||||
|
.given("newContactCaption", "Test AG - Norden")
|
||||||
|
.given("newPostalAddress", """
|
||||||
|
Am Hafen 11
|
||||||
|
26506 Norden
|
||||||
|
""")
|
||||||
|
.given("newOfficePhoneNumber", "+49 4931 654321-0")
|
||||||
|
.given("newEmailAddress", "norden@test-ag.example.org")
|
||||||
|
.doRun();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(2010)
|
@Order(2010)
|
||||||
@Requires("Partner: Test AG")
|
@Requires("Partner: Test AG")
|
||||||
@ -173,10 +249,18 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
|||||||
@Produces("SEPA-Mandate: Test AG")
|
@Produces("SEPA-Mandate: Test AG")
|
||||||
void shouldCreateSepaMandateForDebitor() {
|
void shouldCreateSepaMandateForDebitor() {
|
||||||
new CreateSepaMandateForDebitor(this)
|
new CreateSepaMandateForDebitor(this)
|
||||||
.given("debitor", "Test AG")
|
// existing debitor
|
||||||
.given("memberNumberSuffix", "00")
|
.given("debitorNumber", "3101000")
|
||||||
.given("validFrom", "2024-10-15")
|
|
||||||
.given("membershipFeeBillable", "true")
|
// new sepa-mandate
|
||||||
|
.given("mandateReference", "Test AG - main debitor")
|
||||||
|
.given("mandateAgreement", "2022-10-12")
|
||||||
|
.given("mandateValidFrom", "2024-10-15")
|
||||||
|
|
||||||
|
// new bank-account
|
||||||
|
.given("bankAccountHolder", "Test AG - debit bank account")
|
||||||
|
.given("bankAccountIBAN", "DE02701500000000594937")
|
||||||
|
.given("bankAccountBIC", "SSKMDEMM")
|
||||||
.doRun()
|
.doRun()
|
||||||
.keep();
|
.keep();
|
||||||
}
|
}
|
||||||
@ -186,17 +270,17 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
|||||||
@Requires("SEPA-Mandate: Test AG")
|
@Requires("SEPA-Mandate: Test AG")
|
||||||
void shouldInvalidateSepaMandateForDebitor() {
|
void shouldInvalidateSepaMandateForDebitor() {
|
||||||
new InvalidateSepaMandateForDebitor(this)
|
new InvalidateSepaMandateForDebitor(this)
|
||||||
.given("sepaMandateUuid", "%{SEPA-Mandate: Test AG}")
|
.given("bankAccountIBAN", "DE02701500000000594937")
|
||||||
.given("validUntil", "2025-09-30")
|
.given("mandateValidUntil", "2025-09-30")
|
||||||
.doRun();
|
.doRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(3109)
|
@Order(3109)
|
||||||
@Requires("SEPA-Mandate: Test AG")
|
@Requires("SEPA-Mandate: Test AG")
|
||||||
void shouldDeleteSepaMandateForDebitor() {
|
void shouldFinallyDeleteSepaMandateForDebitor() {
|
||||||
new DeleteSepaMandateForDebitor(this)
|
new FinallyDeleteSepaMandateForDebitor(this)
|
||||||
.given("sepaMandateUuid", "%{SEPA-Mandate: Test AG}")
|
.given("bankAccountIBAN", "DE02701500000000594937")
|
||||||
.doRun();
|
.doRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.UseCase.HttpResponse;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class PathAssertion {
|
||||||
|
|
||||||
|
private final String path;
|
||||||
|
|
||||||
|
public PathAssertion(final String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
public Consumer<UseCase.HttpResponse> contains(final String resolvableValue) {
|
||||||
|
return response -> response.path(path).contains(ScenarioTest.resolve(resolvableValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Consumer<HttpResponse> doesNotExist() {
|
||||||
|
return response -> response.path(path).isNull(); // here, null Optional means key not found in JSON
|
||||||
|
}
|
||||||
|
}
|
@ -63,4 +63,34 @@ Here, use-cases can be re-used, usually with different data.
|
|||||||
|
|
||||||
### The Use-Case Itself
|
### The Use-Case Itself
|
||||||
|
|
||||||
The use-case
|
The use-case is implemented by the `run()`-method which contains HTTP-calls.
|
||||||
|
|
||||||
|
Each HTTP-call is wrapped into either `obtain(...)` to keep the result in a placeholder variable,
|
||||||
|
the variable name is also used as a title.
|
||||||
|
Or it's wrapped into a `withTitle(...)` to assign a title.
|
||||||
|
|
||||||
|
The HTTP-call is followed by some assertions, e.g. the HTTP status and JSON-path-expression-matchers.
|
||||||
|
|
||||||
|
Use `${...}` for placeholders which need to be replaced with JSON quotes
|
||||||
|
(e.g. strings are quoted, numbers are not),
|
||||||
|
`%{...}` for placeholders which need to be rendered raw
|
||||||
|
and `&{...}` for placeholders which need to get URI-encoded.
|
||||||
|
|
||||||
|
If `???` is added before the closing brace, the property is optional.
|
||||||
|
This means, if it's not available in the properties, `null` is used.
|
||||||
|
|
||||||
|
Properties with null-values are removed from the JSON.
|
||||||
|
If you need to keep a null-value, e.g. to delete a property,
|
||||||
|
use `NULL` (all caps) in the template (not the variable value).
|
||||||
|
|
||||||
|
A special syntax is the infix `???`-operator like in: `${%{var1???}???%{var2???}%{var3???}}`.
|
||||||
|
In this case the first non-null value is used.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### The Use-Case Verification
|
||||||
|
|
||||||
|
The verification-step is implemented by the `verify()`-method which usually contains a HTTP-HTTP-call.
|
||||||
|
|
||||||
|
It can also contain a JSON-path verification to check if a certain value is in the result.
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import org.junit.jupiter.api.BeforeEach;
|
|||||||
import org.junit.jupiter.api.TestInfo;
|
import org.junit.jupiter.api.TestInfo;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.web.server.LocalServerPort;
|
import org.springframework.boot.test.web.server.LocalServerPort;
|
||||||
|
import org.testcontainers.shaded.org.apache.commons.lang3.ObjectUtils;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -35,7 +36,7 @@ public abstract class ScenarioTest extends ContextBasedTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return uuid.toString();
|
return ObjectUtils.toString(uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +69,6 @@ public abstract class ScenarioTest extends ContextBasedTest {
|
|||||||
@AfterEach
|
@AfterEach
|
||||||
void cleanup() { // final TestInfo testInfo
|
void cleanup() { // final TestInfo testInfo
|
||||||
properties.clear();
|
properties.clear();
|
||||||
// FIXME: Delete all aliases as well to force HTTP GET queries in each scenario?
|
|
||||||
testReport.close();
|
testReport.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,57 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.scenarios;
|
package net.hostsharing.hsadminng.hs.office.scenarios;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class TemplateResolver {
|
public class TemplateResolver {
|
||||||
|
|
||||||
|
private final static Pattern pattern = Pattern.compile(",(\\s*})", Pattern.MULTILINE);
|
||||||
|
private static final String IF_NOT_FOUND_SYMBOL = "???";
|
||||||
|
|
||||||
|
enum PlaceholderPrefix {
|
||||||
|
RAW('%') {
|
||||||
|
@Override
|
||||||
|
String convert(final Object value) {
|
||||||
|
return value != null ? value.toString() : "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
JSON_QUOTED('$'){
|
||||||
|
@Override
|
||||||
|
String convert(final Object value) {
|
||||||
|
return jsonQuoted(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
URI_ENCODED('&'){
|
||||||
|
@Override
|
||||||
|
String convert(final Object value) {
|
||||||
|
return value != null ? URLEncoder.encode(value.toString(), StandardCharsets.UTF_8) : "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final char prefixChar;
|
||||||
|
|
||||||
|
PlaceholderPrefix(final char prefixChar) {
|
||||||
|
this.prefixChar = prefixChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean contains(final char givenChar) {
|
||||||
|
return Arrays.stream(values()).anyMatch(p -> p.prefixChar == givenChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PlaceholderPrefix ofPrefixChar(final char givenChar) {
|
||||||
|
return Arrays.stream(values()).filter(p -> p.prefixChar == givenChar).findFirst().orElseThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract String convert(final Object value);
|
||||||
|
}
|
||||||
|
|
||||||
private final String template;
|
private final String template;
|
||||||
private final Map<String, Object> properties;
|
private final Map<String, Object> properties;
|
||||||
private final StringBuilder resolved = new StringBuilder();
|
private final StringBuilder resolved = new StringBuilder();
|
||||||
@ -15,18 +63,41 @@ public class TemplateResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String resolve() {
|
String resolve() {
|
||||||
copy();
|
final var resolved = copy();
|
||||||
return resolved.toString();
|
final var withoutDroppedLines = dropLinesWithNullProperties(resolved);
|
||||||
|
final var result = removeDanglingCommas(withoutDroppedLines);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copy() {
|
private static String removeDanglingCommas(final String withoutDroppedLines) {
|
||||||
|
return pattern.matcher(withoutDroppedLines).replaceAll("$1");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String dropLinesWithNullProperties(final String text) {
|
||||||
|
return Arrays.stream(text.split("\n"))
|
||||||
|
.filter(TemplateResolver::keepLine)
|
||||||
|
.map(TemplateResolver::keptNullValues)
|
||||||
|
.collect(Collectors.joining("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean keepLine(final String line) {
|
||||||
|
final var trimmed = line.trim();
|
||||||
|
return !trimmed.endsWith("null,") && !trimmed.endsWith("null");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String keptNullValues(final String line) {
|
||||||
|
return line.replace(": NULL", ": null");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String copy() {
|
||||||
while (hasMoreChars()) {
|
while (hasMoreChars()) {
|
||||||
if ((currentChar() == '$' || currentChar() == '%') && nextChar() == '{') {
|
if (PlaceholderPrefix.contains(currentChar()) && nextChar() == '{') {
|
||||||
startPlaceholder(currentChar());
|
startPlaceholder(currentChar());
|
||||||
} else {
|
} else {
|
||||||
resolved.append(fetchChar());
|
resolved.append(fetchChar());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return resolved.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasMoreChars() {
|
private boolean hasMoreChars() {
|
||||||
@ -41,7 +112,7 @@ public class TemplateResolver {
|
|||||||
if (currentChar() == '}') {
|
if (currentChar() == '}') {
|
||||||
--nested;
|
--nested;
|
||||||
placeholder.append(fetchChar());
|
placeholder.append(fetchChar());
|
||||||
} else if ((currentChar() == '$' || currentChar() == '%') && nextChar() == '{') {
|
} else if (PlaceholderPrefix.contains (currentChar()) && nextChar() == '{') {
|
||||||
++nested;
|
++nested;
|
||||||
placeholder.append(fetchChar());
|
placeholder.append(fetchChar());
|
||||||
} else {
|
} else {
|
||||||
@ -50,21 +121,34 @@ public class TemplateResolver {
|
|||||||
}
|
}
|
||||||
final var name = new TemplateResolver(placeholder.toString(), properties).resolve();
|
final var name = new TemplateResolver(placeholder.toString(), properties).resolve();
|
||||||
final var value = propVal(name);
|
final var value = propVal(name);
|
||||||
if ( intro == '%') {
|
resolved.append(
|
||||||
resolved.append(value);
|
PlaceholderPrefix.ofPrefixChar(intro).convert(value)
|
||||||
} else {
|
);
|
||||||
resolved.append(optionallyQuoted(value));
|
|
||||||
}
|
|
||||||
skipChar('}');
|
skipChar('}');
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object propVal(final String name) {
|
private Object propVal(final String nameExpression) {
|
||||||
final var val = properties.get(name);
|
if (nameExpression.endsWith(IF_NOT_FOUND_SYMBOL)) {
|
||||||
|
final String pureName = nameExpression.substring(0, nameExpression.length() - IF_NOT_FOUND_SYMBOL.length());
|
||||||
|
return properties.get(pureName);
|
||||||
|
} else if (nameExpression.contains(IF_NOT_FOUND_SYMBOL)) {
|
||||||
|
final var parts = StringUtils.split(nameExpression, IF_NOT_FOUND_SYMBOL);
|
||||||
|
return Arrays.stream(parts).filter(Objects::nonNull).findFirst().orElseGet(() -> {
|
||||||
|
if ( parts[parts.length-1].isEmpty() ) {
|
||||||
|
// => whole expression ends with IF_NOT_FOUND_SYMBOL, thus last null element was optional
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// => last alternative element in expression was null and not optional
|
||||||
|
throw new IllegalStateException("Missing required value in property-chain: " + nameExpression);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
final var val = properties.get(nameExpression);
|
||||||
if (val == null) {
|
if (val == null) {
|
||||||
throw new IllegalStateException("Missing required property: " + name);
|
throw new IllegalStateException("Missing required property: " + nameExpression);
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void skipChar(final char expectedChar) {
|
private void skipChar(final char expectedChar) {
|
||||||
if (currentChar() != expectedChar) {
|
if (currentChar() != expectedChar) {
|
||||||
@ -104,35 +188,13 @@ public class TemplateResolver {
|
|||||||
return template.charAt(position+1);
|
return template.charAt(position+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String optionallyQuoted(final Object value) {
|
private static String jsonQuoted(final Object value) {
|
||||||
return switch (value) {
|
return switch (value) {
|
||||||
|
case null -> null;
|
||||||
case Boolean bool -> bool.toString();
|
case Boolean bool -> bool.toString();
|
||||||
case Number number -> number.toString();
|
case Number number -> number.toString();
|
||||||
case String string -> "\"" + string.replace("\n", "\\n") + "\"";
|
case String string -> "\"" + string.replace("\n", "\\n") + "\"";
|
||||||
default -> "\"" + value + "\"";
|
default -> "\"" + value + "\"";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println(
|
|
||||||
new TemplateResolver("""
|
|
||||||
etwas davor,
|
|
||||||
|
|
||||||
${einfacher Platzhalter},
|
|
||||||
${verschachtelter %{Name}},
|
|
||||||
|
|
||||||
und nochmal ohne Quotes:
|
|
||||||
|
|
||||||
%{einfacher Platzhalter},
|
|
||||||
%{verschachtelter %{Name}},
|
|
||||||
|
|
||||||
etwas danach.
|
|
||||||
""",
|
|
||||||
Map.ofEntries(
|
|
||||||
Map.entry("Name", "placeholder"),
|
|
||||||
Map.entry("einfacher Platzhalter", "simple placeholder"),
|
|
||||||
Map.entry("verschachtelter placeholder", "nested placeholder")
|
|
||||||
)).resolve());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class TemplateResolverUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolveTemplate() {
|
||||||
|
final var resolved = new TemplateResolver("""
|
||||||
|
with optional JSON quotes:
|
||||||
|
|
||||||
|
${boolean},
|
||||||
|
${numeric},
|
||||||
|
${simple placeholder},
|
||||||
|
${nested %{name}},
|
||||||
|
${with-special-chars}
|
||||||
|
|
||||||
|
and without quotes:
|
||||||
|
|
||||||
|
%{boolean},
|
||||||
|
%{numeric},
|
||||||
|
%{simple placeholder},
|
||||||
|
%{nested %{name}},
|
||||||
|
%{with-special-chars}
|
||||||
|
|
||||||
|
and uri-encoded:
|
||||||
|
|
||||||
|
&{boolean},
|
||||||
|
&{numeric},
|
||||||
|
&{simple placeholder},
|
||||||
|
&{nested %{name}},
|
||||||
|
&{with-special-chars}
|
||||||
|
""",
|
||||||
|
Map.ofEntries(
|
||||||
|
Map.entry("name", "placeholder"),
|
||||||
|
Map.entry("boolean", true),
|
||||||
|
Map.entry("numeric", 42),
|
||||||
|
Map.entry("simple placeholder", "einfach"),
|
||||||
|
Map.entry("nested placeholder", "verschachtelt"),
|
||||||
|
Map.entry("with-special-chars", "3&3 AG")
|
||||||
|
)).resolve();
|
||||||
|
|
||||||
|
assertThat(resolved).isEqualTo("""
|
||||||
|
with optional JSON quotes:
|
||||||
|
|
||||||
|
true,
|
||||||
|
42,
|
||||||
|
"einfach",
|
||||||
|
"verschachtelt",
|
||||||
|
"3&3 AG"
|
||||||
|
|
||||||
|
and without quotes:
|
||||||
|
|
||||||
|
true,
|
||||||
|
42,
|
||||||
|
einfach,
|
||||||
|
verschachtelt,
|
||||||
|
3&3 AG
|
||||||
|
|
||||||
|
and uri-encoded:
|
||||||
|
|
||||||
|
true,
|
||||||
|
42,
|
||||||
|
einfach,
|
||||||
|
verschachtelt,
|
||||||
|
3%263+AG
|
||||||
|
""".trim());
|
||||||
|
}
|
||||||
|
}
|
@ -57,8 +57,10 @@ public class TestReport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
if (markdownReport != null) {
|
||||||
markdownReport.close();
|
markdownReport.close();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Object orderNumber(final Method method) {
|
private static Object orderNumber(final Method method) {
|
||||||
return method.getAnnotation(Order.class).value();
|
return method.getAnnotation(Order.class).value();
|
||||||
|
@ -8,6 +8,7 @@ import lombok.Getter;
|
|||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import net.hostsharing.hsadminng.reflection.AnnotationFinder;
|
import net.hostsharing.hsadminng.reflection.AnnotationFinder;
|
||||||
import org.apache.commons.collections4.map.LinkedMap;
|
import org.apache.commons.collections4.map.LinkedMap;
|
||||||
|
import org.assertj.core.api.OptionalAssert;
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -19,17 +20,21 @@ import java.net.http.HttpClient;
|
|||||||
import java.net.http.HttpRequest;
|
import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpRequest.BodyPublishers;
|
import java.net.http.HttpRequest.BodyPublishers;
|
||||||
import java.net.http.HttpResponse.BodyHandlers;
|
import java.net.http.HttpResponse.BodyHandlers;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static java.net.URLEncoder.encode;
|
import static java.net.URLEncoder.encode;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.junit.platform.commons.util.StringUtils.isBlank;
|
import static org.junit.platform.commons.util.StringUtils.isBlank;
|
||||||
import static org.junit.platform.commons.util.StringUtils.isNotBlank;
|
import static org.junit.platform.commons.util.StringUtils.isNotBlank;
|
||||||
|
|
||||||
@ -80,11 +85,16 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return run();
|
final var response = run();
|
||||||
|
verify();
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract HttpResponse run();
|
protected abstract HttpResponse run();
|
||||||
|
|
||||||
|
protected void verify() {
|
||||||
|
}
|
||||||
|
|
||||||
public final UseCase<T> given(final String propName, final Object propValue) {
|
public final UseCase<T> given(final String propName, final Object propValue) {
|
||||||
givenProperties.put(propName, propValue);
|
givenProperties.put(propName, propValue);
|
||||||
ScenarioTest.putProperty(propName, propValue);
|
ScenarioTest.putProperty(propName, propValue);
|
||||||
@ -101,26 +111,30 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
final Function<HttpResponse, String> extractor,
|
final Function<HttpResponse, String> extractor,
|
||||||
final String... extraInfo) {
|
final String... extraInfo) {
|
||||||
withTitle(ScenarioTest.resolve(alias), () -> {
|
withTitle(ScenarioTest.resolve(alias), () -> {
|
||||||
http.get().keep(extractor);
|
final var response = http.get().keep(extractor);
|
||||||
Arrays.stream(extraInfo).forEach(testReport::printPara);
|
Arrays.stream(extraInfo).forEach(testReport::printPara);
|
||||||
|
return response;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void obtain(final String alias, final Supplier<HttpResponse> http, final String... extraInfo) {
|
public final void obtain(final String alias, final Supplier<HttpResponse> http, final String... extraInfo) {
|
||||||
withTitle(ScenarioTest.resolve(alias), () -> {
|
withTitle(ScenarioTest.resolve(alias), () -> {
|
||||||
http.get().keep();
|
final var response = http.get().keep();
|
||||||
Arrays.stream(extraInfo).forEach(testReport::printPara);
|
Arrays.stream(extraInfo).forEach(testReport::printPara);
|
||||||
|
return response;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void withTitle(final String title, final Runnable code) {
|
public HttpResponse withTitle(final String title, final Supplier<HttpResponse> code) {
|
||||||
this.nextTitle = title;
|
this.nextTitle = title;
|
||||||
code.run();
|
final var response = code.get();
|
||||||
this.nextTitle = null;
|
this.nextTitle = null;
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public final HttpResponse httpGet(final String uriPath) {
|
public final HttpResponse httpGet(final String uriPathWithPlaceholders) {
|
||||||
|
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders);
|
||||||
final var request = HttpRequest.newBuilder()
|
final var request = HttpRequest.newBuilder()
|
||||||
.GET()
|
.GET()
|
||||||
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
||||||
@ -132,7 +146,8 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public final HttpResponse httpPost(final String uriPath, final JsonTemplate bodyJsonTemplate) {
|
public final HttpResponse httpPost(final String uriPathWithPlaceholders, final JsonTemplate bodyJsonTemplate) {
|
||||||
|
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders);
|
||||||
final var requestBody = bodyJsonTemplate.resolvePlaceholders();
|
final var requestBody = bodyJsonTemplate.resolvePlaceholders();
|
||||||
final var request = HttpRequest.newBuilder()
|
final var request = HttpRequest.newBuilder()
|
||||||
.POST(BodyPublishers.ofString(requestBody))
|
.POST(BodyPublishers.ofString(requestBody))
|
||||||
@ -146,7 +161,8 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public final HttpResponse httpPatch(final String uriPath, final JsonTemplate bodyJsonTemplate) {
|
public final HttpResponse httpPatch(final String uriPathWithPlaceholders, final JsonTemplate bodyJsonTemplate) {
|
||||||
|
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders);
|
||||||
final var requestBody = bodyJsonTemplate.resolvePlaceholders();
|
final var requestBody = bodyJsonTemplate.resolvePlaceholders();
|
||||||
final var request = HttpRequest.newBuilder()
|
final var request = HttpRequest.newBuilder()
|
||||||
.method(HttpMethod.PATCH.toString(), BodyPublishers.ofString(requestBody))
|
.method(HttpMethod.PATCH.toString(), BodyPublishers.ofString(requestBody))
|
||||||
@ -160,7 +176,8 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public final HttpResponse httpDelete(final String uriPath) {
|
public final HttpResponse httpDelete(final String uriPathWithPlaceholders) {
|
||||||
|
final var uriPath = ScenarioTest.resolve(uriPathWithPlaceholders);
|
||||||
final var request = HttpRequest.newBuilder()
|
final var request = HttpRequest.newBuilder()
|
||||||
.DELETE()
|
.DELETE()
|
||||||
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
.uri(new URI("http://localhost:" + testSuite.port + uriPath))
|
||||||
@ -172,12 +189,27 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
return new HttpResponse(HttpMethod.DELETE, uriPath, null, response);
|
return new HttpResponse(HttpMethod.DELETE, uriPath, null, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected PathAssertion path(final String path) {
|
||||||
|
return new PathAssertion(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verify(
|
||||||
|
final String title,
|
||||||
|
final Supplier<UseCase.HttpResponse> http,
|
||||||
|
final Consumer<UseCase.HttpResponse>... assertions) {
|
||||||
|
withTitle(ScenarioTest.resolve(title), () -> {
|
||||||
|
final var response = http.get();
|
||||||
|
Arrays.stream(assertions).forEach(assertion -> assertion.accept(response));
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public final UUID uuid(final String alias) {
|
public final UUID uuid(final String alias) {
|
||||||
return ScenarioTest.uuid(alias);
|
return ScenarioTest.uuid(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String uriEncoded(final String text) {
|
public String uriEncoded(final String text) {
|
||||||
return encode(ScenarioTest.resolve(text));
|
return encode(ScenarioTest.resolve(text), StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class JsonTemplate {
|
public static class JsonTemplate {
|
||||||
@ -193,7 +225,7 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HttpResponse {
|
public final class HttpResponse {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final java.net.http.HttpResponse<String> response;
|
private final java.net.http.HttpResponse<String> response;
|
||||||
@ -232,7 +264,7 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void keep(final Function<HttpResponse, String> extractor) {
|
public HttpResponse keep(final Function<HttpResponse, String> extractor) {
|
||||||
final var alias = nextTitle != null ? nextTitle : resultAlias;
|
final var alias = nextTitle != null ? nextTitle : resultAlias;
|
||||||
assertThat(alias).as("cannot keep result, no alias found").isNotNull();
|
assertThat(alias).as("cannot keep result, no alias found").isNotNull();
|
||||||
|
|
||||||
@ -240,14 +272,16 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
ScenarioTest.putAlias(
|
ScenarioTest.putAlias(
|
||||||
alias,
|
alias,
|
||||||
new ScenarioTest.Alias<>(UseCase.this.getClass(), UUID.fromString(value)));
|
new ScenarioTest.Alias<>(UseCase.this.getClass(), UUID.fromString(value)));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void keep() {
|
public HttpResponse keep() {
|
||||||
final var alias = nextTitle != null ? nextTitle : resultAlias;
|
final var alias = nextTitle != null ? nextTitle : resultAlias;
|
||||||
assertThat(alias).as("cannot keep result, no alias found").isNotNull();
|
assertThat(alias).as("cannot keep result, no alias found").isNotNull();
|
||||||
ScenarioTest.putAlias(
|
ScenarioTest.putAlias(
|
||||||
alias,
|
alias,
|
||||||
new ScenarioTest.Alias<>(UseCase.this.getClass(), locationUuid));
|
new ScenarioTest.Alias<>(UseCase.this.getClass(), locationUuid));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@ -263,7 +297,21 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public String getFromBody(final String path) {
|
public String getFromBody(final String path) {
|
||||||
return JsonPath.parse(response.body()).read(path);
|
return JsonPath.parse(response.body()).read(ScenarioTest.resolve(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public Optional<String> getFromBodyAsOptional(final String path) {
|
||||||
|
try {
|
||||||
|
return Optional.ofNullable(JsonPath.parse(response.body()).read(ScenarioTest.resolve(path)));
|
||||||
|
} catch (final Exception e) {
|
||||||
|
return null; // means the property did not exist at all, not that it was there with value null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public OptionalAssert<String> path(final String path) {
|
||||||
|
return assertThat(getFromBodyAsOptional(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@ -274,6 +322,8 @@ public abstract class UseCase<T extends UseCase<?>> {
|
|||||||
testReport.printLine("\n### " + nextTitle + "\n");
|
testReport.printLine("\n### " + nextTitle + "\n");
|
||||||
} else if (resultAlias != null) {
|
} else if (resultAlias != null) {
|
||||||
testReport.printLine("\n### " + resultAlias + "\n");
|
testReport.printLine("\n### " + resultAlias + "\n");
|
||||||
|
} else {
|
||||||
|
fail("please wrap the http...-call in the UseCase using `withTitle(...)`");
|
||||||
}
|
}
|
||||||
|
|
||||||
// the request
|
// the request
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assumptions.assumeThat;
|
||||||
|
|
||||||
|
public class UseCaseNotImplementedYet extends UseCase<UseCaseNotImplementedYet> {
|
||||||
|
|
||||||
|
public UseCaseNotImplementedYet(final ScenarioTest testSuite) {
|
||||||
|
super(testSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpResponse run() {
|
||||||
|
assumeThat(false).isTrue(); // makes the test gray
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios.contact;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.UseCase;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
|
||||||
|
import static io.restassured.http.ContentType.JSON;
|
||||||
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
|
||||||
|
public class AddPhoneNumberToContactData extends UseCase<AddPhoneNumberToContactData> {
|
||||||
|
|
||||||
|
public AddPhoneNumberToContactData(final ScenarioTest testSuite) {
|
||||||
|
super(testSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpResponse run() {
|
||||||
|
|
||||||
|
obtain(
|
||||||
|
"partnerContactUuid",
|
||||||
|
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||||
|
.expecting(OK).expecting(JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].contact.uuid"),
|
||||||
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
|
);
|
||||||
|
|
||||||
|
withTitle("Patch the Additional Phone-Number into the Contact", () ->
|
||||||
|
httpPatch("/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
|
||||||
|
{
|
||||||
|
"phoneNumbers": {
|
||||||
|
${phoneNumberKeyToAdd}: ${phoneNumberToAdd}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""))
|
||||||
|
.expecting(HttpStatus.OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verify() {
|
||||||
|
verify(
|
||||||
|
"Verify if the New Phone Number Got Added",
|
||||||
|
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||||
|
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||||
|
path("[0].contact.phoneNumbers.%{phoneNumberKeyToAdd}").contains("%{phoneNumberToAdd}")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios.contact;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.UseCase;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
import static io.restassured.http.ContentType.JSON;
|
||||||
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
|
||||||
|
public class AmendContactData extends UseCase<AmendContactData> {
|
||||||
|
|
||||||
|
public AmendContactData(final ScenarioTest testSuite) {
|
||||||
|
super(testSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpResponse run() {
|
||||||
|
|
||||||
|
obtain("partnerContactUuid", () ->
|
||||||
|
httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||||
|
.expecting(OK).expecting(JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].contact.uuid"),
|
||||||
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
|
);
|
||||||
|
|
||||||
|
withTitle("Patch the New Phone Number Into the Contact", () ->
|
||||||
|
httpPatch("/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
|
||||||
|
{
|
||||||
|
"caption": ${newContactCaption???},
|
||||||
|
"postalAddress": ${newPostalAddress???},
|
||||||
|
"phoneNumbers": {
|
||||||
|
"office": ${newOfficePhoneNumber???}
|
||||||
|
},
|
||||||
|
"emailAddresses": {
|
||||||
|
"main": ${newEmailAddress???}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""))
|
||||||
|
.expecting(HttpStatus.OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios.contact;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.UseCase;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
import static io.restassured.http.ContentType.JSON;
|
||||||
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
|
||||||
|
public class RemovePhoneNumberFromContactData extends UseCase<RemovePhoneNumberFromContactData> {
|
||||||
|
|
||||||
|
public RemovePhoneNumberFromContactData(final ScenarioTest testSuite) {
|
||||||
|
super(testSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpResponse run() {
|
||||||
|
|
||||||
|
obtain(
|
||||||
|
"partnerContactUuid",
|
||||||
|
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||||
|
.expecting(OK).expecting(JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].contact.uuid"),
|
||||||
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
|
);
|
||||||
|
|
||||||
|
withTitle("Patch the Additional Phone-Number into the Contact", () ->
|
||||||
|
httpPatch("/api/hs/office/contacts/%{partnerContactUuid}", usingJsonBody("""
|
||||||
|
{
|
||||||
|
"phoneNumbers": {
|
||||||
|
${phoneNumberKeyToRemove}: NULL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""))
|
||||||
|
.expecting(HttpStatus.OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verify() {
|
||||||
|
verify(
|
||||||
|
"Verify if the New Phone Number Got Added",
|
||||||
|
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||||
|
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||||
|
path("[0].contact.phoneNumbers.%{phoneNumberKeyToRemove}").doesNotExist()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios.contact;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.UseCase;
|
||||||
|
|
||||||
|
import static io.restassured.http.ContentType.JSON;
|
||||||
|
import static org.springframework.http.HttpStatus.CREATED;
|
||||||
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
|
||||||
|
public class ReplaceContactData extends UseCase<ReplaceContactData> {
|
||||||
|
|
||||||
|
public ReplaceContactData(final ScenarioTest testSuite) {
|
||||||
|
super(testSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpResponse run() {
|
||||||
|
|
||||||
|
obtain("partnerRelationUuid", () ->
|
||||||
|
httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||||
|
.expecting(OK).expecting(JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
|
);
|
||||||
|
|
||||||
|
obtain("Contact: %{newContactCaption}", () ->
|
||||||
|
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
||||||
|
{
|
||||||
|
"caption": ${newContactCaption},
|
||||||
|
"postalAddress": ${newPostalAddress???},
|
||||||
|
"phoneNumbers": {
|
||||||
|
"phone": ${newOfficePhoneNumber???}
|
||||||
|
},
|
||||||
|
"emailAddresses": {
|
||||||
|
"main": ${newEmailAddress???}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""))
|
||||||
|
.expecting(CREATED).expecting(JSON),
|
||||||
|
"Please check first if that contact already exists, if so, use it's UUID below."
|
||||||
|
);
|
||||||
|
|
||||||
|
withTitle("Replace the Contact-Reference in the Partner-Relation", () ->
|
||||||
|
httpPatch("/api/hs/office/relations/%{partnerRelationUuid}", usingJsonBody("""
|
||||||
|
{
|
||||||
|
"contactUuid": ${Contact: %{newContactCaption}}
|
||||||
|
}
|
||||||
|
"""))
|
||||||
|
.expecting(OK)
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verify() {
|
||||||
|
verify(
|
||||||
|
"Verify if the Contact-Relation Got Replaced in the Partner-Relation",
|
||||||
|
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerName}"))
|
||||||
|
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||||
|
path("[0].contact.caption").contains("%{newContactCaption}")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -26,7 +26,7 @@ public class CreateExternalDebitorForPartner extends UseCase<CreateExternalDebit
|
|||||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||||
.expecting(OK).expecting(JSON),
|
.expecting(OK).expecting(JSON),
|
||||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
"In production data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
);
|
);
|
||||||
|
|
||||||
obtain("BankAccount: Billing GmbH - refund bank account", () ->
|
obtain("BankAccount: Billing GmbH - refund bank account", () ->
|
||||||
|
@ -19,8 +19,7 @@ public class CreateSelfDebitorForPartner extends UseCase<CreateSelfDebitorForPar
|
|||||||
httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerPersonTradeName}"))
|
httpGet("/api/hs/office/relations?relationType=PARTNER&personData=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||||
.expecting(OK).expecting(JSON),
|
.expecting(OK).expecting(JSON),
|
||||||
response -> response.expectArrayElements(1).getFromBody("[0].holder.uuid"),
|
response -> response.expectArrayElements(1).getFromBody("[0].holder.uuid"),
|
||||||
"In production data this query could result in multiple outputs. In that case, you have to find out which is the right one.",
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
"**HINT**: With production data, you might get multiple results and have to decide which is the right one."
|
|
||||||
);
|
);
|
||||||
|
|
||||||
obtain("BankAccount: Test AG - refund bank account", () ->
|
obtain("BankAccount: Test AG - refund bank account", () ->
|
||||||
|
@ -5,6 +5,7 @@ import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
|||||||
|
|
||||||
import static io.restassured.http.ContentType.JSON;
|
import static io.restassured.http.ContentType.JSON;
|
||||||
import static org.springframework.http.HttpStatus.CREATED;
|
import static org.springframework.http.HttpStatus.CREATED;
|
||||||
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
|
||||||
public class CreateSepaMandateForDebitor extends UseCase<CreateSepaMandateForDebitor> {
|
public class CreateSepaMandateForDebitor extends UseCase<CreateSepaMandateForDebitor> {
|
||||||
|
|
||||||
@ -14,12 +15,19 @@ public class CreateSepaMandateForDebitor extends UseCase<CreateSepaMandateForDeb
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HttpResponse run() {
|
protected HttpResponse run() {
|
||||||
|
|
||||||
|
obtain("Debitor: Test AG - main debitor", () ->
|
||||||
|
httpGet("/api/hs/office/debitors?debitorNumber=&{debitorNumber}")
|
||||||
|
.expecting(OK).expecting(JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid")
|
||||||
|
);
|
||||||
|
|
||||||
obtain("BankAccount: Test AG - debit bank account", () ->
|
obtain("BankAccount: Test AG - debit bank account", () ->
|
||||||
httpPost("/api/hs/office/bankaccounts", usingJsonBody("""
|
httpPost("/api/hs/office/bankaccounts", usingJsonBody("""
|
||||||
{
|
{
|
||||||
"holder": "Test AG - debit bank account",
|
"holder": ${bankAccountHolder},
|
||||||
"iban": "DE02701500000000594937",
|
"iban": ${bankAccountIBAN},
|
||||||
"bic": "SSKMDEMM"
|
"bic": ${bankAccountBIC}
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
.expecting(CREATED).expecting(JSON)
|
.expecting(CREATED).expecting(JSON)
|
||||||
@ -29,9 +37,9 @@ public class CreateSepaMandateForDebitor extends UseCase<CreateSepaMandateForDeb
|
|||||||
{
|
{
|
||||||
"debitorUuid": ${Debitor: Test AG - main debitor},
|
"debitorUuid": ${Debitor: Test AG - main debitor},
|
||||||
"bankAccountUuid": ${BankAccount: Test AG - debit bank account},
|
"bankAccountUuid": ${BankAccount: Test AG - debit bank account},
|
||||||
"reference": "Test AG - main debitor",
|
"reference": ${mandateReference},
|
||||||
"agreement": "2022-10-12",
|
"agreement": ${mandateAgreement},
|
||||||
"validFrom": "2022-10-13"
|
"validFrom": ${mandateValidFrom}
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
.expecting(CREATED).expecting(JSON);
|
.expecting(CREATED).expecting(JSON);
|
||||||
|
@ -24,8 +24,10 @@ public class DeleteDebitor extends UseCase<DeleteDebitor> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HttpResponse run() {
|
protected HttpResponse run() {
|
||||||
httpDelete("/api/hs/office/debitors/" + uuid("Debitor: Test AG - delete debitor"))
|
withTitle("Delete the Debitor using its UUID", () ->
|
||||||
.expecting(HttpStatus.NO_CONTENT);
|
httpDelete("/api/hs/office/debitors/&{Debitor: Test AG - delete debitor}")
|
||||||
|
.expecting(HttpStatus.NO_CONTENT)
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.scenarios.debitor;
|
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.UseCase;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
|
|
||||||
|
|
||||||
public class DeleteSepaMandateForDebitor extends UseCase<DeleteSepaMandateForDebitor> {
|
|
||||||
|
|
||||||
public DeleteSepaMandateForDebitor(final ScenarioTest testSuite) {
|
|
||||||
super(testSuite);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected HttpResponse run() {
|
|
||||||
httpDelete("/api/hs/office/sepamandates/" + uuid("SEPA-Mandate: Test AG"))
|
|
||||||
.expecting(HttpStatus.NO_CONTENT);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,7 +12,7 @@ public class DontDeleteDefaultDebitor extends UseCase<DontDeleteDefaultDebitor>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HttpResponse run() {
|
protected HttpResponse run() {
|
||||||
httpDelete("/api/hs/office/debitors/" + uuid("Debitor: Test AG - main debitor"))
|
httpDelete("/api/hs/office/debitors/&{Debitor: Test AG - main debitor}")
|
||||||
// TODO.spec: should be CONFLICT or CLIENT_ERROR for Debitor "00" - but how to delete Partners?
|
// TODO.spec: should be CONFLICT or CLIENT_ERROR for Debitor "00" - but how to delete Partners?
|
||||||
.expecting(HttpStatus.NO_CONTENT);
|
.expecting(HttpStatus.NO_CONTENT);
|
||||||
return null;
|
return null;
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios.debitor;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.UseCase;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
import static io.restassured.http.ContentType.JSON;
|
||||||
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
|
||||||
|
public class FinallyDeleteSepaMandateForDebitor extends UseCase<FinallyDeleteSepaMandateForDebitor> {
|
||||||
|
|
||||||
|
public FinallyDeleteSepaMandateForDebitor(final ScenarioTest testSuite) {
|
||||||
|
super(testSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpResponse run() {
|
||||||
|
|
||||||
|
obtain("SEPA-Mandate: %{bankAccountIBAN}", () ->
|
||||||
|
httpGet("/api/hs/office/sepamandates?iban=&{bankAccountIBAN}")
|
||||||
|
.expecting(OK).expecting(JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
|
"With production data, the bank-account could be used in multiple SEPA-mandates, make sure to use the right one!"
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO.spec: When to allow actual deletion of SEPA-mandates? Add constraint accordingly.
|
||||||
|
return withTitle("Delete the SEPA-Mandate by its UUID", () -> httpDelete("/api/hs/office/sepamandates/&{SEPA-Mandate: %{bankAccountIBAN}}")
|
||||||
|
.expecting(HttpStatus.NO_CONTENT)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -15,11 +15,20 @@ public class InvalidateSepaMandateForDebitor extends UseCase<InvalidateSepaManda
|
|||||||
@Override
|
@Override
|
||||||
protected HttpResponse run() {
|
protected HttpResponse run() {
|
||||||
|
|
||||||
return httpPatch("/api/hs/office/sepamandates/" + uuid("SEPA-Mandate: Test AG"), usingJsonBody("""
|
obtain("SEPA-Mandate: %{bankAccountIBAN}", () ->
|
||||||
|
httpGet("/api/hs/office/sepamandates?iban=&{bankAccountIBAN}")
|
||||||
|
.expecting(OK).expecting(JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
|
"With production data, the bank-account could be used in multiple SEPA-mandates, make sure to use the right one!"
|
||||||
|
);
|
||||||
|
|
||||||
|
return withTitle("Patch the End of the Mandate into the SEPA-Mandate", () ->
|
||||||
|
httpPatch("/api/hs/office/sepamandates/&{SEPA-Mandate: %{bankAccountIBAN}}", usingJsonBody("""
|
||||||
{
|
{
|
||||||
"validUntil": ${validUntil}
|
"validUntil": ${mandateValidUntil}
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
.expecting(OK).expecting(JSON);
|
.expecting(OK).expecting(JSON)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public class AddOperationsContactToPartner extends UseCase<AddOperationsContactT
|
|||||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||||
.expecting(OK).expecting(JSON),
|
.expecting(OK).expecting(JSON),
|
||||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
"In production data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
);
|
);
|
||||||
|
|
||||||
obtain("Person: %{operationsContactGivenName} %{operationsContactFamilyName}", () ->
|
obtain("Person: %{operationsContactGivenName} %{operationsContactFamilyName}", () ->
|
||||||
@ -64,4 +64,15 @@ public class AddOperationsContactToPartner extends UseCase<AddOperationsContactT
|
|||||||
"""))
|
"""))
|
||||||
.expecting(CREATED).expecting(JSON);
|
.expecting(CREATED).expecting(JSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verify() {
|
||||||
|
verify(
|
||||||
|
"Verify the New OPERATIONS Relation",
|
||||||
|
() -> httpGet("/api/hs/office/relations?relationType=OPERATIONS&personData=" + uriEncoded(
|
||||||
|
"%{operationsContactFamilyName}"))
|
||||||
|
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||||
|
path("[0].contact.caption").contains("%{operationsContactGivenName} %{operationsContactFamilyName}")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public class AddRepresentativeToPartner extends UseCase<AddRepresentativeToPartn
|
|||||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||||
.expecting(OK).expecting(JSON),
|
.expecting(OK).expecting(JSON),
|
||||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
"In production data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
);
|
);
|
||||||
|
|
||||||
obtain("Person: %{representativeGivenName} %{representativeFamilyName}", () ->
|
obtain("Person: %{representativeGivenName} %{representativeFamilyName}", () ->
|
||||||
@ -65,4 +65,14 @@ public class AddRepresentativeToPartner extends UseCase<AddRepresentativeToPartn
|
|||||||
"""))
|
"""))
|
||||||
.expecting(CREATED).expecting(JSON);
|
.expecting(CREATED).expecting(JSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verify() {
|
||||||
|
verify(
|
||||||
|
"Verify the REPRESENTATIVE Relation Got Removed",
|
||||||
|
() -> httpGet("/api/hs/office/relations?relationType=REPRESENTATIVE&personData=" + uriEncoded("%{representativeFamilyName}"))
|
||||||
|
.expecting(OK).expecting(JSON).expectArrayElements(1),
|
||||||
|
path("[0].contact.caption").contains("%{representativeGivenName} %{representativeFamilyName}")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,22 +28,28 @@ public class CreatePartner extends UseCase<CreatePartner> {
|
|||||||
"Even in production data we expect this query to return just a single result." // TODO.impl: add constraint?
|
"Even in production data we expect this query to return just a single result." // TODO.impl: add constraint?
|
||||||
);
|
);
|
||||||
|
|
||||||
obtain("Person: %{tradeName}", () ->
|
obtain("Person: %{%{tradeName???}???%{givenName???} %{familyName???}}", () ->
|
||||||
httpPost("/api/hs/office/persons", usingJsonBody("""
|
httpPost("/api/hs/office/persons", usingJsonBody("""
|
||||||
{
|
{
|
||||||
"personType": ${personType},
|
"personType": ${personType???},
|
||||||
"tradeName": ${tradeName}
|
"tradeName": ${tradeName???},
|
||||||
|
"givenName": ${givenName???},
|
||||||
|
"familyName": ${familyName???}
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
|
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
|
||||||
);
|
);
|
||||||
|
|
||||||
obtain("Contact: %{tradeName} - Board of Directors", () ->
|
obtain("Contact: %{contactCaption}", () ->
|
||||||
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
||||||
{
|
{
|
||||||
"caption": ${contactCaption},
|
"caption": ${contactCaption},
|
||||||
|
"postalAddress": ${postalAddress???},
|
||||||
|
"phoneNumbers": {
|
||||||
|
"office": ${officePhoneNumber???}
|
||||||
|
},
|
||||||
"emailAddresses": {
|
"emailAddresses": {
|
||||||
"main": ${emailAddress}
|
"main": ${emailAddress???}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
@ -55,8 +61,8 @@ public class CreatePartner extends UseCase<CreatePartner> {
|
|||||||
"partnerNumber": ${partnerNumber},
|
"partnerNumber": ${partnerNumber},
|
||||||
"partnerRel": {
|
"partnerRel": {
|
||||||
"anchorUuid": ${Person: Hostsharing eG},
|
"anchorUuid": ${Person: Hostsharing eG},
|
||||||
"holderUuid": ${Person: %{tradeName}},
|
"holderUuid": ${Person: %{%{tradeName???}???%{givenName???} %{familyName???}}},
|
||||||
"contactUuid": ${Contact: %{tradeName} - Board of Directors}
|
"contactUuid": ${Contact: %{contactCaption}}
|
||||||
},
|
},
|
||||||
"details": {
|
"details": {
|
||||||
"registrationOffice": "Registergericht Hamburg",
|
"registrationOffice": "Registergericht Hamburg",
|
||||||
@ -66,4 +72,13 @@ public class CreatePartner extends UseCase<CreatePartner> {
|
|||||||
"""))
|
"""))
|
||||||
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON);
|
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verify() {
|
||||||
|
verify(
|
||||||
|
"Verify the New Partner Relation",
|
||||||
|
() -> httpGet("/api/hs/office/relations?relationType=PARTNER&contactData=&{contactCaption}")
|
||||||
|
.expecting(OK).expecting(JSON).expectArrayElements(1)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,10 @@ public class DeletePartner extends UseCase<DeletePartner> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HttpResponse run() {
|
protected HttpResponse run() {
|
||||||
httpDelete("/api/hs/office/partners/" + uuid("Partner: Delete AG"))
|
withTitle("Delete Partner by its UUID", () ->
|
||||||
.expecting(HttpStatus.NO_CONTENT);
|
httpDelete("/api/hs/office/partners/&{Partner: Delete AG}")
|
||||||
|
.expecting(HttpStatus.NO_CONTENT)
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,14 @@ public class CreatePerson extends UseCase<CreatePerson> {
|
|||||||
@Override
|
@Override
|
||||||
protected HttpResponse run() {
|
protected HttpResponse run() {
|
||||||
|
|
||||||
return httpPost("/api/hs/office/persons", usingJsonBody("""
|
return withTitle("Create the Person", () ->
|
||||||
|
httpPost("/api/hs/office/persons", usingJsonBody("""
|
||||||
{
|
{
|
||||||
"personType": ${personType},
|
"personType": ${personType},
|
||||||
"tradeName": ${tradeName}
|
"tradeName": ${tradeName}
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON);
|
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.scenarios.subscription;
|
package net.hostsharing.hsadminng.hs.office.scenarios.subscription;
|
||||||
|
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.UseCase;
|
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
import net.hostsharing.hsadminng.hs.office.scenarios.ScenarioTest;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.UseCase;
|
||||||
|
|
||||||
import static io.restassured.http.ContentType.JSON;
|
import static io.restassured.http.ContentType.JSON;
|
||||||
|
import static org.springframework.http.HttpStatus.NOT_FOUND;
|
||||||
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
||||||
import static org.springframework.http.HttpStatus.OK;
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
|
||||||
@ -16,14 +17,27 @@ public class RemoveOperationsContactFromPartner extends UseCase<RemoveOperations
|
|||||||
@Override
|
@Override
|
||||||
protected HttpResponse run() {
|
protected HttpResponse run() {
|
||||||
|
|
||||||
obtain("Operations-Contact: %{operationsContactPerson}", () ->
|
obtain("Operations-Contact: %{operationsContactPerson}",
|
||||||
httpGet("/api/hs/office/relations?relationType=OPERATIONS&name=" + uriEncoded("%{operationsContactPerson}"))
|
() ->
|
||||||
|
httpGet("/api/hs/office/relations?relationType=OPERATIONS&name=" + uriEncoded(
|
||||||
|
"%{operationsContactPerson}"))
|
||||||
.expecting(OK).expecting(JSON),
|
.expecting(OK).expecting(JSON),
|
||||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
"In production data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
);
|
);
|
||||||
|
|
||||||
return httpDelete("/api/hs/office/relations/" + uuid("Operations-Contact: %{operationsContactPerson}"))
|
return withTitle("Delete the Contact", () ->
|
||||||
.expecting(NO_CONTENT);
|
httpDelete("/api/hs/office/relations/&{Operations-Contact: %{operationsContactPerson}}")
|
||||||
|
.expecting(NO_CONTENT)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verify() {
|
||||||
|
verify(
|
||||||
|
"Verify the New OPERATIONS Relation",
|
||||||
|
() -> httpGet("/api/hs/office/relations/&{Operations-Contact: %{operationsContactPerson}}")
|
||||||
|
.expecting(NOT_FOUND)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public class SubscribeToMailinglist extends UseCase<SubscribeToMailinglist> {
|
|||||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||||
.expecting(OK).expecting(JSON),
|
.expecting(OK).expecting(JSON),
|
||||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
"In production data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
);
|
);
|
||||||
|
|
||||||
obtain("Person: %{subscriberGivenName} %{subscriberFamilyName}", () ->
|
obtain("Person: %{subscriberGivenName} %{subscriberFamilyName}", () ->
|
||||||
|
@ -22,10 +22,12 @@ public class UnsubscribeFromMailinglist extends UseCase<UnsubscribeFromMailingli
|
|||||||
"&contactData=" + uriEncoded("%{subscriberEMailAddress}"))
|
"&contactData=" + uriEncoded("%{subscriberEMailAddress}"))
|
||||||
.expecting(OK).expecting(JSON),
|
.expecting(OK).expecting(JSON),
|
||||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
"In production data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
);
|
);
|
||||||
|
|
||||||
return httpDelete("/api/hs/office/relations/" + uuid("Subscription: %{subscriberEMailAddress}"))
|
return withTitle("Delete the Subscriber-Relation by its UUID", () ->
|
||||||
.expecting(NO_CONTENT);
|
httpDelete("/api/hs/office/relations/&{Subscription: %{subscriberEMailAddress}}")
|
||||||
|
.expecting(NO_CONTENT)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountReposi
|
|||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
||||||
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
|
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
|
||||||
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
||||||
import org.json.JSONException;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
@ -58,7 +57,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
|
|||||||
class ListSepaMandates {
|
class ListSepaMandates {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void globalAdmin_canViewAllSepaMandates_ifNoCriteriaGiven() throws JSONException {
|
void globalAdmin_canViewAllSepaMandates_ifNoCriteriaGiven() {
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -97,6 +96,36 @@ class HsOfficeSepaMandateControllerAcceptanceTest extends ContextBasedTestWithCl
|
|||||||
"""));
|
"""));
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalAdmin_canFindSepaMandateByName() {
|
||||||
|
|
||||||
|
RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-subject", "superuser-alex@hostsharing.net")
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.get("http://localhost/api/hs/office/sepamandates?iban=DE02120300000000202051")
|
||||||
|
.then().log().all().assertThat()
|
||||||
|
.statusCode(200)
|
||||||
|
.contentType("application/json")
|
||||||
|
.log().all()
|
||||||
|
.body("", lenientlyEquals("""
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"debitor": { "debitorNumber": 1000111 },
|
||||||
|
"bankAccount": {
|
||||||
|
"iban": "DE02120300000000202051",
|
||||||
|
"holder": "First GmbH"
|
||||||
|
},
|
||||||
|
"reference": "ref-10001-11",
|
||||||
|
"validFrom": "2022-10-01",
|
||||||
|
"validTo": "2026-12-31"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"""));
|
||||||
|
// @formatter:on
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
|
Loading…
Reference in New Issue
Block a user