From 70286cfd6bf3712a1eded750fcc5e84ca8f1192e Mon Sep 17 00:00:00 2001 From: hongwei Date: Fri, 30 Jan 2026 12:22:48 +0100 Subject: [PATCH] Enhance Http4sLiftBridgeParityTest with DirectLogin scenarios Add test user and consumer setup in beforeAll for DirectLogin testing. Introduce new scenarios to validate DirectLogin behavior with and without authentication headers, ensuring consistent response codes and token presence across Http4s and Lift implementations. This improves test coverage and aligns with the ongoing efforts for contract parity. --- .../v5_0_0/Http4sLiftBridgeParityTest.scala | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/obp-api/src/test/scala/code/api/v5_0_0/Http4sLiftBridgeParityTest.scala b/obp-api/src/test/scala/code/api/v5_0_0/Http4sLiftBridgeParityTest.scala index 08518d818..690a8befc 100644 --- a/obp-api/src/test/scala/code/api/v5_0_0/Http4sLiftBridgeParityTest.scala +++ b/obp-api/src/test/scala/code/api/v5_0_0/Http4sLiftBridgeParityTest.scala @@ -6,15 +6,55 @@ import code.api.ResponseHeader import code.api.berlin.group.ConstantsBG import code.api.util.APIUtil.OAuth._ import code.api.util.http4s.Http4sLiftWebBridge +import code.consumer.Consumers +import code.model.dataAccess.AuthUser import net.liftweb.json.JValue import net.liftweb.json.JsonAST.JObject import net.liftweb.json.JsonParser.parse +import net.liftweb.mapper.By +import net.liftweb.util.Helpers._ import org.http4s.{Header, Headers, Method, Request, Status, Uri} import org.scalatest.Tag import org.typelevel.ci.CIString class Http4sLiftBridgeParityTest extends V500ServerSetup { + // Create a test user with known password for DirectLogin testing + private val testUsername = "http4s_bridge_test_user" + private val testPassword = "TestPassword123!" + private val testConsumerKey = randomString(40).toLowerCase + private val testConsumerSecret = randomString(40).toLowerCase + + override def beforeAll(): Unit = { + super.beforeAll() + + // Create AuthUser if not exists + if (AuthUser.find(By(AuthUser.username, testUsername)).isEmpty) { + AuthUser.create + .email(s"$testUsername@test.com") + .username(testUsername) + .password(testPassword) + .validated(true) + .firstName("Http4s") + .lastName("TestUser") + .saveMe + } + + // Create Consumer if not exists + if (Consumers.consumers.vend.getConsumerByConsumerKey(testConsumerKey).isEmpty) { + Consumers.consumers.vend.createConsumer( + Some(testConsumerKey), + Some(testConsumerSecret), + Some(true), + Some("http4s bridge test app"), + None, + Some("test application for http4s bridge parity"), + Some(s"$testUsername@test.com"), + None, None, None, None, None + ) + } + } + object Http4sLiftBridgeParityTag extends Tag("Http4sLiftBridgeParity") private val http4sRoutes = Http4sLiftWebBridge.withStandardHeaders(Http4sLiftWebBridge.routes).orNotFound @@ -94,7 +134,7 @@ class Http4sLiftBridgeParityTest extends V500ServerSetup { assertCorrelationId(http4sHeaders) } - scenario("DirectLogin parity", Http4sLiftBridgeParityTag) { + scenario("DirectLogin parity - missing auth header", Http4sLiftBridgeParityTag) { val liftReq = (baseRequest / "my" / "logins" / "direct").POST val liftResponse = makePostRequest(liftReq, "") val reqData = extractParamsAndHeaders(liftReq, "", "") @@ -104,5 +144,39 @@ class Http4sLiftBridgeParityTest extends V500ServerSetup { (hasField(http4sJson, "error") || hasField(http4sJson, "message")) shouldBe true assertCorrelationId(http4sHeaders) } + + scenario("DirectLogin parity - with valid credentials returns 201", Http4sLiftBridgeParityTag) { + // Use the test user with known password created in beforeAll + val directLoginHeader = s"""DirectLogin username="$testUsername", password="$testPassword", consumer_key="$testConsumerKey"""" + + val liftReq = (baseRequest / "my" / "logins" / "direct").POST + .setHeader("Authorization", directLoginHeader) + .setHeader("Content-Type", "application/json") + + val liftResponse = makePostRequest(liftReq, "") + + val reqData = ReqData( + url = s"http://${server.host}:${server.port}/my/logins/direct", + method = "POST", + body = "", + body_encoding = "UTF-8", + headers = Map( + "Authorization" -> directLoginHeader, + "Content-Type" -> "application/json" + ), + query_params = Map.empty, + form_params = Map.empty + ) + val (http4sStatus, http4sJson, http4sHeaders) = runHttp4s(reqData) + + // Both should return 201 Created + liftResponse.code should equal(201) + http4sStatus.code should equal(201) + liftResponse.code should equal(http4sStatus.code) + + // Both should have a token field + hasField(http4sJson, "token") shouldBe true + assertCorrelationId(http4sHeaders) + } } }