Indholdsfortegnelse:
Formålet med dette dokument er at beskrive hvordan et udviklingsmiljø til videreudvikling af Nationalt eCPR-servicen kan sættes op, samt hvordan koden bygges, deployes og testes.
Først beskrives de softwaremæssige krav der er til miljøet, samt hvordan kode hentes og bygges. Kodestrukturen, kodemæssige afhængigheder til tredjeparts moduler og de forskellige servicemodulers ansvar og design beskrives sidst i dette dokument sammen med testdesign.
Læser forventes at have kendskab til Java softwareudvikling med anvendelse af Maven og WildFly. Derudover forventes kendskab til docker-compose.
Hvor der i teksten er angivet <component base> refereres til topniveaufolderen for kildekoden for komponenten.
eCPR-servicen udstiller en SOAP service, der følger DGWS. Snitfladen er defineret i et sæt WSDL filer og en række XSD filer.
eCPR-servicen er en Java baseret komponent, der for nuværende baserer sig på Java 8 og Spring frameworket. Den overordnede arkitektur og design er beskrevet i eCPR - Design- og Arkitekturbeskrivelse.
I det følgende antages at koden er hentet fra git: https://git.nspop.dk/projects/COM
eCPR-servicen deployeres vha. docker, og baserer sig på NSP platformens base image, hvori der findes nødvendigt software til afvikling.
Derudover er der krav til de anvendte udviklingsværktøjer:
Man skal bruge Apache Maven til at bygge eCPR, hvilket gøres ved at køre kommandoen
mvn clean install |
Med denne kommando køres unittest også. For at bygge uden test køres kommandoen
mvn clean install -D maven.test.skip=true -e |
For at bygge og køre integrationstests køres kommandoen
mvn clean install -P=integrationstest |
Efter byg (med eller uden test) kan WAR filen findes under ecpr2-service/target/ecpr2-service-1.28.18
For at bygge docker-imaget udføres kommandoen
docker-compose -f compose/development/docker-compose.yml up -d --build |
som både bygger og starter en lokal database og selve servicen ecpr2. Herefter kan eCPR findes på port 8380.
Endpointet kan findes på http://localhost:8380/ecpr2/services/ecpr2.
Systemarkitekturen er beskrevet i eCPR - Design- og Arkitekturbeskrivelse. Nedenfor beskrives systemdesignet vha. sekvensdiagrammer, der viser flowet gennem systemet. Som eksempel er her udtaget "createPersonRequest", der repræsenterer mange af de hovedtræk der er i et forløb når der modtages et request.
Læsevejledning til sekvensdiagrammet
Sekvensdiagrammet er udarbejdet med inspiration i UML. For at overskueliggøre diagrammet er der dog gjort undtagelser:
Der er generelt mange steder hvor en exception kan genereres/udløses. Som udgangspunkt kan alle valideringer udløse en exception samt alle create() kald. I sekvensdiagrammet kunne alle returkald (stiplede linjer) have udløst exception frem for en tom returnering, men det fremgår ikke af diagrammet for læsbarhedens skyld. Alle exceptions bliver grebet (catch) i ECPR2WebServiceImpl. Her bliver de håndteret, hvor en given fejlkode medsendt i den kastede exception bliver tiløjet responset. Et fejlende respons ser ud som følger:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <SOAP-ENV:Fault> <faultcode>SOAP-ENV:Server</faultcode> <faultstring xml:lang="en"> Fejlmeddlelse </faultstring> </SOAP-ENV:Fault> </SOAP-ENV:Body> </SOAP-ENV:Envelope> |
Kildekoden bygges vha Apache Maven. Overordnet består kildekoden af 5 Maven moduler, et parent modul (ecpr2) og 4 øvrige moduler, som kort beskrives nedenfor:
| Indeholder XSD-filer og WSDL-filer som udgør snitfladebeskrivelsen |
| Genererer java-filer ud fra XSD-filer og WSDL-filer fra ecpr2-schemas |
| Indeholder selve sourcekoden for systemet. Denne struktur er yderligere beskrevet nedenfor |
| Her ligger integrationstest for det samlede systemet |
ecpr-datagenerator | Modulet kan generere baggrundsdata til performancetesten (Se eCPR - Testvejledning) |
Når systemet bygges med maven er bygge rækkefølgen følgende:
Selve eCPR-servicens kodestruktur er uddybet nedenfor, hvor hver mappe under ecpr-service → src → main → java → dk.sds.ecpr2 er beskrevet:
Navn | Beskrivelse |
---|---|
advis | advis indeholder de klasser der er nødvendige ift. advisering via NAS |
constants | Konstanter til Lucene felt navne |
dao | Indeholder Data Access Object klasser. (DAO'er) |
domain | Indeholder alle Value Objekter (VO'er) |
rest | Indeholder 4 REST-endpoints. DKSController konfigurerer dcc-endpointet, ExportHistoryController udstiller status på exportHistoryJobbet, IsAliveController udstiller healthendpointet (se endpoints i driftsvejledningen) og WSDLController udstiller et endpoint hvor man kan se wsdl filerne. |
security | Håndtering af roller og rettigheder |
service | Håndtering af den primære logik. Herunder er alle handlers også defineret |
util | Indeholder hjælpeklasser, samt generel fejlhåndtering (Fejlkoder, fejlutil mm) |
webservice | Webservicer håndterer at modtage og sende requests/responses (Mapning af XML) samt videreføre kaldet i systemet, herunder securyty check. |
For at sikre en ensartet navngivning af tabeller, kolonner osv. er nedenstående navnekonvention indført i forhold til databasen.
Databasemodel styres ved hjælp af liquibase. Det betyder, at når der skal laves ændringer til databasemodellen, må man ikke rette i de eksisterende skemafiler. I stedet skal der laves nye filer, der beskriver ændringerne.
Skal der tilføjes f.eks. en ny kolonne eller en ny tabel skal nedenstående gøres.
Opstår der en situation, hvor der skal tilføjes yderlige testdata, for at integrationstesten kan afvikles, skal nedenstående udføres.
For at kunne teste systemet er udarbejdet både unittests og integrationstest. Til unittest bruges en in-memory h2 database, mens der til integrationstestene opstartes en dockercontainer. Der er forskel på hvilke tabeller og testdata, der er behov for i de to scenarier. Når unittestene afviklies oprettes de tabeller og testdata der ligger i mappen compose/database/initializeInMemoryDB mens der i dockermiljøet oprettes de tabeller og testdata, der ligger i mappen compose/database/initializeDockerDB.
JUnit anvendes til implementering af unit tests. Der er udarbejdet unit tests på kritisk logik i ecpr2-servicen.
Unit tests afvikling under byg med kommandoen angivet under Bygge WAR.
Mix-tests
Unit-testene er i visse tilfælde udarbejdet som integrationstest mellem flere klasser i systemet. Her er stadig gjort brug af JUnit til test (Se eCPR - Testvejledning).
Integrationstests er udarbejdet under modulet ecpr-test og kan afvikles under byg ved brug af profilen integrationstest, så længe tests ikke skippes.
Dette afvikles op mod det kørende udviklingsmiljø (docker-compose setup).
Performance testen foregår vha. et test framework udviklet af Arosii (version 2.0.0), og er udviklet med afslt i Performancekrav til NSP-services.
Performance testen består af 2 dele:
Udvikling og opsæt er beskrevet i nærværende dokument, mens den faktiske udførsel af testen er beskrevet i eCPR - Testvejledning.
I det følgende antages at koden er hentet ned fra git: https://git.nspop.dk/projects/NT/repos/performance-framework/ samt at man har docker installeret i sit udviklingsmiljø. JMeter skal også være tilgængelig.
Før performancetesten blev udviklet blev produktionsdata for eCPR undersøgt, for at kortlægge brigscenarier, og hvordan forskellige kald blev brugt. Dette reulterede i følgende mønstre:
Undersøgt i produktionsdata |
| |
| Rækkefælge af kald | Nærmere uddybning |
SearchPerson: |
|
|
GetPersonByID |
|
|
CreateAndUpdate |
| |
SearchAndCreate |
| |
Opfundede scenarier* |
| |
Merge |
|
|
ReservePersonID |
|
|
CompareName |
|
|
* De opfundede scenarier kunne ikke findes produktionsdata
På baggrund af kaldemønstrene som ses i tabellen ovenfor, er udarbejdet 6 threads, som tilsammen indeholder de identificerede brugscenarier:
Nogle af scenarierne kræver et mindre setup, og derfor er Threaden opsat med flere kald, end de kald, der er identificeret i tabellen. Et eksempel er MergePerson. Her kræves der 2 identiske personer. Dette er ikke oprettet at datageneratoren. For at oprette dette udføres 2 kald: GetPersonById → CreatePerson. Herefter udføres det forventede scenarie med SearchPerson → MergePerson → SearchPerson.
Kildekoden fra svn.nspop.dk indeholder også performance test til andre services. Nedenfor er givet en introduktion til eCPR servicens. Overordnet er repositoriet inddelt i 2, nemlig modules og tests.
Mappen 'modules' indeholder samplers med tilhørende samplerGUIs, der bruges i GUI'en. For eCPR performancetesten er udarbejdet en sampler og en GUI for samtlige endpoints, på nær DeletePerson, da denne kun bruges i test.
Nedenfor ses en liste over de udarbejdede samplers med tilhørende GUI, samt en kort beskrivelse, hvor dette er relevant:
GUI | Sampler | Beskrivelse/bemærkning |
---|---|---|
eCPRCreatePersonRequestSamplerGUI | eCPRCreatePersonRequestSampler | Her er det valgt, at der ved oprettelse udelukkende angives for- og efternavn, fødselsdato og køn. |
eCPRGetPersonByIDSamplerGUI | eCPRGetPersonByIDSampler | |
eCPRMergePersonsRequestSamplerGUI | eCPRMergePersonsRequestSampler | |
eCPRUpdatePersonSamplerGUI | eCPRUpdatePersonSampler | Ved en updatePerson skal navn og fødselsdato opdateres, og der tilføjes en adresse. |
eCPRSearchPersonRequestSamplerGUI | eCPRSearchPersonRequestSampler | I search person skal angives for- og efternavn samt fødselsdato. Der er mulighed for at angive en identifier, men denne kan som den eneste også efterlades tom. |
eCPRReservePersonIDSamplerGUI | eCPRReservePersonIDSampler | Denne har ingen variable GUI elementer, men har en Random generering af OrganisationsId, for at undgå at generere for mange id'er pr organisation på den samme dag |
eCPRGetOIDSamplerGUI | eCPRGetOIDSampler | Disse har ikke nogen GUI elementer, da requested ikke har nogle variable parametre. Sampleren bruges derfor udelukkende til at lave et setup af performancetesten, og ikke fordi outputtet bruges i de øvrige tests |
eCPRGetPermissionsGUI | eCPRGetPermissions | |
eCPRCompareNameRequestSamplerGUI | eCPRCompareNameRequestSampler | Ved Compare name kan angives et for- og efternavn. I sampleren er der indsat en generator, som i ~50% af tilfældende tilpasser navnet, så CompareName ikke altid returnerer 100. |
Når requested opsættes er der gjort brug af XML-filer, der indeholder et eksempel på et request. Dette forsimpler opsætningen af requested, og dermed overskueliggører koden. XML-filerne er placeret i resourcesfolderen under modules (modules/jmeter-ecpr/src/main/resources/com/arosii/jmeter/protocol/ecpr/sampler)
Tests mappen indeholder de generede test filer, som for eCPR svarer til testplanen eCPR.templates.jmx samt 3 distributioner (Disse er nærmere omtalt i eCPR - Testvejledning)
I dokumentet "testvejledning" afsnit performance test angives, hvilken version af performance testen der anvendes med en given version af eCPR servicen.
eCPR-servicens performance test består af ovennævnte java sourcer. Lokal test kan gøres ved at bygge projektet, starte dette i en lokal dockercontainer og starte JMeter op, og hererfter åbne testplanen eCPR.templates.jmx. For at testen kan køre skal bruges noget testdata. Dette data defineres i nogle testfiler som er placeret under /performance-framework/tests/ecpr/src/test/jmeter/templates/testplans. For performancetesten af eCPR bruges følgende filer, hvor parentesen angiver hvilke parametre der er i filen):
Testfil 1,2 og 3 kan bruges direkte, men identifiers (XeCPR) i identifier skal befinde sig i databasen. Denne kan genereres ifbm. datageneratoren opretter dummy-data, så testdatabasen ikke er helt tom. Herefter kopieres outputfilen identifiers.csv ind i mappen testplans i JMeter projektet). Alternativt kan lokalt laves et loop af "crestePerson" hvorefter der manuelt udtrækkes XeCPR-numre fra databasen.
Når man har udviklet og bygget test projektet, startes JMeter. Herefter kan en eksisterende performance test åbnes og køres herfra. Eller en ny kan laves.
For at køre en performancetest skal classpathen defineres i "user.properties" for JMeter (ligger i samme mappe som JMeter.bat).
Det følgende skærmbillede viser den skærm, som er udviklet i eCPRUpdatePersonRequestSamplerGui hvor der bruges data fra de samplers, der tidligere er kørt (eCPRCreatePersonRequestSampler og eCPRGetPersonByIDSampler):
Når man starter testen (den grønne pil) aktiveres et kald mod den service, der er konfigureret under 'Host configuration' og hermed aktiveres koden fra de respektive samplers. I dette skærmbillede ses, at for tråden Perormancetest - Create and Update aktiveres koden for først eCPRCreatePersonRequestSampler, herefter eCPRGetPersonByIDSampler og til sidst eCPRSearchPersonRequestSampler. Herefter aktiveres koden fra de samplers, der er defineret i loopcontrolleren SearchAndCreatePerson. Til sidst er indsat en Constant Throughput timer der sørger for, at samplersne eksekveres i en forholdsvis realistisk hastighed, her med en hastighed på 12 samplers/minut, svarende til en hver 3. sekundt.
Resultatet kan ses under 'View Result Tree', hvor både kald og svar kan ses. Her skal man være opmærksom på, at JMeter viser kaldene som værende fejlet, selvom de er lykkedes. Derfor skal man se på Sampleresult, hvor HTTP-statuskoden afgører om et request er lykkedes (Status = 200)
I skærmbilledet ses også samtlige tråde, der spinnes op under en performancetest af hele systemet. Hver tråd repræsenterer et brugscenarie. Brugscenarierne er primært identificeret ud fra produktionsdata fra eCPR2 på FMK.
Den endelige kørsel af performance testen skal bruge en test plan (skabes når ovenstående test gemmes) samt en distribution, der indeholder 'Distribution' delen af ovenstående. De gemmes henholdsvis i tests/ecpr/src/test/jmeter/templates/testplans og tests/ecpr/src/test/jmeter/templates/distributions. For at ændre distributionen skal der altså indlæses en ønsket distribution fil fra tests/ecpr/src/test/jmeter/templates/distributions.
Distribution
I distribution kan belastningen og fordelingen styres. Samtlige tråde er sat til at loope forevigt, og længden styres dermed af en Scheduler, hvor tiden kan styres via Distribution paramteren MASTER_LOOP_TIME. Antallet af usersne styres med parameteren USER_THREAD_COUNT, svarende til antallet af tråde der startes af hver handling. Den eneste undtagelse er tråden Performancetest -Spike of GetPersonById. Denne tråd modulerer et spike af GetPersonByID, der ses i produktionsdata, hvor der en gang timen laves 210-220 kald af GetPersonByID. Denne tråd er dermed sat til at udføre 220 kald af GetPersonByID, efterfulgt af en Constant throuhput timer, der efter hver 220. kald er sat til at vente 10 sekunder. Denne parameter på 6 omgang/minut tilpasses alt efter hvorlænge performancetesten udføres. Den reelle værdi er 1 gang i timen, men dette kan være en dårlig testværdi.
Løsningen er udviklet i Java og den udstillede WebServices er implementeret som Servlet 3 og anvender JAXB til serialisering og de-serialisering af beskeder.
Til håndtering af dependency injection bruges Spring, og til database transaktioner og databaser anvendes Spring JDBC
Nedenstående liste er en liste af 3. parts moduler som eCPR direkte afhænger af, opstillet i alfabetisk orden. Det vil sige dem der er listet i POM filerne. Udover det anvendes der også en række biblioteker, der stilles til rådighed af platformen. Disse er ikke listet her.
com.fasterxml.jackson.core:jackson-annotations:2.8.10
com.fasterxml.jackson.core:jackson-core:2.8.10
com.fasterxml.jackson.core:jackson-databind:2.8.10
com.github.mwiede:jsch:0.2.11
com.sun.xml.bind:jaxb-impl
commons-io:commons-io:2.7
javax.servlet:javax.servlet-api:3.1.0:provided
log4j:log4j:1.2.17
org.apache.cxf:cxf-api:2.7.13:provided
org.apache.commons:commons-text:1.10.0
org.apache.httpcomponents:httpclient:4.5.13
org.apache.lucene:lucene-core:8.11.2
org.apache.lucene:lucene-queryparser:8.11.2
org.apache.lucene:lucene-suggest:8.11.2
org.springframework:spring-core:5.2.24.RELEASE
org.springframework:spring-context:5.2.24.RELEASE
org.springframework:spring-jdbc:5.2.24.RELEASE
org.springframework:spring-test:5.2.24.RELEASE
dk.sosi.seal:seal:2.6.19
dk.sdsd.nsp:nsp-util:1.0.11
dk.sds.nsp.security:security-api:1.0.6:provided
dk.sds.nsp.audit:audit-api:1.0.1:provided
Nedenstående er en liste over de biblioteker der anvendes i forbindelse med test. Det vil sige dem der er angivet i POM filerne med scope test.
org.junit.jupiter:junit-jupiter:5.9.1:test
org.springframework.boot:spring-boot-starter-test:test
org.apache.sshd:sshd-core:0.8.0:test
com.h2database:h2:1.4.200:test
org.junit.vintage:junit-vintage-engine:5.9.1:test
org.mockito:mockito-core:4.11.0:test
Til integrationstestene anvendes derudover
dk.nsp.idp:nsp-test-idp:1.0.7
Ændringslog
1.0 | 2023-12-12 | Indhold publiceret | Trifork |