diff --git a/ontrack-ui-graphql/src/main/java/net/nemerosa/ontrack/graphql/support/GraphqlUtils.java b/ontrack-ui-graphql/src/main/java/net/nemerosa/ontrack/graphql/support/GraphqlUtils.java index 61b63977138..725977d7785 100644 --- a/ontrack-ui-graphql/src/main/java/net/nemerosa/ontrack/graphql/support/GraphqlUtils.java +++ b/ontrack-ui-graphql/src/main/java/net/nemerosa/ontrack/graphql/support/GraphqlUtils.java @@ -180,26 +180,6 @@ public static DataFetcher fetcher(Class sourceType, BiFunction stdListArguments() { return Arrays.asList( GraphQLArgument.newArgument() diff --git a/ontrack-ui-graphql/src/test/groovy/net/nemerosa/ontrack/graphql/BranchBuildsFilterQLIT.groovy b/ontrack-ui-graphql/src/test/groovy/net/nemerosa/ontrack/graphql/BranchBuildsFilterQLIT.groovy deleted file mode 100644 index 303bcb1fc1a..00000000000 --- a/ontrack-ui-graphql/src/test/groovy/net/nemerosa/ontrack/graphql/BranchBuildsFilterQLIT.groovy +++ /dev/null @@ -1,356 +0,0 @@ -package net.nemerosa.ontrack.graphql - -import net.nemerosa.ontrack.extension.api.support.TestSimpleProperty -import net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType -import net.nemerosa.ontrack.model.security.BuildConfig -import net.nemerosa.ontrack.model.security.ProjectView -import net.nemerosa.ontrack.model.structure.Signature -import net.nemerosa.ontrack.model.structure.ValidationRunStatusID -import org.junit.Test - -import java.time.LocalDateTime - -import static net.nemerosa.ontrack.model.structure.NameDescription.nd - -class BranchBuildsFilterQLIT extends AbstractQLITSupport { - - @Test - void 'Default filter with validation stamp'() { - def branch = doCreateBranch() - def build = doCreateBuild(branch, nd('1', '')) - doCreateValidationStamp(branch, nd('NONE', '')) - doValidateBuild(build, 'VS', ValidationRunStatusID.STATUS_PASSED) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {withValidationStamp: "VS"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == [build.name] - - data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {withValidationStamp: "NONE"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == [] - } - - @Test - void 'Default filter with validation stamp and returning validation runs'() { - def branch = doCreateBranch() - def build = doCreateBuild(branch, nd('1', '')) - doValidateBuild(build, 'VS', ValidationRunStatusID.STATUS_PASSED) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {withValidationStamp: "VS"}) { - name - validationRuns { - validationRunStatuses { - statusID { - id - } - } - } - } - } - }""") - assert data.branches.first().builds.name.flatten() == [build.name] - assert data.branches.first().builds.validationRuns.validationRunStatuses.statusID.id.flatten() == ['PASSED'] - } - - @Test - void 'Default filter with validation stamp status'() { - def branch = doCreateBranch() - def vs = doCreateValidationStamp(branch, nd('VS', '')) - doValidateBuild(doCreateBuild(branch, nd('1', '')), vs, ValidationRunStatusID.STATUS_FAILED) - doValidateBuild(doCreateBuild(branch, nd('2', '')), vs, ValidationRunStatusID.STATUS_PASSED) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {withValidationStamp: "VS", withValidationStampStatus: "PASSED"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['2'] - } - - @Test - void 'Default filter since validation stamp'() { - def branch = doCreateBranch() - def vs = doCreateValidationStamp(branch, nd('VS', '')) - doValidateBuild(doCreateBuild(branch, nd('1', '')), vs, ValidationRunStatusID.STATUS_PASSED) - doValidateBuild(doCreateBuild(branch, nd('2', '')), vs, ValidationRunStatusID.STATUS_PASSED) - doCreateBuild(branch, nd('3', '')) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {sinceValidationStamp: "VS"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['3', '2'] - } - - @Test - void 'Default filter since validation stamp status'() { - def branch = doCreateBranch() - def vs = doCreateValidationStamp(branch, nd('VS', '')) - doValidateBuild(doCreateBuild(branch, nd('1', '')), vs, ValidationRunStatusID.STATUS_PASSED) - doValidateBuild(doCreateBuild(branch, nd('2', '')), vs, ValidationRunStatusID.STATUS_PASSED) - doValidateBuild(doCreateBuild(branch, nd('3', '')), vs, ValidationRunStatusID.STATUS_FAILED) - doCreateBuild(branch, nd('4', '')) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {sinceValidationStamp: "VS", sinceValidationStampStatus: "PASSED"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['4', '3', '2'] - } - - @Test - void 'Default filter with promotion level'() { - def branch = doCreateBranch() - def copper = doCreatePromotionLevel(branch, nd('COPPER', '')) - doPromote(doCreateBuild(branch, nd('1', '')), copper, '') - doCreateBuild(branch, nd('2', '')) - doPromote(doCreateBuild(branch, nd('3', '')), copper, '') - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {withPromotionLevel: "COPPER"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['3', '1'] - } - - @Test - void 'Default filter since promotion level'() { - def branch = doCreateBranch() - def copper = doCreatePromotionLevel(branch, nd('COPPER', '')) - doPromote(doCreateBuild(branch, nd('1', '')), copper, '') - doCreateBuild(branch, nd('2', '')) - doPromote(doCreateBuild(branch, nd('3', '')), copper, '') - doCreateBuild(branch, nd('4', '')) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {sincePromotionLevel: "COPPER"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['4', '3'] - } - - @Test - void 'Default filter since and with promotion level'() { - def branch = doCreateBranch() - def copper = doCreatePromotionLevel(branch, nd('COPPER', '')) - def bronze = doCreatePromotionLevel(branch, nd('BRONZE', '')) - - doCreateBuild(branch, nd('1', '')) - def build2 = doCreateBuild(branch, nd('2', '')) - doPromote(build2, copper, '') - doPromote(build2, bronze, '') - doCreateBuild(branch, nd('3', '')) - doPromote(doCreateBuild(branch, nd('4', '')), copper, '') - doCreateBuild(branch, nd('5', '')) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {sincePromotionLevel: "BRONZE", withPromotionLevel: "COPPER"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['4', '2'] - } - - @Test - void 'Default filter dates'() { - def branch = doCreateBranch() - doCreateBuild(branch, nd('1', ''), Signature.of(LocalDateTime.of(2016, 11, 30, 17, 00), 'test')) - doCreateBuild(branch, nd('2', ''), Signature.of(LocalDateTime.of(2016, 12, 02, 17, 10), 'test')) - doCreateBuild(branch, nd('3', ''), Signature.of(LocalDateTime.of(2016, 12, 04, 17, 20), 'test')) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {afterDate: "2016-12-01", beforeDate: "2016-12-03"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['2'] - } - - @Test - void 'Default filter with property'() { - def branch = doCreateBranch() - doSetProperty(doCreateBuild(branch, nd('1', '')), TestSimplePropertyType, new TestSimpleProperty("1")) - doCreateBuild(branch, nd('2', '')) - doSetProperty(doCreateBuild(branch, nd('3', '')), TestSimplePropertyType, new TestSimpleProperty("3")) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {withProperty: "net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['3', '1'] - } - - @Test - void 'Default filter with property value'() { - def branch = doCreateBranch() - doSetProperty(doCreateBuild(branch, nd('1', '')), TestSimplePropertyType, new TestSimpleProperty("1")) - doCreateBuild(branch, nd('2', '')) - doSetProperty(doCreateBuild(branch, nd('3', '')), TestSimplePropertyType, new TestSimpleProperty("3")) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {withProperty: "net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType", withPropertyValue: "1"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['1'] - } - - @Test - void 'Default filter since property'() { - def branch = doCreateBranch() - doSetProperty(doCreateBuild(branch, nd('1', '')), TestSimplePropertyType, new TestSimpleProperty("1")) - doCreateBuild(branch, nd('2', '')) - doSetProperty(doCreateBuild(branch, nd('3', '')), TestSimplePropertyType, new TestSimpleProperty("3")) - doCreateBuild(branch, nd('4', '')) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: {sinceProperty: "net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType"}) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['4', '3'] - } - - @Test - void 'Default filter since property value'() { - def branch = doCreateBranch() - doSetProperty(doCreateBuild(branch, nd('1', '')), TestSimplePropertyType, new TestSimpleProperty("1")) - doCreateBuild(branch, nd('2', '')) - doSetProperty(doCreateBuild(branch, nd('3', '')), TestSimplePropertyType, new TestSimpleProperty("3")) - doCreateBuild(branch, nd('4', '')) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(filter: { - sinceProperty: "net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType", - sincePropertyValue: "1" - }) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['4', '3', '2', '1'] - } - - @Test - void 'Default filter with linked FROM criteria'() { - // Project 1 - def branch1 = doCreateBranch() - def build1 = doCreateBuild(branch1, nd('1.0', '')) - // Project 2 - def branch2 = doCreateBranch() - def build2 = doCreateBuild(branch2, nd('2.0', '')) - // Link build 2 --> build 1 - asUser().with(build2, BuildConfig).with(build1, ProjectView).call { - structureService.addBuildLink( - build2, - build1 - ) - } - - def data = asUser().withView(branch1).withView(branch2).call { - run("""{ - branches (id: ${branch1.id}) { - builds(filter: { - linkedFrom: "${branch2.project.name}:*" - }) { - name - } - } - }""") - } - assert data.branches.first().builds.name.flatten() == ['1.0'] - } - - @Test - void 'Default filter with linked TO criteria'() { - // Project 1 - def branch1 = doCreateBranch() - def build1 = doCreateBuild(branch1, nd('1.0', '')) - // Project 2 - def branch2 = doCreateBranch() - def build2 = doCreateBuild(branch2, nd('2.0', '')) - // Link build 2 --> build 1 - asUser().with(build2, BuildConfig).with(build1, ProjectView).call { - structureService.addBuildLink( - build2, - build1 - ) - } - - def data = asUser().withView(branch1).withView(branch2).call { - run("""{ - branches (id: ${branch2.id}) { - builds(filter: { - linkedTo: "${branch1.project.name}:*" - }) { - name - } - } - }""") - } - assert data.branches.first().builds.name.flatten() == ['2.0'] - } - - @Test - void 'Last promotion filter'() { - def branch = doCreateBranch() - def copper = doCreatePromotionLevel(branch, nd('COPPER', '')) - def bronze = doCreatePromotionLevel(branch, nd('BRONZE', '')) - def silver = doCreatePromotionLevel(branch, nd('SILVER', '')) - - doCreateBuild(branch, nd('1', '')) - doPromote(doCreateBuild(branch, nd('2', '')), silver, '') - doPromote(doCreateBuild(branch, nd('3', '')), bronze, '') - doCreateBuild(branch, nd('4', '')) - doPromote(doCreateBuild(branch, nd('5', '')), copper, '') - doCreateBuild(branch, nd('6', '')) - - def data = run("""{ - branches (id: ${branch.id}) { - builds(lastPromotions: true) { - name - } - } - }""") - assert data.branches.first().builds.name.flatten() == ['5', '3', '2'] - } - -} diff --git a/ontrack-ui-graphql/src/test/groovy/net/nemerosa/ontrack/graphql/support/GraphqlUtilsTest.groovy b/ontrack-ui-graphql/src/test/groovy/net/nemerosa/ontrack/graphql/support/GraphqlUtilsTest.groovy deleted file mode 100644 index 22f84e3ed6f..00000000000 --- a/ontrack-ui-graphql/src/test/groovy/net/nemerosa/ontrack/graphql/support/GraphqlUtilsTest.groovy +++ /dev/null @@ -1,29 +0,0 @@ -package net.nemerosa.ontrack.graphql.support - -import org.junit.Test - -import static net.nemerosa.ontrack.graphql.support.GraphqlUtils.lowerCamelCase - -class GraphqlUtilsTest { - - @Test - void 'Lower camel case'() { - assert lowerCamelCase(null) == null - assert lowerCamelCase("") == "" - assert lowerCamelCase(" ") == "" - assert lowerCamelCase("Abc") == "abc" - assert lowerCamelCase("abc") == "abc" - assert lowerCamelCase("AbcDef") == "abcdef" - assert lowerCamelCase("abcDef") == "abcdef" - assert lowerCamelCase("abc Def") == "abcDef" - assert lowerCamelCase("Abc Def") == "abcDef" - assert lowerCamelCase("Abc def") == "abcDef" - } - - @Test - void 'Lower camel case more complex cases'() { - assert lowerCamelCase("prefix:suffix") == "prefixSuffix" - assert lowerCamelCase("prefix: suffix") == "prefixSuffix" - } - -} diff --git a/ontrack-ui-graphql/src/test/java/net/nemerosa/ontrack/graphql/BranchBuildsFilterQLIT.kt b/ontrack-ui-graphql/src/test/java/net/nemerosa/ontrack/graphql/BranchBuildsFilterQLIT.kt new file mode 100644 index 00000000000..9456d1a2286 --- /dev/null +++ b/ontrack-ui-graphql/src/test/java/net/nemerosa/ontrack/graphql/BranchBuildsFilterQLIT.kt @@ -0,0 +1,529 @@ +package net.nemerosa.ontrack.graphql + +import net.nemerosa.ontrack.extension.api.support.TestSimpleProperty +import net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType +import net.nemerosa.ontrack.json.getRequiredTextField +import net.nemerosa.ontrack.model.structure.Build +import net.nemerosa.ontrack.model.structure.ValidationRunStatusID +import org.junit.jupiter.api.Test +import java.time.LocalDateTime +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class BranchBuildsFilterQLIT : AbstractQLKTITSupport() { + + @Test + fun `Default filter with validation stamp`() { + project { + branch { + validationStamp("NONE") + val vs = validationStamp("VS") + val build = build("1") { + validate(vs) + } + run( + """{ + branches (id: $id) { + builds(filter: {withValidationStamp: "VS"}) { + name + } + } + }""" + ) { data -> + val names = data.path("branches").path(0).path("builds").map { it.getRequiredTextField("name") } + assertEquals(listOf(build.name), names) + } + run( + """{ + branches (id: $id) { + builds(filter: {withValidationStamp: "NONE"}) { + name + } + } + }""" + ) { data -> + val names = data.path("branches").path(0).path("builds").map { it.getRequiredTextField("name") } + assertTrue(names.isEmpty(), "No build found with NONE validation") + } + } + } + } + + @Test + fun `Default filter with validation stamp and returning validation runs`() { + project { + branch { + val vs = validationStamp("VS") + val build = build { + validate(vs) + } + run( + """{ + branches (id: $id) { + builds(filter: {withValidationStamp: "VS"}) { + name + validationRuns { + validationRunStatuses { + statusID { + id + } + } + } + } + } + }""" + ) { data -> + val builds = data.path("branches").path(0).path("builds") + assertEquals(listOf(build.name), builds.map { it.getRequiredTextField("name") }) + val statuses = builds.path(0).path("validationRuns") + .flatMap { run -> + run.path("validationRunStatuses").map { s -> + s.path("statusID").path("id").asText() + } + } + assertEquals( + listOf("PASSED"), + statuses + ) + } + } + } + } + + @Test + fun `Default filter with validation stamp status`() { + project { + branch { + val vs = validationStamp("VS") + build { + validate(vs, ValidationRunStatusID.STATUS_FAILED) + } + val passed = build { + validate(vs, ValidationRunStatusID.STATUS_PASSED) + } + + run( + """{ + branches (id: $id) { + builds(filter: {withValidationStamp: "VS", withValidationStampStatus: "PASSED"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf(passed.name), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter since validation stamp`() { + project { + branch { + val vs = validationStamp("VS") + build { + validate(vs) + } + val lastValidated = build { + validate(vs) + } + val last = build() + run( + """{ + branches (id: $id) { + builds(filter: {sinceValidationStamp: "VS"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf(last.name, lastValidated.name), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter since validation stamp status`() { + project { + branch { + val vs = validationStamp("VS") + build("1") { validate(vs, ValidationRunStatusID.STATUS_PASSED) } + build("2") { validate(vs, ValidationRunStatusID.STATUS_PASSED) } + build("3") { validate(vs, ValidationRunStatusID.STATUS_FAILED) } + build("4") + run( + """{ + branches (id: $id) { + builds(filter: {sinceValidationStamp: "VS", sinceValidationStampStatus: "PASSED"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("4", "3", "2"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + + } + + @Test + fun `Default filter with promotion level`() { + project { + branch { + val copper = promotionLevel("COPPER") + build("1") { + promote(copper) + } + build("2") + build("3") { + promote(copper) + } + run( + """{ + branches (id: $id) { + builds(filter: {withPromotionLevel: "COPPER"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("3", "1"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter since promotion level`() { + project { + branch { + val copper = promotionLevel("COPPER") + build("1") { + promote(copper) + } + build("2") + build("3") { + promote(copper) + } + build("4") + run( + """{ + branches (id: $id) { + builds(filter: {sincePromotionLevel: "COPPER"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("4", "3"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter since and with promotion level`() { + project { + branch { + val copper = promotionLevel("COPPER") + val bronze = promotionLevel("BRONZE") + build("1") + build("2") { + promote(copper) + promote(bronze) + } + build("3") + build("4") { + promote(copper) + } + build("5") + run( + """{ + branches (id: $id) { + builds(filter: {sincePromotionLevel: "BRONZE", withPromotionLevel: "COPPER"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("4", "2"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter dates`() { + project { + branch { + build("1") { + updateBuildSignature(time = LocalDateTime.of(2016, 11, 30, 17, 0)) + } + build("2") { + updateBuildSignature(time = LocalDateTime.of(2016, 12, 2, 17, 10)) + } + build("3") { + updateBuildSignature(time = LocalDateTime.of(2016, 12, 4, 17, 20)) + } + run( + """{ + branches (id: $id) { + builds(filter: {afterDate: "2016-12-01", beforeDate: "2016-12-03"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("2"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter with property`() { + project { + branch { + build("1") { + setProperty(this, TestSimplePropertyType::class.java, TestSimpleProperty("1")) + } + build("2") + build("3") { + setProperty(this, TestSimplePropertyType::class.java, TestSimpleProperty("3")) + } + run( + """{ + branches (id: $id) { + builds(filter: {withProperty: "net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("3", "1"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter with property value`() { + project { + branch { + build("1") { + setProperty(this, TestSimplePropertyType::class.java, TestSimpleProperty("1")) + } + build("2") + build("3") { + setProperty(this, TestSimplePropertyType::class.java, TestSimpleProperty("3")) + } + run( + """{ + branches (id: $id) { + builds(filter: {withProperty: "net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType", withPropertyValue: "1"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("1"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter since property`() { + project { + branch { + build("1") { + setProperty(this, TestSimplePropertyType::class.java, TestSimpleProperty("1")) + } + build("2") + build("3") { + setProperty(this, TestSimplePropertyType::class.java, TestSimpleProperty("3")) + } + build("4") + run( + """{ + branches (id: $id) { + builds(filter: {sinceProperty: "net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType"}) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("4", "3"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter since property value`() { + project { + branch { + build("1") { + setProperty(this, TestSimplePropertyType::class.java, TestSimpleProperty("1")) + } + build("2") + build("3") { + setProperty(this, TestSimplePropertyType::class.java, TestSimpleProperty("3")) + } + build("4") + run( + """{ + branches (id: $id) { + builds(filter: { + sinceProperty: "net.nemerosa.ontrack.extension.api.support.TestSimplePropertyType", + sincePropertyValue: "1" + }) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("4", "3", "2", "1"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + + @Test + fun `Default filter with linked FROM criteria`() { + val build1 = project { + branch { + build() + } + } + val build2 = project { + branch { + build { + linkTo(build1) + } + } + } + run( + """{ + branches(id: ${build1.branch.id}) { + builds(filter: { + linkedFrom: "${build2.project.name}:*" + }) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf(build1.name), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + + @Test + fun `Default filter with linked TO criteria`() { + val build1 = project { + branch { + build() + } + } + val build2 = project { + branch { + build { + linkTo(build1) + } + } + } + run( + """{ + branches(id: ${build2.branch.id}) { + builds(filter: { + linkedTo: "${build1.project.name}:*" + }) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf(build2.name), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + + @Test + fun `Last promotion filter`() { + project { + branch { + val copper = promotionLevel("COPPER") + val bronze = promotionLevel("BRONZE") + val silver = promotionLevel("SILVER") + build("1") + build("2") { + promote(silver) + } + build("3") { + promote(bronze) + } + build("4") + build("5") { + promote(copper) + } + build("6") + run( + """{ + branches (id: $id) { + builds(lastPromotions: true) { + name + } + } + }""" + ) { data -> + assertEquals( + listOf("5", "3", "2"), + data.path("branches").path(0).path("builds").map { it.path("name").asText() } + ) + } + } + } + } + +}