Copilot commented on code in PR #7831:
URL: https://github.com/apache/texera/pull/7831#discussion_r3835553682
##########
common/workflow-core/src/test/scala/org/apache/texera/amber/core/storage/model/LakeFSFileDocumentSpec.scala:
##########
@@ -37,6 +74,126 @@ class LakeFSFileDocumentSpec extends AnyFlatSpec with
Matchers {
// URI parsing is shared by every resource type; exercise it through the
dataset type.
private def datasetDoc(uri: URI) = new LakeFSFileDocument(uri,
ResourceType.Dataset)
+ //
-----------------------------------------------------------------------------------------
+ // Loopback stub
+ //
-----------------------------------------------------------------------------------------
+
+ /** One recorded request. Fields are read directly; never destructured in a
`case` pattern. */
+ private case class Hit(method: String, path: String, query: Map[String,
String])
+
+ private val requests = new ConcurrentLinkedQueue[Hit]()
+ private var server: HttpServer = _
+ private var serverPool: ExecutorService = _
+
+ /** Request paths that should answer 500 instead of being served, for this
one test. */
+ @volatile private var failing: Set[String] = Set.empty
+
+ private val repositoryName = "texera-file-doc"
+ private val fileName = "records.csv"
+ // Most dataset and model files live under a directory, so the read path is
driven over both
+ // shapes: `fileName` at the repository root, and this nested path.
+ //
+ // getFileRelativePath() renders a parsed path with the *platform*
separator, so every expectation
+ // over a multi-segment path — here and in the URI block above — is derived
through Paths.get
+ // exactly as production renders it. Spelling out a literal
"nested/dir/records.csv" instead would
+ // assert a normalization the class does not do (it would fail on Windows
today), not a choice the
+ // class makes.
+ private val nestedSegments = Seq("nested", "dir", fileName)
+
+ private def statPath =
s"/api/v1/repositories/$repositoryName/refs/$versionHash/objects/stat"
+ private def objectPath =
s"/api/v1/repositories/$repositoryName/refs/$versionHash/objects"
+ private def presignedPath = "/signed-blob/records.csv"
+
+ // Longer than asFile's 1024-byte copy buffer and not a multiple of it (2502
bytes), so the copy
+ // loop runs several times and ends on a short read that must not be padded
out to a full buffer.
+ private val presignedContent: String = "presigned-payload;" * 139
+ // Deliberately different bytes, and a different length, from the presigned
payload.
+ private val fallbackContent: String = "direct-lakefs-download"
+
+ private def presignedUrl: String =
+ s"http://127.0.0.1:${server.getAddress.getPort}$presignedPath"
+
+ private def objectStatsJson: String =
+
s"""{"path":"$fileName","path_type":"object","physical_address":"$presignedUrl",
+
|"checksum":"chk","mtime":1700000000,"size_bytes":${presignedContent.length}}""".stripMargin
+
+ private def handle(exchange: HttpExchange): Unit = {
+ try {
+ val uri = exchange.getRequestURI
+ val query = Option(uri.getRawQuery)
+ .filter(_.nonEmpty)
+ .map(_.split("&").toList.map { pair =>
+ def dec(s: String) = URLDecoder.decode(s,
StandardCharsets.UTF_8.name())
+ pair.indexOf('=') match {
+ case -1 => dec(pair) -> ""
+ case i => dec(pair.substring(0, i)) -> dec(pair.substring(i + 1))
+ }
+ }.toMap)
+ .getOrElse(Map.empty[String, String])
+ requests.add(Hit(exchange.getRequestMethod, uri.getPath, query))
+
+ val (status, body) =
+ if (failing.contains(uri.getPath)) (500, """{"message":"stubbed
failure"}""")
+ else
+ uri.getPath match {
+ case p if p == statPath => (200, objectStatsJson)
+ case p if p == presignedPath => (200, presignedContent)
+ case p if p == objectPath => (200, fallbackContent)
+ case p => (501, s"""{"message":"no stub
route for $p"}""")
+ }
+
+ val bytes = body.getBytes(StandardCharsets.UTF_8)
+ exchange.getResponseHeaders.set("Content-Type", "application/json")
+ exchange.sendResponseHeaders(status, bytes.length.toLong)
+ exchange.getResponseBody.write(bytes)
Review Comment:
The loopback stub always sets `Content-Type: application/json`, but the
`presignedPath` and direct `objects` download routes return raw bytes (not
JSON). Using a binary content type makes the stub closer to real
lakeFS/object-store responses and avoids accidentally relying on JSON content
handling in the HTTP client.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]