You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@texera.apache.org by gi...@apache.org on 2026/07/31 18:44:06 UTC
(texera) 01/01: test(amber): cover AI assistant initialization (#7156)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-7156-24a20c8e4b6f876082be35f6f5fba4833a122de8
in repository https://gitbox.apache.org/repos/asf/texera.git
commit e6b000ec93214d0a8a9db644081e32bec6b91286
Author: Xinyuan Lin <xi...@uci.edu>
AuthorDate: Fri Jul 31 11:43:43 2026 -0700
test(amber): cover AI assistant initialization (#7156)
### What changes were proposed in this PR?
Adds focused unit coverage for the OpenAI assistant handshake: a
successful local `/models` response verifies the GET request and
normalized bearer key, while non-success and malformed-URL paths verify
the fallback result.
### Any related issues, documentation, discussions?
Closes #7152
### How was this PR tested?
- `WorkflowExecutionService/testOnly
org.apache.texera.web.resource.aiassistant.AiAssistantManagerSpec` — 3
succeeded.
- `WorkflowExecutionService/Test/scalafmtCheck` and
`WorkflowExecutionService/Test/scalafix --check`.
Mutation proof:
| Production mutation | Result |
| --- | --- |
| Changed the HTTP method from `GET` to `POST` | 1 test failed |
| Reversed the `responseCode == 200` condition | 2 tests failed |
| Returned `OpenAI` from the exception fallback | 1 test failed |
Each mutation was reverted before the final green test run.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Codex (GPT-5)
---
.../aiassistant/AiAssistantManagerSpec.scala | 102 +++++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/amber/src/test/scala/org/apache/texera/web/resource/aiassistant/AiAssistantManagerSpec.scala b/amber/src/test/scala/org/apache/texera/web/resource/aiassistant/AiAssistantManagerSpec.scala
new file mode 100644
index 0000000000..a14b5a4b11
--- /dev/null
+++ b/amber/src/test/scala/org/apache/texera/web/resource/aiassistant/AiAssistantManagerSpec.scala
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.texera.web.resource.aiassistant
+
+import com.sun.net.httpserver.{HttpExchange, HttpHandler, HttpServer}
+import org.scalatest.PrivateMethodTester
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+import java.net.InetSocketAddress
+import java.util.concurrent.atomic.AtomicReference
+
+class AiAssistantManagerSpec extends AnyFlatSpec with Matchers with PrivateMethodTester {
+
+ private val initOpenAI = PrivateMethod[String](Symbol("initOpenAI"))
+
+ private def initializeOpenAI(): String = AiAssistantManager invokePrivate initOpenAI()
+
+ private def withAssistantConfiguration[T](
+ accountKey: String,
+ sharedUrl: String
+ )(test: => T): T = {
+ val originalAccountKey = AiAssistantManager.accountKey
+ val originalSharedUrl = AiAssistantManager.sharedUrl
+ AiAssistantManager.accountKey = accountKey
+ AiAssistantManager.sharedUrl = sharedUrl
+ try {
+ test
+ } finally {
+ AiAssistantManager.accountKey = originalAccountKey
+ AiAssistantManager.sharedUrl = originalSharedUrl
+ }
+ }
+
+ private def withModelsServer(statusCode: Int)(
+ test: (String, AtomicReference[String], AtomicReference[String]) => Unit
+ ): Unit = {
+ val requestMethod = new AtomicReference[String]()
+ val authorization = new AtomicReference[String]()
+ val server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0)
+ server.createContext(
+ "/models",
+ new HttpHandler {
+ override def handle(exchange: HttpExchange): Unit = {
+ requestMethod.set(exchange.getRequestMethod)
+ authorization.set(exchange.getRequestHeaders.getFirst("Authorization"))
+ exchange.sendResponseHeaders(statusCode, -1)
+ exchange.close()
+ }
+ }
+ )
+ server.start()
+ try {
+ val serverUrl = s"http://127.0.0.1:${server.getAddress.getPort}"
+ test(serverUrl, requestMethod, authorization)
+ } finally {
+ server.stop(0)
+ }
+ }
+
+ "initOpenAI" should "accept a successful models response with a normalized bearer key" in {
+ withModelsServer(200) { (serverUrl, requestMethod, authorization) =>
+ withAssistantConfiguration(" \"test-key\" ", serverUrl) {
+ initializeOpenAI() shouldBe "OpenAI"
+ }
+
+ requestMethod.get() shouldBe "GET"
+ authorization.get() shouldBe "Bearer test-key"
+ }
+ }
+
+ it should "reject a non-successful models response" in {
+ withModelsServer(503) { (serverUrl, _, _) =>
+ withAssistantConfiguration("test-key", serverUrl) {
+ initializeOpenAI() shouldBe "NoAiAssistant"
+ }
+ }
+ }
+
+ it should "fall back when the configured service URL is malformed" in {
+ withAssistantConfiguration("test-key", "not a valid URL") {
+ initializeOpenAI() shouldBe "NoAiAssistant"
+ }
+ }
+}