This is an automated email from the ASF dual-hosted git repository.
Yicong-Huang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/texera.git
The following commit(s) were added to refs/heads/main by this push:
new cb2f375bb9 test(workflow-core): add unit test coverage for
VFSURIFactory (#4757)
cb2f375bb9 is described below
commit cb2f375bb90966eb3fde08bfab0abce2ef15db98
Author: Xinyuan Lin <[email protected]>
AuthorDate: Sun May 3 00:09:29 2026 -0700
test(workflow-core): add unit test coverage for VFSURIFactory (#4757)
### What changes were proposed in this PR?
Add `VFSURIFactorySpec` covering URI construction and decoding in
`VFSURIFactory`:
- `createResultURI` includes wid/eid/globalportid and the result
resource type
- Result URIs round-trip through `decodeURI`
- `createRuntimeStatisticsURI` omits the `opid/` segment
- `createConsoleMessagesURI` embeds the operator id and the
`consoleMessages` resource type
- `decodeURI` rejects non-vfs schemes, URIs missing required segments,
and unknown resource-type tails
### Any related issues, documentation, discussions?
Closes #4756
### How was this PR tested?
`sbt "WorkflowCore/testOnly
org.apache.texera.amber.core.storage.VFSURIFactorySpec"` — 7/7 tests
pass.
### Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 4.7)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
.../amber/core/storage/VFSURIFactorySpec.scala | 109 +++++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git
a/common/workflow-core/src/test/scala/org/apache/texera/amber/core/storage/VFSURIFactorySpec.scala
b/common/workflow-core/src/test/scala/org/apache/texera/amber/core/storage/VFSURIFactorySpec.scala
new file mode 100644
index 0000000000..6fbe35873a
--- /dev/null
+++
b/common/workflow-core/src/test/scala/org/apache/texera/amber/core/storage/VFSURIFactorySpec.scala
@@ -0,0 +1,109 @@
+/*
+ * 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.amber.core.storage
+
+import org.apache.texera.amber.core.virtualidentity.{
+ ExecutionIdentity,
+ OperatorIdentity,
+ PhysicalOpIdentity,
+ WorkflowIdentity
+}
+import org.apache.texera.amber.core.workflow.{GlobalPortIdentity, PortIdentity}
+import org.scalatest.flatspec.AnyFlatSpec
+
+import java.net.URI
+
+class VFSURIFactorySpec extends AnyFlatSpec {
+
+ private val workflowId = WorkflowIdentity(7L)
+ private val executionId = ExecutionIdentity(11L)
+ private val operatorId = OperatorIdentity("opA")
+ private val portId =
+ GlobalPortIdentity(
+ PhysicalOpIdentity(operatorId, "main"),
+ PortIdentity(0),
+ input = true
+ )
+
+ "VFSURIFactory.createResultURI" should "include workflow, execution, port,
and the result resource type" in {
+ val uri = VFSURIFactory.createResultURI(workflowId, executionId, portId)
+ assert(uri.getScheme == VFSURIFactory.VFS_FILE_URI_SCHEME)
+ val path = uri.getPath
+ assert(path.contains("/wid/7"))
+ assert(path.contains("/eid/11"))
+ assert(path.contains("/globalportid/"))
+ assert(path.endsWith("/result"))
+ }
+
+ it should "round-trip through decodeURI" in {
+ val uri = VFSURIFactory.createResultURI(workflowId, executionId, portId)
+ val (wid, eid, globalPortIdOpt, resourceType) =
VFSURIFactory.decodeURI(uri)
+ assert(wid == workflowId)
+ assert(eid == executionId)
+ assert(globalPortIdOpt.contains(portId))
+ assert(resourceType == VFSResourceType.RESULT)
+ }
+
+ "VFSURIFactory.createRuntimeStatisticsURI" should "produce a
runtimeStatistics URI without an opid segment" in {
+ val uri = VFSURIFactory.createRuntimeStatisticsURI(workflowId, executionId)
+ val path = uri.getPath
+ assert(path.endsWith("/runtimestatistics"))
+ assert(!path.contains("/opid/"))
+
+ val (wid, eid, globalPortIdOpt, resourceType) =
VFSURIFactory.decodeURI(uri)
+ assert(wid == workflowId)
+ assert(eid == executionId)
+ assert(globalPortIdOpt.isEmpty)
+ assert(resourceType == VFSResourceType.RUNTIME_STATISTICS)
+ }
+
+ "VFSURIFactory.createConsoleMessagesURI" should "embed the operator id and
the consoleMessages resource type" in {
+ val uri = VFSURIFactory.createConsoleMessagesURI(workflowId, executionId,
operatorId)
+ val path = uri.getPath
+ assert(path.contains(s"/opid/${operatorId.id}"))
+ assert(path.endsWith("/consolemessages"))
+
+ // The current `decodeURI` does not extract the operator id (it has no
+ // "opid" branch), so we only round-trip wid/eid/resourceType here.
+ val (wid, eid, globalPortIdOpt, resourceType) =
VFSURIFactory.decodeURI(uri)
+ assert(wid == workflowId)
+ assert(eid == executionId)
+ assert(globalPortIdOpt.isEmpty)
+ assert(resourceType == VFSResourceType.CONSOLE_MESSAGES)
+ }
+
+ "VFSURIFactory.decodeURI" should "reject URIs with a non-vfs scheme" in {
+ assertThrows[IllegalArgumentException] {
+ VFSURIFactory.decodeURI(new URI("http:///wid/1/eid/1/result"))
+ }
+ }
+
+ it should "reject URIs missing required segments" in {
+ assertThrows[IllegalArgumentException] {
+ VFSURIFactory.decodeURI(new URI("vfs:///wid/1/result"))
+ }
+ }
+
+ it should "reject URIs whose final segment is not a known resource type" in {
+ assertThrows[IllegalArgumentException] {
+ VFSURIFactory.decodeURI(new URI("vfs:///wid/1/eid/2/notarealresource"))
+ }
+ }
+}