commit b33d4324adecad7d3ffbcefda12e7e2791ab1151
parent 5e1baab1cc6509e2115941586ccd3b34996bb072
Author: MS <ms@taler.net>
Date: Mon, 5 Dec 2022 20:35:36 +0100
Some legacy API tests.
Diffstat:
4 files changed, 318 insertions(+), 77 deletions(-)
diff --git a/nexus/build.gradle b/nexus/build.gradle
@@ -89,6 +89,7 @@ dependencies {
// Ktor, an HTTP client and server library
implementation "io.ktor:ktor-server-core:$ktor_version"
implementation "io.ktor:ktor-client-apache:$ktor_version"
+ implementation "io.ktor:ktor-client-auth:$ktor_version"
implementation "io.ktor:ktor-server-netty:$ktor_version"
implementation "io.ktor:ktor-server-test-host:$ktor_version"
implementation "io.ktor:ktor-auth:$ktor_version"
@@ -101,18 +102,26 @@ dependencies {
implementation 'com.cronutils:cron-utils:9.1.5'
// Unit testing
- testImplementation 'junit:junit:4.13.2'
+ // testImplementation 'junit:junit:4.13.2'
+ // From https://docs.gradle.org/current/userguide/java_testing.html#sec:java_testing_basics:
+ testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
testImplementation 'org.jetbrains.kotlin:kotlin-test:1.5.21'
testImplementation 'org.jetbrains.kotlin:kotlin-test-junit:1.5.21'
}
+test {
+ useJUnit()
+ failFast = true
+ testLogging.showStandardStreams = false
+ environment.put("LIBEUFIN_SANDBOX_ADMIN_PASSWORD", "foo")
+}
+
application {
mainClassName = "tech.libeufin.nexus.MainKt"
applicationName = "libeufin-nexus"
applicationDefaultJvmArgs = ['-Djava.net.preferIPv6Addresses=true']
}
-
jar {
manifest {
attributes "Main-Class": "tech.libeufin.nexus.MainKt"
diff --git a/nexus/src/test/kotlin/DownloadAndSubmit.kt b/nexus/src/test/kotlin/DownloadAndSubmit.kt
@@ -187,8 +187,8 @@ class DownloadAndSubmit {
val painMessage = createPain001document(
NexusPaymentInitiationData(
debtorIban = bar!!.iban,
- debtorBic = bar!!.bankCode,
- debtorName = bar!!.accountHolder,
+ debtorBic = bar.bankCode,
+ debtorName = bar.accountHolder,
currency = "TESTKUDOS",
amount = "1",
creditorIban = getIban(),
diff --git a/nexus/src/test/kotlin/SandboxLegacyApiTest.kt b/nexus/src/test/kotlin/SandboxLegacyApiTest.kt
@@ -0,0 +1,304 @@
+import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.databind.util.ByteBufferBackedInputStream
+import io.ktor.client.features.*
+import io.ktor.client.request.*
+import io.ktor.client.statement.HttpResponse
+import io.ktor.http.*
+import io.ktor.server.testing.*
+import io.ktor.util.*
+import io.ktor.utils.io.*
+import io.netty.handler.codec.http.HttpResponseStatus
+import kotlinx.coroutines.runBlocking
+import org.junit.Ignore
+import org.junit.Test
+import tech.libeufin.sandbox.sandboxApp
+import tech.libeufin.util.buildBasicAuthLine
+import tech.libeufin.util.getIban
+import java.io.ByteArrayOutputStream
+import java.io.InputStream
+import java.nio.ByteBuffer
+
+/**
+ * Mostly checking legacy API's access control.
+ */
+class SandboxLegacyApiTest {
+ fun dbHelper (f: () -> Unit) {
+ withTestDatabase {
+ prepSandboxDb()
+ f()
+ }
+ }
+ val mapper = ObjectMapper()
+
+
+ // EBICS Subscribers API.
+ @Test
+ fun adminEbiscSubscribers() {
+ dbHelper {
+ withTestApplication(sandboxApp) {
+ runBlocking {
+ /**
+ * Create a EBICS subscriber. That conflicts because
+ * MakeEnv.kt created it already, but tests access control
+ * and conflict detection.
+ */
+ var body = mapper.writeValueAsString(object {
+ val hostID = "foo"
+ val userID = "foo"
+ val systemID = "foo"
+ val partnerID = "foo"
+ })
+ var r: HttpResponse = client.post("/admin/ebics/subscribers") {
+ expectSuccess = false
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "foo")
+ )
+ append(
+ HttpHeaders.ContentType,
+ ContentType.Application.Json
+ )
+ }
+ this.body = body
+ }
+ assert(r.status.value == HttpStatusCode.Conflict.value)
+ /**
+ * Check that EBICS subscriber indeed exists.
+ */
+ r = client.get("/admin/ebics/subscribers") {
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "foo")
+ )
+ }
+ }
+ assert(r.status.value == HttpStatusCode.OK.value)
+ val buf = ByteArrayOutputStream()
+ r.content.read { buf.write(it.array()) }
+ val respObj = mapper.readTree(buf.toString())
+ assert("foo" == respObj.get("subscribers").get(0).get("userID").asText())
+ /**
+ * Try same operations as above, with wrong admin credentials
+ */
+ r = client.get("/admin/ebics/subscribers") {
+ expectSuccess = false
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "wrong")
+ )
+ }
+ }
+ assert(r.status.value == HttpStatusCode.Unauthorized.value)
+ r = client.post("/admin/ebics/subscribers") {
+ expectSuccess = false
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "wrong")
+ )
+ }
+ }
+ assert(r.status.value == HttpStatusCode.Unauthorized.value)
+ // Good credentials, but unauthorized user.
+ r = client.get("/admin/ebics/subscribers") {
+ expectSuccess = false
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("foo", "foo")
+ )
+ }
+ }
+ assert(r.status.value == HttpStatusCode.Unauthorized.value)
+ r = client.post("/admin/ebics/subscribers") {
+ expectSuccess = false
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("foo", "foo")
+ )
+ }
+ }
+ assert(r.status.value == HttpStatusCode.Unauthorized.value)
+ /**
+ * Give a bank account to the existing subscriber. Bank account
+ * is (implicitly / hard-coded) hosted at default demobank.
+ */
+ // Create new subscriber. No need to have the related customer.
+ body = mapper.writeValueAsString(object {
+ val hostID = "eufinSandbox"
+ val userID = "baz"
+ val partnerID = "baz"
+ val systemID = "foo"
+ })
+ client.post<HttpResponse>("/admin/ebics/subscribers") {
+ expectSuccess = true
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "foo")
+ )
+ append(
+ HttpHeaders.ContentType,
+ ContentType.Application.Json
+ )
+ }
+ this.body = body
+ }
+ // Associate new bank account to it.
+ body = mapper.writeValueAsString(object {
+ val subscriber = object {
+ val userID = "baz"
+ val partnerID = "baz"
+ val systemID = "baz"
+ val hostID = "eufinSandbox"
+ }
+ val iban = getIban()
+ val bic = "SANDBOXX"
+ val name = "Now Have Account"
+ val label = "baz"
+ val owner = "baz"
+ })
+ client.post<HttpResponse>("/admin/ebics/bank-accounts") {
+ expectSuccess = true
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "foo")
+ )
+ append(
+ HttpHeaders.ContentType,
+ ContentType.Application.Json
+ )
+ }
+ this.body = body
+ }
+ r = client.get("/admin/ebics/subscribers") {
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "foo")
+ )
+ }
+ }
+ assert(r.status.value == HttpStatusCode.OK.value)
+ val buf_ = ByteArrayOutputStream()
+ r.content.read { buf_.write(it.array()) }
+ val respObj_ = mapper.readTree(buf_.toString())
+ val bankAccountLabel = respObj_.get("subscribers").get(1).get("demobankAccountLabel").asText()
+ assert("baz" == bankAccountLabel)
+ // Same operation, wrong/unauth credentials.
+ r = client.post("/admin/ebics/bank-accounts") {
+ expectSuccess = false
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "wrong")
+ )
+ }
+ }
+ assert(r.status.value == HttpStatusCode.Unauthorized.value)
+ r = client.post("/admin/ebics/bank-accounts") {
+ expectSuccess = false
+ headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("foo", "foo")
+ )
+ }
+ }
+ assert(r.status.value == HttpStatusCode.Unauthorized.value)
+ }
+ }
+ }
+ }
+
+ // EBICS Hosts API.
+ @Ignore
+ fun adminEbicsCreateHost() {
+ dbHelper {
+ withTestApplication(sandboxApp) {
+ runBlocking {
+ val body = mapper.writeValueAsString(
+ object {
+ val hostID = "www"
+ var ebicsVersion = "www"
+ }
+ )
+ // Valid request, good credentials.
+ var r = client.post<HttpResponse>("/admin/ebics/hosts") {
+ this.body = body
+ this.headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "foo")
+ )
+ append(
+ HttpHeaders.ContentType,
+ ContentType.Application.Json
+ )
+ }
+ }
+ assert(r.status.value == HttpResponseStatus.OK.code())
+ r = client.get("/admin/ebics/hosts") {
+ expectSuccess = false
+
+ }
+ assert(r.status.value == HttpResponseStatus.UNAUTHORIZED.code())
+ r = client.get("/admin/ebics/hosts") {
+ this.headers {
+ append(
+ HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "foo")
+ )
+ }
+ }
+ assert(r.status.value == HttpResponseStatus.OK.code())
+ // Invalid, with good credentials.
+ r = client.post("/admin/ebics/hosts") {
+ expectSuccess = false
+ this.body = "invalid"
+ this.headers {
+ append(
+ io.ktor.http.HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "foo")
+ )
+ append(
+ io.ktor.http.HttpHeaders.ContentType,
+ ContentType.Application.Json
+ )
+ }
+ }
+ assert(r.status.value == HttpResponseStatus.BAD_REQUEST.code())
+ // Unauth: admin with wrong password.
+ r = client.post("/admin/ebics/hosts") {
+ expectSuccess = false
+ this.headers {
+ append(
+ io.ktor.http.HttpHeaders.Authorization,
+ buildBasicAuthLine("admin", "bar")
+ )
+ }
+ }
+ assert(r.status.value == HttpResponseStatus.UNAUTHORIZED.code())
+ // Auth & forbidden resource.
+ r = client.post("/admin/ebics/hosts") {
+ expectSuccess = false
+ this.headers {
+ append(
+ io.ktor.http.HttpHeaders.Authorization,
+ // Exist, but no rights over the EBICS host.
+ buildBasicAuthLine("foo", "foo")
+ )
+ }
+ }
+ assert(r.status.value == HttpResponseStatus.UNAUTHORIZED.code())
+ }
+ }
+ }
+ }
+}
+\ No newline at end of file
diff --git a/nexus/src/test/kotlin/SelfContainedDBTest.kt b/nexus/src/test/kotlin/SelfContainedDBTest.kt
@@ -1,72 +0,0 @@
-import org.jetbrains.exposed.dao.Entity
-import org.jetbrains.exposed.dao.EntityClass
-import org.jetbrains.exposed.dao.IntEntity
-import org.jetbrains.exposed.dao.IntEntityClass
-import org.jetbrains.exposed.dao.id.EntityID
-import org.jetbrains.exposed.dao.id.IdTable
-import org.jetbrains.exposed.dao.id.IntIdTable
-import org.jetbrains.exposed.sql.Database
-import org.jetbrains.exposed.sql.SchemaUtils
-import org.jetbrains.exposed.sql.StdOutSqlLogger
-import org.jetbrains.exposed.sql.addLogger
-import org.jetbrains.exposed.sql.transactions.transaction
-import org.junit.Test
-import java.io.File
-
-object ContainedTableWithIntId : IntIdTable() {
- val column = text("column")
-}
-class ContainedEntityWithIntId(id: EntityID<Int>) : IntEntity(id) {
- companion object : IntEntityClass<ContainedEntityWithIntId>(ContainedTableWithIntId)
- var column by ContainedTableWithIntId.column
-}
-
-object ContainedTableWithStringId : IdTable<String>() {
- override val id = varchar("id", 10).entityId()
- override val primaryKey = PrimaryKey(id, name = "id")
- val column = text("column")
-
-}
-class ContainedEntityWithStringId(id: EntityID<String>) : Entity<String>(id) {
- companion object : EntityClass<String, ContainedEntityWithStringId>(ContainedTableWithStringId)
- var column by ContainedTableWithStringId.column
-}
-
-object ContainingTable : IdTable<String>() {
- override val id = varchar("id", 10).entityId()
- override val primaryKey = PrimaryKey(id, name = "id")
- val referenceStringId = reference("referenceStringId", ContainedTableWithStringId)
- val referenceIntId = reference("referenceIntId", ContainedTableWithIntId)
-}
-class ContainingEntity(id: EntityID<String>) : Entity<String>(id) {
- companion object : EntityClass<String, ContainingEntity>(ContainingTable)
- var referenceStringId by ContainedEntityWithStringId referencedOn ContainingTable.referenceStringId
- var referenceIntId by ContainedEntityWithIntId referencedOn ContainingTable.referenceIntId
-}
-
-class DBTest {
- @Test
- fun facadeConfigTest() {
- withTestDatabase {
- transaction {
- addLogger(StdOutSqlLogger)
- SchemaUtils.create(
- ContainingTable,
- ContainedTableWithIntId,
- ContainedTableWithStringId
- )
- val entityWithIntId = ContainedEntityWithIntId.new {
- column = "value"
- }
- entityWithIntId.flush()
- val entityWithStringId = ContainedEntityWithStringId.new("contained-id") {
- column = "another value"
- }
- ContainingEntity.new("containing-id") {
- referenceIntId = entityWithIntId
- referenceStringId = entityWithStringId
- }
- }
- }
- }
-}
-\ No newline at end of file