Fixed multi-threadening segment numbers generation
This commit is contained in:
parent
00d0e4158f
commit
16a73aa055
|
@ -8,9 +8,7 @@ import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGe
|
|||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedienArtVersion
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanProcess
|
||||
import net.dankito.banking.fints.messages.segmente.ISegmentNumberGenerator
|
||||
import net.dankito.banking.fints.messages.segmente.Segment
|
||||
import net.dankito.banking.fints.messages.segmente.SegmentNumberGenerator
|
||||
import net.dankito.banking.fints.messages.segmente.Synchronisierung
|
||||
import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId
|
||||
import net.dankito.banking.fints.messages.segmente.id.ISegmentId
|
||||
|
@ -30,13 +28,20 @@ import kotlin.math.absoluteValue
|
|||
* Takes the Segments of they payload, may signs and encrypts them, calculates message size,
|
||||
* adds the message header and ending, and formats the whole message to string.
|
||||
*/
|
||||
open class MessageBuilder(protected val generator: ISegmentNumberGenerator = SegmentNumberGenerator(),
|
||||
protected val utils: FinTsUtils = FinTsUtils()) {
|
||||
open class MessageBuilder(protected val utils: FinTsUtils = FinTsUtils()) {
|
||||
|
||||
companion object {
|
||||
const val MessageHeaderMinLength = 28
|
||||
|
||||
const val AddedSeparatorsLength = 3
|
||||
|
||||
private const val MessageHeaderSegmentNumber = 1
|
||||
|
||||
private const val UnsignedMessagePayloadSegmentNumberStart = MessageHeaderSegmentNumber + 1
|
||||
|
||||
private const val SignatureHeaderSegmentNumber = MessageHeaderSegmentNumber + 1
|
||||
|
||||
private const val SignedMessagePayloadFirstSegmentNumber = SignatureHeaderSegmentNumber + 1
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,15 +65,15 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
open fun createAnonymousDialogInitMessage(context: JobContext): MessageBuilderResult {
|
||||
|
||||
return createUnsignedMessageBuilderResult(context, MessageType.AnonymousDialogInit, listOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(1), context),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), context)
|
||||
IdentifikationsSegment(UnsignedMessagePayloadSegmentNumberStart, context),
|
||||
Verarbeitungsvorbereitung(UnsignedMessagePayloadSegmentNumberStart + 1, context)
|
||||
))
|
||||
}
|
||||
|
||||
open fun createAnonymousDialogEndMessage(context: JobContext): MessageBuilderResult {
|
||||
|
||||
return createUnsignedMessageBuilderResult(context, MessageType.DialogEnd, listOf(
|
||||
Dialogende(generator.resetSegmentNumber(1), context.dialog)
|
||||
Dialogende(UnsignedMessagePayloadSegmentNumberStart, context.dialog)
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -116,40 +121,37 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
}
|
||||
|
||||
protected open fun createInitDialogMessage(context: JobContext, segmentIdForTwoStepTanProcess: CustomerSegmentId?): MessageBuilderResult {
|
||||
|
||||
val segments = mutableListOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(2), context),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), context)
|
||||
IdentifikationsSegment(SignedMessagePayloadFirstSegmentNumber, context),
|
||||
Verarbeitungsvorbereitung(SignedMessagePayloadFirstSegmentNumber + 1, context)
|
||||
)
|
||||
|
||||
if (segmentIdForTwoStepTanProcess != null) {
|
||||
segments.add(createTwoStepTanSegment(context, segmentIdForTwoStepTanProcess))
|
||||
}
|
||||
else if (context.bank.isTanMethodSelected) {
|
||||
segments.add(createTwoStepTanSegment(context, CustomerSegmentId.Identification))
|
||||
segments.add(createTwoStepTanSegment(context, segmentIdForTwoStepTanProcess, SignedMessagePayloadFirstSegmentNumber + 2))
|
||||
} else if (context.bank.isTanMethodSelected) {
|
||||
segments.add(createTwoStepTanSegment(context, CustomerSegmentId.Identification, SignedMessagePayloadFirstSegmentNumber + 2))
|
||||
}
|
||||
|
||||
if (context.bank.customerSystemId == KundensystemID.Anonymous) {
|
||||
segments.add(Synchronisierung(generator.getNextSegmentNumber(), Synchronisierungsmodus.NeueKundensystemIdZurueckmelden))
|
||||
segments.add(Synchronisierung(segments.size + 3, Synchronisierungsmodus.NeueKundensystemIdZurueckmelden))
|
||||
}
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.DialogInit, segments)
|
||||
}
|
||||
|
||||
open fun createSynchronizeCustomerSystemIdMessage(context: JobContext): MessageBuilderResult {
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.SynchronizeCustomerSystemId, listOf(
|
||||
IdentifikationsSegment(generator.resetSegmentNumber(2), context),
|
||||
Verarbeitungsvorbereitung(generator.getNextSegmentNumber(), context),
|
||||
createTwoStepTanSegment(context, CustomerSegmentId.Identification),
|
||||
Synchronisierung(generator.getNextSegmentNumber(), Synchronisierungsmodus.NeueKundensystemIdZurueckmelden)
|
||||
IdentifikationsSegment(SignedMessagePayloadFirstSegmentNumber, context),
|
||||
Verarbeitungsvorbereitung(SignedMessagePayloadFirstSegmentNumber + 1, context),
|
||||
createTwoStepTanSegment(context, CustomerSegmentId.Identification, SignedMessagePayloadFirstSegmentNumber + 2),
|
||||
Synchronisierung(SignedMessagePayloadFirstSegmentNumber + 3, Synchronisierungsmodus.NeueKundensystemIdZurueckmelden)
|
||||
))
|
||||
}
|
||||
|
||||
open fun createDialogEndMessage(context: JobContext): MessageBuilderResult {
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.DialogEnd, listOf(
|
||||
Dialogende(generator.resetSegmentNumber(2), context.dialog)
|
||||
Dialogende(SignedMessagePayloadFirstSegmentNumber, context.dialog)
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -178,13 +180,15 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
parameter.isSettingMaxCountEntriesAllowedByBank = determineIsSettingMaxCountEntriesAllowed(context.bank, InstituteSegmentId.AccountTransactionsMt940Parameters, listOf(5, 6, 7))
|
||||
}
|
||||
|
||||
val transactionsJob = if (result.isAllowed(7)) KontoumsaetzeZeitraumMt940Version7(generator.resetSegmentNumber(2), parameter, context.bank)
|
||||
else if (result.isAllowed(6)) KontoumsaetzeZeitraumMt940Version6(generator.resetSegmentNumber(2), parameter)
|
||||
else KontoumsaetzeZeitraumMt940Version5(generator.resetSegmentNumber(2), parameter)
|
||||
val segmentNumber = SignedMessagePayloadFirstSegmentNumber
|
||||
|
||||
val transactionsJob = if (result.isAllowed(7)) KontoumsaetzeZeitraumMt940Version7(segmentNumber, parameter, context.bank)
|
||||
else if (result.isAllowed(6)) KontoumsaetzeZeitraumMt940Version6(segmentNumber, parameter)
|
||||
else KontoumsaetzeZeitraumMt940Version5(segmentNumber, parameter)
|
||||
|
||||
val segments = mutableListOf<Segment>(transactionsJob)
|
||||
|
||||
addTanSegmentIfRequired(context, CustomerSegmentId.AccountTransactionsMt940, segments)
|
||||
addTanSegmentIfRequired(context, CustomerSegmentId.AccountTransactionsMt940, segments, segmentNumber + 1)
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.GetTransactions, segments)
|
||||
}
|
||||
|
@ -198,9 +202,9 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
protected open fun createGetCreditCardTransactionsMessage(context: JobContext, result: MessageBuilderResult,
|
||||
parameter: GetAccountTransactionsParameter): MessageBuilderResult {
|
||||
|
||||
val segments = mutableListOf<Segment>(KreditkartenUmsaetze(generator.resetSegmentNumber(2), parameter))
|
||||
val segments = mutableListOf<Segment>(KreditkartenUmsaetze(SignedMessagePayloadFirstSegmentNumber, parameter))
|
||||
|
||||
addTanSegmentIfRequired(context, CustomerSegmentId.CreditCardTransactions, segments)
|
||||
addTanSegmentIfRequired(context, CustomerSegmentId.CreditCardTransactions, segments, SignedMessagePayloadFirstSegmentNumber + 1)
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.GetCreditCardTransactions, segments)
|
||||
}
|
||||
|
@ -224,12 +228,15 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
val result = supportsGetBalanceMessage(account)
|
||||
|
||||
if (result.isJobVersionSupported) {
|
||||
val balanceJob = if (result.isAllowed(5)) SaldenabfrageVersion5(generator.resetSegmentNumber(2), account)
|
||||
else SaldenabfrageVersion7(generator.resetSegmentNumber(2), account, context.bank)
|
||||
val segmentNumber = SignedMessagePayloadFirstSegmentNumber
|
||||
|
||||
val balanceJob = if (result.isAllowed(5)) SaldenabfrageVersion5(segmentNumber, account)
|
||||
// TODO: what about HKSAL6?
|
||||
else SaldenabfrageVersion7(segmentNumber, account, context.bank)
|
||||
|
||||
val segments = mutableListOf<Segment>(balanceJob)
|
||||
|
||||
addTanSegmentIfRequired(context, CustomerSegmentId.Balance, segments)
|
||||
addTanSegmentIfRequired(context, CustomerSegmentId.Balance, segments, segmentNumber + 1)
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.GetBalance, segments)
|
||||
}
|
||||
|
@ -254,8 +261,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
|
||||
if (result.isJobVersionSupported) {
|
||||
val segments = listOf(
|
||||
TanGeneratorListeAnzeigen(result.getHighestAllowedVersion!!,
|
||||
generator.resetSegmentNumber(2), tanMediaKind, tanMediumClass)
|
||||
TanGeneratorListeAnzeigen(result.getHighestAllowedVersion!!, SignedMessagePayloadFirstSegmentNumber, tanMediaKind, tanMediumClass)
|
||||
)
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.GetTanMedia, segments)
|
||||
|
@ -272,7 +278,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
|
||||
if (result.isJobVersionSupported) {
|
||||
val segments = listOf(
|
||||
TanGeneratorTanMediumAnOderUmmelden(result.getHighestAllowedVersion!!, generator.resetSegmentNumber(2),
|
||||
TanGeneratorTanMediumAnOderUmmelden(result.getHighestAllowedVersion!!, SignedMessagePayloadFirstSegmentNumber,
|
||||
context.bank, newActiveTanMedium, tan, atc)
|
||||
)
|
||||
|
||||
|
@ -287,7 +293,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
val tanProcess = if (tanResponse.tanProcess == TanProcess.TanProcess1) TanProcess.TanProcess1 else TanProcess.TanProcess2
|
||||
|
||||
val segments = listOf(
|
||||
ZweiSchrittTanEinreichung(generator.resetSegmentNumber(2), tanProcess, null,
|
||||
ZweiSchrittTanEinreichung(SignedMessagePayloadFirstSegmentNumber, tanProcess, null,
|
||||
tanResponse.jobHashValue, tanResponse.jobReference, false, null, tanResponse.tanMediaIdentifier)
|
||||
)
|
||||
|
||||
|
@ -302,10 +308,10 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
val (result, urn) = supportsBankTransferAndSepaVersion(context.bank, account, segmentId)
|
||||
|
||||
if (result.isJobVersionSupported && urn != null) {
|
||||
val segments = mutableListOf<Segment>(SepaBankTransferBase(segmentId, generator.resetSegmentNumber(2),
|
||||
val segments = mutableListOf<Segment>(SepaBankTransferBase(segmentId, SignedMessagePayloadFirstSegmentNumber,
|
||||
urn, context.bank.customerName, account, context.bank.bic, data))
|
||||
|
||||
addTanSegmentIfRequired(context, segmentId, segments)
|
||||
addTanSegmentIfRequired(context, segmentId, segments, SignedMessagePayloadFirstSegmentNumber + 1)
|
||||
|
||||
return createSignedMessageBuilderResult(context, MessageType.TransferMoney, segments)
|
||||
}
|
||||
|
@ -387,32 +393,32 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
return createSignedMessage(context, null, payloadSegments)
|
||||
}
|
||||
|
||||
open fun createSignedMessage(context: JobContext, tan: String? = null,
|
||||
payloadSegments: List<Segment>): String {
|
||||
open fun createSignedMessage(context: JobContext, tan: String? = null, payloadSegments: List<Segment>): String {
|
||||
|
||||
val date = utils.formatDateTodayAsInt()
|
||||
val time = utils.formatTimeNowAsInt()
|
||||
|
||||
val signedPayload = signPayload(2, context, date, time, tan, payloadSegments)
|
||||
val signedPayload = signPayload(context, date, time, tan, payloadSegments)
|
||||
|
||||
val encryptedPayload = encryptPayload(context, date, time, signedPayload)
|
||||
|
||||
return createMessage(context, encryptedPayload)
|
||||
return createMessage(context, encryptedPayload, payloadSegments.size)
|
||||
}
|
||||
|
||||
open fun createMessage(context: JobContext, payloadSegments: List<Segment>): String {
|
||||
open fun createMessage(context: JobContext, payloadSegments: List<Segment>, countWrappedSegments: Int = 0): String {
|
||||
|
||||
val dialog = context.dialog
|
||||
dialog.increaseMessageNumber()
|
||||
|
||||
val formattedPayload = formatPayload(payloadSegments)
|
||||
|
||||
val ending = Nachrichtenabschluss(generator.getNextSegmentNumber(), dialog)
|
||||
// if there are segments wrapped like in signed message body, we have to add these segments to segment count; +2 for Message Header and -Ending
|
||||
val ending = Nachrichtenabschluss(payloadSegments.size + countWrappedSegments + 2, dialog)
|
||||
val formattedEnding = ending.format()
|
||||
|
||||
val messageSize = calculateMessageSize(formattedPayload, formattedEnding, dialog)
|
||||
|
||||
val header = Nachrichtenkopf(ISegmentNumberGenerator.FirstSegmentNumber, messageSize, dialog)
|
||||
val header = Nachrichtenkopf(MessageHeaderSegmentNumber, messageSize, dialog)
|
||||
|
||||
return listOf(header.format(), formattedPayload, formattedEnding)
|
||||
.joinToString(Separators.SegmentSeparator, postfix = Separators.SegmentSeparator)
|
||||
|
@ -422,19 +428,19 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
// we don't know Header's length yet - but already have to know its length in order to calculate message length.
|
||||
// -> generate header with a known minimum header length added to message body length to calculate header length
|
||||
val minMessageSize = formattedPayload.length + MessageHeaderMinLength + formattedEnding.length + AddedSeparatorsLength
|
||||
val headerWithMinMessageSize = Nachrichtenkopf(ISegmentNumberGenerator.FirstSegmentNumber, minMessageSize, dialogContext).format()
|
||||
val headerWithMinMessageSize = Nachrichtenkopf(MessageHeaderSegmentNumber, minMessageSize, dialogContext).format()
|
||||
|
||||
return formattedPayload.length + headerWithMinMessageSize.length + formattedEnding.length + AddedSeparatorsLength
|
||||
}
|
||||
|
||||
|
||||
protected open fun signPayload(headerSegmentNumber: Int, context: JobContext, date: Int, time: Int,
|
||||
protected open fun signPayload(context: JobContext, date: Int, time: Int,
|
||||
tan: String? = null, payloadSegments: List<Segment>): List<Segment> {
|
||||
|
||||
val controlReference = createControlReference()
|
||||
|
||||
val signatureHeader = PinTanSignaturkopf(
|
||||
headerSegmentNumber,
|
||||
SignatureHeaderSegmentNumber, // is always 2
|
||||
context,
|
||||
controlReference,
|
||||
date,
|
||||
|
@ -442,7 +448,7 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
)
|
||||
|
||||
val signatureEnding = Signaturabschluss(
|
||||
generator.getNextSegmentNumber(),
|
||||
payloadSegments.size + 3, // +3: Message Header (1), Signatur Header (2), Signature Ending
|
||||
controlReference,
|
||||
context.bank.pin,
|
||||
tan
|
||||
|
@ -507,14 +513,14 @@ open class MessageBuilder(protected val generator: ISegmentNumberGenerator = Seg
|
|||
return MessageBuilderResult(false)
|
||||
}
|
||||
|
||||
protected open fun addTanSegmentIfRequired(context: JobContext, segmentId: CustomerSegmentId, segments: MutableList<Segment>) {
|
||||
protected open fun addTanSegmentIfRequired(context: JobContext, segmentId: CustomerSegmentId, segments: MutableList<Segment>, segmentNumber: Int) {
|
||||
if (isTanRequiredForJob(context, segmentId)) {
|
||||
segments.add(createTwoStepTanSegment(context, segmentId))
|
||||
segments.add(createTwoStepTanSegment(context, segmentId, segmentNumber))
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun createTwoStepTanSegment(context: JobContext, segmentId: CustomerSegmentId): ZweiSchrittTanEinreichung {
|
||||
return ZweiSchrittTanEinreichung(generator.getNextSegmentNumber(), TanProcess.TanProcess4, segmentId,
|
||||
protected open fun createTwoStepTanSegment(context: JobContext, segmentId: CustomerSegmentId, segmentNumber: Int): ZweiSchrittTanEinreichung {
|
||||
return ZweiSchrittTanEinreichung(segmentNumber, TanProcess.TanProcess4, segmentId,
|
||||
tanMediaIdentifier = getTanMediaIdentifierIfRequired(context))
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package net.dankito.banking.fints.messages.segmente
|
||||
|
||||
|
||||
interface ISegmentNumberGenerator {
|
||||
|
||||
companion object {
|
||||
const val FirstSegmentNumber = 1
|
||||
}
|
||||
|
||||
|
||||
fun resetSegmentNumber(countNumberToSkipForHeader: Int): Int
|
||||
|
||||
fun getNextSegmentNumber(): Int
|
||||
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package net.dankito.banking.fints.messages.segmente
|
||||
|
||||
import net.dankito.banking.fints.messages.segmente.ISegmentNumberGenerator.Companion.FirstSegmentNumber
|
||||
|
||||
|
||||
open class SegmentNumberGenerator : ISegmentNumberGenerator {
|
||||
|
||||
protected var currentSegmentNumber = 0
|
||||
|
||||
|
||||
override fun resetSegmentNumber(countNumbersToSkipForHeaders: Int): Int {
|
||||
currentSegmentNumber = FirstSegmentNumber + countNumbersToSkipForHeaders
|
||||
|
||||
return currentSegmentNumber
|
||||
}
|
||||
|
||||
override fun getNextSegmentNumber(): Int {
|
||||
return ++currentSegmentNumber
|
||||
}
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "Current segment number = $currentSegmentNumber"
|
||||
}
|
||||
|
||||
}
|
|
@ -9,6 +9,7 @@ import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Datum
|
|||
import net.dankito.banking.fints.messages.datenelemente.abgeleiteteformate.Laenderkennzeichen
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.Dialogsprache
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion
|
||||
import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.response.segments.AccountType
|
||||
import net.dankito.banking.fints.response.segments.ChangeTanMediaParameters
|
||||
|
@ -86,6 +87,10 @@ abstract class FinTsTestBase {
|
|||
return randomWithSeed().nextInt(1000000, 9999999).toString()
|
||||
}
|
||||
|
||||
protected open fun createAllowedJob(segmentId: CustomerSegmentId, version: Int): JobParameters = JobParameters(
|
||||
segmentId.id, 1, 1, null, "${segmentId.id.replace("HK", "HI")}S:1:$version"
|
||||
)
|
||||
|
||||
protected open fun convertDate(date: LocalDate): String {
|
||||
return Datum.format(date)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import kotlin.test.*
|
|||
|
||||
class MessageBuilderTest : FinTsTestBase() {
|
||||
|
||||
private val underTest = object : MessageBuilder(utils = object : FinTsUtils() {
|
||||
private val underTest = object : MessageBuilder(object : FinTsUtils() {
|
||||
override fun formatDate(date: LocalDate): String {
|
||||
return Date.toString()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
package net.dankito.banking.fints.messages
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.LocalTime
|
||||
import net.dankito.banking.fints.FinTsTestBase
|
||||
import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.*
|
||||
import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId
|
||||
import net.dankito.banking.fints.model.*
|
||||
import net.dankito.banking.fints.response.segments.*
|
||||
import net.dankito.banking.fints.util.FinTsUtils
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.test.AfterTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class MultiThreadedMessageBuilderTest : FinTsTestBase() {
|
||||
|
||||
private val underTest = object : MessageBuilder(object : FinTsUtils() {
|
||||
override fun formatDate(date: LocalDate): String {
|
||||
return Date.toString()
|
||||
}
|
||||
|
||||
override fun formatTime(time: LocalTime): String {
|
||||
return Time.toString()
|
||||
}
|
||||
}) {
|
||||
|
||||
override fun createControlReference(): String {
|
||||
return ControlReference
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private val bank = createTestBank()
|
||||
|
||||
@AfterTest
|
||||
fun tearDown() {
|
||||
bank.supportedJobs = listOf()
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testSegmentNumberOrderForParallelMessageCreation(): Unit = runTest {
|
||||
// in previous version when FinTsClient has been used in multi-threaded environments, e.g. on web servers were
|
||||
// messages are created for multiple parallel users, the segment numbers were wrong and not incrementally ordered
|
||||
|
||||
val bank = createBankWithAllFeatures()
|
||||
|
||||
val context = createContext(bank)
|
||||
|
||||
val dispatcher = Executors.newFixedThreadPool(24).asCoroutineDispatcher()
|
||||
val coroutineScope = CoroutineScope(dispatcher)
|
||||
|
||||
IntRange(0, 10_000).map { index ->
|
||||
coroutineScope.async {
|
||||
// context.startNewDialog()
|
||||
val result = createRandomMessage(index, context)
|
||||
|
||||
val (segments, segmentNumbers) = extractSegmentNumbers(result)
|
||||
|
||||
// assert that segment numbers are in ascending order in steps of one
|
||||
segmentNumbers.dropLast(1).forEachIndexed { index, segmentNumber ->
|
||||
val nextSegmentNumber = segmentNumbers[index + 1]
|
||||
|
||||
assertEquals(segmentNumber + 1, nextSegmentNumber,
|
||||
"Message numbers should be in ascending order with step one:\n${segments[index]}\n${segments[index + 1]}")
|
||||
}
|
||||
|
||||
assertEquals(1, segmentNumbers.first())
|
||||
assertEquals(segmentNumbers.size, segmentNumbers.last())
|
||||
|
||||
segments
|
||||
}
|
||||
}.awaitAll()
|
||||
}
|
||||
|
||||
private fun extractSegmentNumbers(result: MessageBuilderResult): Pair<List<String>, List<Int>> {
|
||||
val segments = result.createdMessage!!.split("'").filter { it.isNotBlank() && it.startsWith("HNVSK") == false }.map { segment ->
|
||||
if (segment.startsWith("HNVSD")) segment.substring(segment.indexOf("HNSHK"))
|
||||
else segment
|
||||
}
|
||||
val segmentNumbers = segments.map { segment ->
|
||||
val indexOfFirstSeparator = segment.indexOf(':')
|
||||
val indexOfSecondSeparator = segment.indexOf(':', indexOfFirstSeparator + 1)
|
||||
segment.substring(indexOfFirstSeparator + 1, indexOfSecondSeparator).toInt()
|
||||
}
|
||||
|
||||
return Pair(segments, segmentNumbers)
|
||||
}
|
||||
|
||||
private fun createRandomMessage(index: Int, context: JobContext, account: AccountData = bank.accounts.first()): MessageBuilderResult = when (index % 14) {
|
||||
0 -> underTest.createAnonymousDialogInitMessage(context)
|
||||
2 -> underTest.createInitDialogMessage(context)
|
||||
3 -> underTest.createInitDialogMessageWithoutStrongCustomerAuthentication(context, null)
|
||||
4 -> underTest.createSynchronizeCustomerSystemIdMessage(context)
|
||||
5 -> underTest.createGetTanMediaListMessage(context)
|
||||
6 -> underTest.createChangeTanMediumMessage(context, TanGeneratorTanMedium(TanMediumKlasse.TanGenerator, TanMediumStatus.Aktiv, "", null, null, null, null, null), null, null)
|
||||
7 -> underTest.createGetBalanceMessage(context, account)
|
||||
8 -> underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(bank, account, true))
|
||||
9 -> underTest.createGetTransactionsMessage(context, GetAccountTransactionsParameter(bank, bank.accounts[1], true))
|
||||
10 -> underTest.createBankTransferMessage(context, BankTransferData("", "", "", Money.Zero, null), account)
|
||||
11 -> underTest.createBankTransferMessage(context, BankTransferData("", "", "", Money.Zero, null, true), account)
|
||||
12 -> underTest.createSendEnteredTanMessage(context, "", TanResponse(TanProcess.TanProcess2, null, null, null, null, null, null, "HITAN:5:6:4+4++4937-10-13-02.30.03.700259+Sie möchten eine \"Umsatzabfrage\" freigeben?: Bitte bestätigen Sie den \"Startcode 80085335\" mit der Taste \"OK\".+@12@100880085335++Kartennummer ******0892"))
|
||||
13 -> underTest.createDialogEndMessage(context)
|
||||
else -> underTest.createAnonymousDialogEndMessage(context)
|
||||
}
|
||||
|
||||
|
||||
private fun createBankWithAllFeatures(): BankData {
|
||||
val getTransactionsJob = RetrieveAccountTransactionsParameters(JobParameters(CustomerSegmentId.AccountTransactionsMt940.id, 1, 1, null, "HIKAZS:73:5"), 180, true, false)
|
||||
val changeTanMediumJob = createAllowedJob(CustomerSegmentId.ChangeTanMedium, 3)
|
||||
bank.supportedJobs = listOf(
|
||||
getTransactionsJob,
|
||||
createAllowedJob(CustomerSegmentId.TanMediaList, 5), changeTanMediumJob,
|
||||
createAllowedJob(CustomerSegmentId.Balance, 7),
|
||||
createAllowedJob(CustomerSegmentId.CreditCardTransactions, 2),
|
||||
SepaAccountInfoParameters(createAllowedJob(CustomerSegmentId.SepaBankTransfer, 1), true, true, true, true, 35, listOf("pain.001.001.03")),
|
||||
SepaAccountInfoParameters(createAllowedJob(CustomerSegmentId.SepaRealTimeTransfer, 1), true, true, true, true, 35, listOf("pain.001.001.03")),
|
||||
)
|
||||
bank.pinInfo = PinInfo(getTransactionsJob, null, null, null, null, null, listOf(
|
||||
JobTanConfiguration(CustomerSegmentId.Balance.id, true),
|
||||
JobTanConfiguration(CustomerSegmentId.AccountTransactionsMt940.id, true),
|
||||
JobTanConfiguration(CustomerSegmentId.CreditCardTransactions.id, true),
|
||||
JobTanConfiguration(CustomerSegmentId.SepaBankTransfer.id, true),
|
||||
JobTanConfiguration(CustomerSegmentId.SepaRealTimeTransfer.id, true)
|
||||
))
|
||||
bank.changeTanMediumParameters = ChangeTanMediaParameters(changeTanMediumJob, false, false, false, false, false, listOf())
|
||||
|
||||
val checkingAccount = AccountData(CustomerId, null, BankCountryCode, BankCode, "ABCDDEBBXXX", CustomerId, AccountType.Girokonto, "EUR", "", null, null, bank.supportedJobs.map { it.jobName }, bank.supportedJobs)
|
||||
bank.addAccount(checkingAccount)
|
||||
|
||||
val creditCardAccountJobs = bank.supportedJobs.filterNot { it.jobName == CustomerSegmentId.AccountTransactionsMt940.id }
|
||||
val creditCardAccount = AccountData(CustomerId + "_CreditCard", null, BankCountryCode, BankCode, "ABCDDEBBXXX", CustomerId, AccountType.Kreditkartenkonto, "EUR", "", null, null, creditCardAccountJobs.map { it.jobName }, creditCardAccountJobs)
|
||||
bank.addAccount(creditCardAccount)
|
||||
|
||||
return bank
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue