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-7305-ad638ae035579025f48697089ad9bbc3a50d2c08 in repository https://gitbox.apache.org/repos/asf/texera.git
commit ae1d1d88e6d6a3f3559eb6512a679959da152421 Author: Xinyuan Lin <[email protected]> AuthorDate: Tue Aug 4 17:43:54 2026 -0700 test(amber): cover ProjectResource's colour and per-project workflow APIs (#7305) ### What changes were proposed in this PR? `ProjectResourceSpec` exercised the create / rename / describe / add / remove / delete paths, but three of the resource's methods were never called by it. Six tests for those: **`updateProjectColor`** — the only one with real validation: ```scala if (colorHex == null || colorHex.length != 6 && colorHex.length != 3 || !colorHex.matches(...)) ``` The guard checks length **and** hex-ness, so the rejection test covers both kinds of bad input: a length-only check would let `"GGGGGG"` through, and a regex-only check would let `""` through. It also asserts a rejected update leaves the previously stored colour intact, and that the null check precedes the length read — without it a null colour is an NPE rather than a 400. Both the 3- and 6-digit forms are accepted, and the value is stored verbatim rather than expanded. **`deleteProjectColor`** — clears the value. **`listProjectWorkflows`** — filters by project id. The test seeds **two** projects each holding one workflow, so a filter that ignored the pid would return both and fail; plus a project holding none returns empty. These are additions to the spec's existing `MockTexeraDB` fixture, not new infrastructure. For transparency on scope: `WorkflowVersionResource` (12 missed, 88.4%) was looked at as a companion for this PR and deliberately left out. Every one of its methods is already exercised by its spec, so the residue is branch-level and did not look reachable without padding. No production file is touched. ### Any related issues, documentation, discussions? Closes #7302 ### How was this PR tested? Six new tests, run as the whole spec so the pre-existing cases are proven intact — 16 tests, Java 17: ``` sbt "WorkflowExecutionService/testOnly org.apache.texera.web.resource.dashboard.user.project.ProjectResourceSpec" ``` ``` [info] Tests: succeeded 16, failed 0, canceled 0, ignored 0, pending 0 [info] All tests passed. ``` `Test/scalafmtCheck` and `Test/scalafix --check` both `[success]`. ### Was this PR authored or co-authored using generative AI tooling? Generated-by: Claude Code (Opus 5) --------- Signed-off-by: Xinyuan Lin <[email protected]> Co-authored-by: Copilot Autofix powered by AI <[email protected]> --- .../user/project/ProjectResourceSpec.scala | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/amber/src/test/scala/org/apache/texera/web/resource/dashboard/user/project/ProjectResourceSpec.scala b/amber/src/test/scala/org/apache/texera/web/resource/dashboard/user/project/ProjectResourceSpec.scala index e05a6fb63d..f97d3d4519 100644 --- a/amber/src/test/scala/org/apache/texera/web/resource/dashboard/user/project/ProjectResourceSpec.scala +++ b/amber/src/test/scala/org/apache/texera/web/resource/dashboard/user/project/ProjectResourceSpec.scala @@ -254,6 +254,75 @@ class ProjectResourceSpec workflowOfProjectCount(wid, pid) shouldBe 0 } + it should "accept both 3- and 6-digit hex colours and persist the last one" in { + val pid = resource.createProject(session(owner), "p").getPid + + resource.updateProjectColor(pid, "AABBCC", session(owner)) + resource.getProject(pid).getColor shouldBe "AABBCC" + + // The shorthand form is legal too, and the value is stored verbatim rather than expanded. + resource.updateProjectColor(pid, "f0a", session(owner)) + resource.getProject(pid).getColor shouldBe "f0a" + } + + it should "reject colours that are not 3 or 6 hex digits, leaving the stored one intact" in { + val pid = resource.createProject(session(owner), "p").getPid + resource.updateProjectColor(pid, "123456", session(owner)) + + // Wrong length, and a right-length value with a non-hex digit: this exercises both the + // length and hex-digit validation branches in updateProjectColor. + Seq("12345", "1234567", "GGGGGG", "12G", "").foreach { bad => + withClue(s"colour '$bad': ") { + assertThrows[BadRequestException] { + resource.updateProjectColor(pid, bad, session(owner)) + } + } + } + + resource.getProject(pid).getColor shouldBe "123456" + } + + it should "reject a null colour before dereferencing it" in { + val pid = resource.createProject(session(owner), "p").getPid + + // The null check has to come first; without it the length read is an NPE rather than a 400. + assertThrows[BadRequestException] { + resource.updateProjectColor(pid, null, session(owner)) + } + } + + it should "clear a project's colour" in { + val pid = resource.createProject(session(owner), "p").getPid + resource.updateProjectColor(pid, "ABCDEF", session(owner)) + + resource.deleteProjectColor(pid) + + resource.getProject(pid).getColor shouldBe null + } + + it should "list only the workflows belonging to the given project" in { + val pid = resource.createProject(session(owner), "p").getPid + val other = resource.createProject(session(owner), "other").getPid + val inProject = seedWorkflow(ownerUid) + val elsewhere = seedWorkflow(ownerUid) + resource.addWorkflowToProject(pid, inProject, session(owner)) + resource.addWorkflowToProject(other, elsewhere, session(owner)) + + // Two projects each holding one workflow, so a filter that ignored the pid would return both. + resource.listProjectWorkflows(pid, session(owner)).map(_.workflow.getWid) shouldBe List( + inProject + ) + resource.listProjectWorkflows(other, session(owner)).map(_.workflow.getWid) shouldBe List( + elsewhere + ) + } + + it should "return no workflows for a project that holds none" in { + val pid = resource.createProject(session(owner), "empty").getPid + + resource.listProjectWorkflows(pid, session(owner)) shouldBe empty + } + it should "delete a project" in { val pid = resource.createProject(session(owner), "doomed").getPid resource.getProject(pid) should not be null
