From 59e3038423bad0e0a33065c9ef3febfbd43dddfd Mon Sep 17 00:00:00 2001 From: Jiri Danek Date: Sat, 19 Oct 2024 18:22:37 +0200 Subject: [PATCH 1/3] ref(utils): extract the oauth token logic into utility method --- .../test/platform/httpClient/OAuthToken.java | 59 +++++++++++++++++++ .../odh/test/e2e/standard/DistributedST.java | 50 +--------------- 2 files changed, 62 insertions(+), 47 deletions(-) create mode 100644 src/main/java/io/odh/test/platform/httpClient/OAuthToken.java diff --git a/src/main/java/io/odh/test/platform/httpClient/OAuthToken.java b/src/main/java/io/odh/test/platform/httpClient/OAuthToken.java new file mode 100644 index 00000000..cfcc96bb --- /dev/null +++ b/src/main/java/io/odh/test/platform/httpClient/OAuthToken.java @@ -0,0 +1,59 @@ +/* + * Copyright Skodjob authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.odh.test.platform.httpClient; + +import io.fabric8.openshift.api.model.OAuthAccessToken; +import io.fabric8.openshift.api.model.OAuthAccessTokenBuilder; +import io.fabric8.openshift.api.model.OAuthClient; +import io.fabric8.openshift.api.model.OAuthClientBuilder; +import io.fabric8.openshift.api.model.User; +import io.skodjob.testframe.resources.KubeResourceManager; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Random; + +public class OAuthToken { + public String getToken(String redirectUrl) throws NoSuchAlgorithmException { + // https://github.com/openshift/cluster-authentication-operator/blob/master/test/library/client.go#L35-L44 + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + String sha256Prefix = "sha256~"; + String randomToken = "nottoorandom%d".formatted(new Random().nextInt()); + byte[] hashed = digest.digest(randomToken.getBytes(StandardCharsets.UTF_8)); + String privateToken = sha256Prefix + randomToken; + String publicToken = sha256Prefix + Base64.getUrlEncoder().withoutPadding().encodeToString(hashed); + + User user = KubeResourceManager.getKubeClient().getOpenShiftClient().users().withName("kubeadmin").get(); + + final String oauthClientName = "oauth-client"; + OAuthClient client = new OAuthClientBuilder() + .withNewMetadata() + .withName(oauthClientName) + .endMetadata() + .withSecret("the-secret-for-oauth-client") + .withRedirectURIs("https://localhost") + .withGrantMethod("auto") + .withAccessTokenInactivityTimeoutSeconds(300) + .build(); + KubeResourceManager.getInstance().createResourceWithoutWait(client); + + OAuthAccessToken token = new OAuthAccessTokenBuilder() + .withNewMetadata() + .withName(publicToken) + .endMetadata() + .withExpiresIn(86400L) + .withScopes("user:full") + .withRedirectURI(redirectUrl) + .withClientName(oauthClientName) + .withUserName(user.getMetadata().getName()) + .withUserUID(user.getMetadata().getUid()) + .build(); + KubeResourceManager.getInstance().createResourceWithWait(token); + + return privateToken; + } +} diff --git a/src/test/java/io/odh/test/e2e/standard/DistributedST.java b/src/test/java/io/odh/test/e2e/standard/DistributedST.java index 70be0145..85a650e4 100644 --- a/src/test/java/io/odh/test/e2e/standard/DistributedST.java +++ b/src/test/java/io/odh/test/e2e/standard/DistributedST.java @@ -13,12 +13,7 @@ import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition; import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext; -import io.fabric8.openshift.api.model.OAuthAccessToken; -import io.fabric8.openshift.api.model.OAuthAccessTokenBuilder; -import io.fabric8.openshift.api.model.OAuthClient; -import io.fabric8.openshift.api.model.OAuthClientBuilder; import io.fabric8.openshift.api.model.Route; -import io.fabric8.openshift.api.model.User; import io.fabric8.openshift.client.OpenShiftClient; import io.odh.test.Environment; import io.odh.test.OdhAnnotationsLabels; @@ -26,6 +21,7 @@ import io.odh.test.install.InstallTypes; import io.odh.test.platform.RayClient; import io.odh.test.platform.TlsUtils; +import io.odh.test.platform.httpClient.OAuthToken; import io.odh.test.utils.CsvUtils; import io.odh.test.utils.DscUtils; import io.opendatahub.datasciencecluster.v1.DataScienceCluster; @@ -53,12 +49,8 @@ import org.slf4j.LoggerFactory; import java.net.http.HttpClient; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.util.Base64; import java.util.Map; import java.util.Objects; -import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; @@ -197,44 +189,8 @@ void testDistributedWorkloadWithKueue() throws Exception { final String clusterQueueName = "cluster-queue"; final String localQueueName = "local-queue"; - // https://github.com/openshift/cluster-authentication-operator/blob/master/test/library/client.go#L35-L44 - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - String sha256Prefix = "sha256~"; - String randomToken = "nottoorandom%d".formatted(new Random().nextInt()); - byte[] hashed = digest.digest(randomToken.getBytes(StandardCharsets.UTF_8)); - String privateToken = sha256Prefix + randomToken; - String publicToken = sha256Prefix + Base64.getUrlEncoder().withoutPadding().encodeToString(hashed); - - String oauthToken = Allure.step("Create OAuth Token", () -> { - User user = kubeClient.users().withName("kubeadmin").get(); - - final String oauthClientName = "oauth-client"; - OAuthClient client = new OAuthClientBuilder() - .withNewMetadata() - .withName(oauthClientName) - .endMetadata() - .withSecret("the-secret-for-oauth-client") - .withRedirectURIs("https://localhost") - .withGrantMethod("auto") - .withAccessTokenInactivityTimeoutSeconds(300) - .build(); - KubeResourceManager.getInstance().createResourceWithoutWait(client); - - OAuthAccessToken token = new OAuthAccessTokenBuilder() - .withNewMetadata() - .withName(publicToken) - .endMetadata() - .withExpiresIn(86400L) - .withScopes("user:full") - .withRedirectURI("https://ray-dashboard-koranteng-test-codeflare.apps-crc.testing/oauth/callback") - .withClientName(oauthClientName) - .withUserName(user.getMetadata().getName()) - .withUserUID(user.getMetadata().getUid()) - .build(); - KubeResourceManager.getInstance().createResourceWithWait(token); - - return privateToken; - }); + String redirectUrl = "https://ray-dashboard-koranteng-test-codeflare.apps-crc.testing/oauth/callback"; + String oauthToken = Allure.step("Create OAuth Token", () -> new OAuthToken().getToken(redirectUrl)); Allure.step("Setup resources", () -> { Allure.step("Create namespace", () -> { From 8e89ee16052e6c343dc8c1c960b05d44dbf4b7cf Mon Sep 17 00:00:00 2001 From: Jiri Danek Date: Sat, 19 Oct 2024 20:49:13 +0200 Subject: [PATCH 2/3] feat(KPFv2Client): add httpServer and oauthToken parameters --- .../io/odh/test/platform/KFPv2Client.java | 46 +++++++++---------- .../test/e2e/standard/PipelineV2ServerST.java | 1 + 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/main/java/io/odh/test/platform/KFPv2Client.java b/src/main/java/io/odh/test/platform/KFPv2Client.java index e5e07ced..b5257a09 100644 --- a/src/main/java/io/odh/test/platform/KFPv2Client.java +++ b/src/main/java/io/odh/test/platform/KFPv2Client.java @@ -38,15 +38,15 @@ public class KFPv2Client { .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .enable(JsonParser.Feature.INCLUDE_SOURCE_IN_LOCATION) .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); - private final HttpClient httpClient = HttpClient.newBuilder() - .version(HttpClient.Version.HTTP_2) - .followRedirects(HttpClient.Redirect.NORMAL) - .build(); + private final HttpClient httpClient; private final String baseUrl; + private final String oauthToken; - public KFPv2Client(String baseUrl) { + public KFPv2Client(HttpClient httpClient, String baseUrl, String oauthToken) { + this.httpClient = httpClient; this.baseUrl = baseUrl; + this.oauthToken = oauthToken; } @SneakyThrows @@ -54,11 +54,10 @@ public Pipeline importPipeline(String name, String description, String filePath) MultipartFormDataBodyPublisher requestBody = new MultipartFormDataBodyPublisher() .addFile("uploadfile", Path.of(filePath), "application/yaml"); - HttpRequest createPipelineRequest = HttpRequest.newBuilder() + HttpRequest createPipelineRequest = buildRequest() .uri(new URI(baseUrl + "/apis/v2beta1/pipelines/upload?name=%s&description=%s".formatted(name, description))) .header("Content-Type", requestBody.contentType()) .POST(requestBody) - .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())) .build(); HttpResponse responseCreate = httpClient.send(createPipelineRequest, HttpResponse.BodyHandlers.ofString()); @@ -69,10 +68,9 @@ public Pipeline importPipeline(String name, String description, String filePath) @SneakyThrows public @Nonnull List listPipelines() { - HttpRequest request = HttpRequest.newBuilder() + HttpRequest request = buildRequest() .uri(URI.create(baseUrl + "/apis/v2beta1/pipelines")) .GET() - .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())) .build(); HttpResponse reply = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); @@ -86,10 +84,9 @@ public Pipeline importPipeline(String name, String description, String filePath) @SneakyThrows public @Nonnull List listPipelineVersions(String pipelineId) { - HttpRequest request = HttpRequest.newBuilder() + HttpRequest request = buildRequest() .uri(URI.create(baseUrl + "/apis/v2beta1/pipelines/" + pipelineId + "/versions")) .GET() - .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())) .build(); HttpResponse reply = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); @@ -113,10 +110,9 @@ public PipelineRun runPipeline(String pipelineTestRunBasename, String pipelineId pipelineRun.runtimeConfig = new RuntimeConfig(); pipelineRun.runtimeConfig.parameters = parameters; } - HttpRequest request = HttpRequest.newBuilder() + HttpRequest request = buildRequest() .uri(URI.create(baseUrl + "/apis/v2beta1/runs")) .POST(HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(pipelineRun))) - .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())) .build(); HttpResponse reply = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); @@ -126,10 +122,9 @@ public PipelineRun runPipeline(String pipelineTestRunBasename, String pipelineId @SneakyThrows public List getPipelineRunStatus() { - HttpRequest request = HttpRequest.newBuilder() + HttpRequest request = buildRequest() .uri(URI.create(baseUrl + "/apis/v2beta1/runs")) .GET() - .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())) .build(); HttpResponse reply = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); @@ -139,10 +134,9 @@ public List getPipelineRunStatus() { @SneakyThrows public PipelineRun waitForPipelineRun(String pipelineRunId) { - HttpRequest request = HttpRequest.newBuilder() + HttpRequest request = buildRequest() .uri(URI.create(baseUrl + "/apis/v2beta1/runs/" + pipelineRunId)) .GET() - .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())) .build(); AtomicReference run = new AtomicReference<>(); @@ -177,10 +171,9 @@ public PipelineRun waitForPipelineRun(String pipelineRunId) { @SneakyThrows public void deletePipelineRun(String runId) { - HttpRequest request = HttpRequest.newBuilder() + HttpRequest request = buildRequest() .uri(URI.create(baseUrl + "/apis/v2beta1/runs/" + runId)) .DELETE() - .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())) .build(); HttpResponse reply = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); Assertions.assertEquals(200, reply.statusCode(), reply.body()); @@ -188,10 +181,9 @@ public void deletePipelineRun(String runId) { @SneakyThrows public void deletePipeline(String pipelineId) { - HttpRequest request = HttpRequest.newBuilder() + HttpRequest request = buildRequest() .uri(URI.create(baseUrl + "/apis/v2beta1/pipelines/" + pipelineId)) .DELETE() - .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())) .build(); HttpResponse reply = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); Assertions.assertEquals(200, reply.statusCode(), reply.body()); @@ -199,10 +191,9 @@ public void deletePipeline(String pipelineId) { @SneakyThrows public void deletePipelineVersion(String pipelineId, String pipelineVersionId) { - HttpRequest request = HttpRequest.newBuilder() + HttpRequest request = buildRequest() .uri(URI.create(baseUrl + "/apis/v2beta1/pipelines/" + pipelineId + "/versions/" + pipelineVersionId)) .DELETE() - .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())) .build(); HttpResponse reply = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); Assertions.assertEquals(200, reply.statusCode(), reply.body()); @@ -270,4 +261,13 @@ public static class RuntimeConfig { public Object parameters; public String pipelineRoot; } + + private HttpRequest.Builder buildRequest() { + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .timeout(Duration.of(DEFAULT_TIMEOUT_DURATION, DEFAULT_TIMEOUT_UNIT.toChronoUnit())); + if (oauthToken != null) { + requestBuilder.header("Authorization", "Bearer " + oauthToken); + } + return requestBuilder; + } } diff --git a/src/test/java/io/odh/test/e2e/standard/PipelineV2ServerST.java b/src/test/java/io/odh/test/e2e/standard/PipelineV2ServerST.java index b64f01ab..cfb583aa 100644 --- a/src/test/java/io/odh/test/e2e/standard/PipelineV2ServerST.java +++ b/src/test/java/io/odh/test/e2e/standard/PipelineV2ServerST.java @@ -160,6 +160,7 @@ void deployDataScienceCluster() { /// ODS-2206 - Verify user can create and run a data science pipeline in DS Project /// ODS-2226 - Verify user can delete components of data science pipeline from DS Pipelines page /// https://issues.redhat.com/browse/RHODS-5133 + @SuppressWarnings({"checkstyle:MethodLength"}) @TestDoc( description = @Desc("Check that user can create, run and deleted DataSciencePipeline from a DataScience project"), contact = @Contact(name = "Jiri Danek", email = "jdanek@redhat.com"), From 651abac57822943e412fda057f6d78c77e2a1d19 Mon Sep 17 00:00:00 2001 From: Jiri Danek Date: Sat, 19 Oct 2024 18:21:30 +0200 Subject: [PATCH 3/3] RHOAIENG-14782: fix(PipelineV2ServerST): remove obsolete devflags and use the public route for pipelines server api --- .../test/e2e/standard/PipelineV2ServerST.java | 130 ++++++++++-------- 1 file changed, 72 insertions(+), 58 deletions(-) diff --git a/src/test/java/io/odh/test/e2e/standard/PipelineV2ServerST.java b/src/test/java/io/odh/test/e2e/standard/PipelineV2ServerST.java index cfb583aa..327278e4 100644 --- a/src/test/java/io/odh/test/e2e/standard/PipelineV2ServerST.java +++ b/src/test/java/io/odh/test/e2e/standard/PipelineV2ServerST.java @@ -12,16 +12,17 @@ import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretBuilder; -import io.fabric8.kubernetes.api.model.Service; -import io.fabric8.kubernetes.client.LocalPortForward; import io.fabric8.kubernetes.client.dsl.Resource; -import io.fabric8.kubernetes.client.dsl.ServiceResource; import io.fabric8.openshift.api.model.Route; import io.fabric8.openshift.client.OpenShiftClient; import io.odh.test.Environment; import io.odh.test.OdhAnnotationsLabels; import io.odh.test.TestUtils; +import io.odh.test.install.InstallTypes; import io.odh.test.platform.KFPv2Client; +import io.odh.test.platform.TlsUtils; +import io.odh.test.platform.httpClient.OAuthToken; +import io.odh.test.utils.CsvUtils; import io.odh.test.utils.DscUtils; import io.opendatahub.datasciencecluster.v1.DataScienceCluster; import io.opendatahub.datasciencecluster.v1.DataScienceClusterBuilder; @@ -42,8 +43,6 @@ import io.opendatahub.datasciencecluster.v1.datascienceclusterspec.components.RayBuilder; import io.opendatahub.datasciencecluster.v1.datascienceclusterspec.components.Workbenches; import io.opendatahub.datasciencecluster.v1.datascienceclusterspec.components.WorkbenchesBuilder; -import io.opendatahub.datasciencecluster.v1.datascienceclusterspec.components.datasciencepipelines.DevFlagsBuilder; -import io.opendatahub.datasciencecluster.v1.datascienceclusterspec.components.datasciencepipelines.devflags.ManifestsBuilder; import io.opendatahub.datasciencepipelinesapplications.v1alpha1.DataSciencePipelinesApplication; import io.opendatahub.datasciencepipelinesapplications.v1alpha1.DataSciencePipelinesApplicationBuilder; import io.opendatahub.datasciencepipelinesapplications.v1alpha1.datasciencepipelinesapplicationspec.ApiServer; @@ -59,12 +58,14 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIf; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; +import java.net.http.HttpClient; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import static org.hamcrest.MatcherAssert.assertThat; @@ -84,6 +85,7 @@ @Step(value = "Delete ODH operator and all created resources", expected = "Operator is removed and all other resources as well") } ) +@DisabledIf(value = "isDSPv1Only", disabledReason = "Old versions of ODH don't support DSPv2.") public class PipelineV2ServerST extends StandardAbstract { private static final Logger LOGGER = LoggerFactory.getLogger(PipelineV2ServerST.class); @@ -123,25 +125,8 @@ void deployDataScienceCluster() { .withCodeflare( new CodeflareBuilder().withManagementState(Codeflare.ManagementState.Managed).build() ) - // TODO(jdanek): remove devFlags prior to release, when KFPv2 is the default .withDatasciencepipelines( - new DatasciencepipelinesBuilder() - .withManagementState(Datasciencepipelines.ManagementState.Managed) - // https://github.com/opendatahub-io/data-science-pipelines-operator/blob/main/datasciencecluster/datasciencecluster.yaml - .withDevFlags( - new DevFlagsBuilder() - .withManifests( - List.of( - new ManifestsBuilder() - .withUri("https://github.com/opendatahub-io/data-science-pipelines-operator/tarball/main") - .withContextDir("config") - .withSourcePath("overlays/odh") - .build() - ) - ) - .build() - ) - .build() + new DatasciencepipelinesBuilder().withManagementState(Datasciencepipelines.ManagementState.Managed).build() ) .withModelmeshserving( new ModelmeshservingBuilder().withManagementState(Modelmeshserving.ManagementState.Managed).build() @@ -178,7 +163,7 @@ void deployDataScienceCluster() { } ) @Test - void testUserCanOperateDSv2PipelineFromDSProject() throws IOException { + void testUserCanOperateDSv2PipelineFromDSProject() throws Exception { final String pipelineTestName = "pipeline-test-name"; final String pipelineTestDesc = "pipeline-test-desc"; final String prjTitle = "pipeline-test"; @@ -221,9 +206,6 @@ void testUserCanOperateDSv2PipelineFromDSProject() throws IOException { .withNewSpec() // https://github.com/opendatahub-io/data-science-pipelines-operator/blob/main/config/samples/v2/dspa-simple/dspa_simple.yaml .withDspVersion("v2") - .withNewMlpipelineUI() - .withImage("quay.io/opendatahub/ds-pipelines-frontend:latest") - .endMlpipelineUI() // TODO(jdanek): v1 values below, this will need review and updating closer to release .withNewApiServer() .withApplyTektonCustomResource(true) @@ -282,46 +264,55 @@ void testUserCanOperateDSv2PipelineFromDSProject() throws IOException { Resource endpoints = client.endpoints().inNamespace(prjTitle).withName("ds-pipeline-pipelines-definition"); TestUtils.waitForEndpoints("pipelines", endpoints); - Allure.step("Connect to the API server"); - Resource route = client.routes() - .inNamespace(prjTitle).withName("ds-pipeline-pipelines-definition"); + Allure.step("Fetch OpenShift's ingress CA for a HTTPS client"); + Secret ingressCaCerts = client.secrets().inNamespace("openshift-ingress").withName("router-certs-default").get(); + HttpClient httpClient = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .followRedirects(HttpClient.Redirect.NORMAL) + .sslContext(TlsUtils.getSSLContextFromSecret(ingressCaCerts)) + .build(); - // TODO(jdanek) I still don't know how to do oauth, so let's forward a port - ServiceResource svc = client.services().inNamespace(prjTitle).withName("ds-pipeline-pipelines-definition"); - try (LocalPortForward portForward = svc.portForward(8888, 0)) { - KFPv2Client kfpClient = new KFPv2Client("http://localhost:%d".formatted(portForward.getLocalPort())); + Allure.step("Connect to the Pipeline API server"); + Route route = client.routes() + .inNamespace(prjTitle).withName("ds-pipeline-pipelines-definition").get(); - // WORKAROUND(RHOAIENG-3250): delete sample pipeline present on ODH - deletePreexistingPipelinesAndVersions(kfpClient); + String url = "https://" + route.getStatus().getIngress().get(0).getHost(); + String redirectUrl = url + "/oauth/callback"; + String oauthToken = Allure.step("Create OAuth Token", + () -> new OAuthToken().getToken(redirectUrl)); - KFPv2Client.Pipeline importedPipeline = kfpClient.importPipeline(pipelineTestName, pipelineTestDesc, pipelineTestFilepath); + KFPv2Client kfpClient = new KFPv2Client(httpClient, url, oauthToken); - List pipelines = kfpClient.listPipelines(); - assertThat(pipelines.stream().map(p -> p.displayName).collect(Collectors.toList()), Matchers.contains(pipelineTestName)); + // WORKAROUND(RHOAIENG-3250): delete sample pipeline present on ODH + deletePreexistingPipelinesAndVersions(kfpClient); - Map parameters = Map.of( - "min_max_scaler", false, - "neighbors", 1, - "standard_scaler", true - ); - KFPv2Client.PipelineRun pipelineRun = kfpClient.runPipeline(pipelineTestRunBasename, importedPipeline.pipelineId, parameters, "Immediate"); + KFPv2Client.Pipeline importedPipeline = kfpClient.importPipeline(pipelineTestName, pipelineTestDesc, pipelineTestFilepath); - kfpClient.waitForPipelineRun(pipelineRun.runId); + List pipelines = kfpClient.listPipelines(); + assertThat(pipelines.stream().map(p -> p.displayName).collect(Collectors.toList()), Matchers.contains(pipelineTestName)); - List statuses = kfpClient.getPipelineRunStatus(); - assertThat(statuses.stream() - .filter(run -> run.runId.equals(pipelineRun.runId)) - .map(run -> run.state) - .findFirst().orElseThrow(), Matchers.is("SUCCEEDED")); + Map parameters = Map.of( + "min_max_scaler", false, + "neighbors", 1, + "standard_scaler", true + ); + KFPv2Client.PipelineRun pipelineRun = kfpClient.runPipeline(pipelineTestRunBasename, importedPipeline.pipelineId, parameters, "Immediate"); - checkPipelineRunK8sDeployments(prjTitle, pipelineRun.runId); + kfpClient.waitForPipelineRun(pipelineRun.runId); - kfpClient.deletePipelineRun(pipelineRun.runId); - for (KFPv2Client.PipelineVersion pipelineVersion : kfpClient.listPipelineVersions(importedPipeline.pipelineId)) { - kfpClient.deletePipelineVersion(importedPipeline.pipelineId, pipelineVersion.pipelineVersionId); - } - kfpClient.deletePipeline(importedPipeline.pipelineId); + List statuses = kfpClient.getPipelineRunStatus(); + assertThat(statuses.stream() + .filter(run -> run.runId.equals(pipelineRun.runId)) + .map(run -> run.state) + .findFirst().orElseThrow(), Matchers.is("SUCCEEDED")); + + checkPipelineRunK8sDeployments(prjTitle, pipelineRun.runId); + + kfpClient.deletePipelineRun(pipelineRun.runId); + for (KFPv2Client.PipelineVersion pipelineVersion : kfpClient.listPipelineVersions(importedPipeline.pipelineId)) { + kfpClient.deletePipelineVersion(importedPipeline.pipelineId, pipelineVersion.pipelineVersionId); } + kfpClient.deletePipeline(importedPipeline.pipelineId); } @io.qameta.allure.Step @@ -366,4 +357,27 @@ private void checkPipelineRunK8sDeployments(String prjTitle, String runId) { .toList(); Assertions.assertIterableEquals(expectedNodeNames.stream().sorted().toList(), argoNodeNames.stream().sorted().toList(), argoNodeNames.toString()); } + + static boolean isDSPv1Only() { + final CsvUtils.Version maxOdhVersion = CsvUtils.Version.fromString("2.10.0"); + final CsvUtils.Version maxRhoaiVersion = CsvUtils.Version.fromString("2.9.0"); + + // can't tell, but since it's likely a recent ODH, then `return false;` is probably correct + if (!Environment.OPERATOR_INSTALL_TYPE.equalsIgnoreCase(InstallTypes.OLM.toString())) { + return false; + } + + String operatorVersionString = Objects.requireNonNull(CsvUtils.getOperatorVersionFromCsv()); + if (operatorVersionString.isEmpty()) { + // if csv has not yet been installed in the cluster + operatorVersionString = Environment.OLM_OPERATOR_VERSION; + } + CsvUtils.Version operatorVersion = CsvUtils.Version.fromString(operatorVersionString); + + if (Environment.PRODUCT.equalsIgnoreCase(Environment.PRODUCT_ODH)) { + return operatorVersion.compareTo(maxOdhVersion) < 0; + } else { + return operatorVersion.compareTo(maxRhoaiVersion) < 0; + } + } }