|
| 1 | +import { |
| 2 | + ModelLocationSelectOption, |
| 3 | + ModelStateLabel, |
| 4 | + ModelTypeLabel, |
| 5 | +} from '@odh-dashboard/model-serving/types/form-data'; |
| 6 | +import { deleteOpenShiftProject } from '../../../../utils/oc_commands/project'; |
| 7 | +import { HTPASSWD_CLUSTER_ADMIN_USER } from '../../../../utils/e2eUsers'; |
| 8 | +import { projectDetails, projectListPage } from '../../../../pages/projects'; |
| 9 | +import { retryableBefore } from '../../../../utils/retryableHooks'; |
| 10 | +import { createCleanProject } from '../../../../utils/projectChecker'; |
| 11 | +import { |
| 12 | + modelServingGlobal, |
| 13 | + modelServingSection, |
| 14 | + modelServingWizard, |
| 15 | + deleteModelServingModal, |
| 16 | + inferenceServiceActions, |
| 17 | +} from '../../../../pages/modelServing'; |
| 18 | +import { generateTestUUID } from '../../../../utils/uuidGenerator'; |
| 19 | +import type { DataScienceProjectData } from '../../../../types'; |
| 20 | +import { loadDSPFixture } from '../../../../utils/dataLoader'; |
| 21 | +import { |
| 22 | + createCleanHardwareProfile, |
| 23 | + cleanupHardwareProfiles, |
| 24 | +} from '../../../../utils/oc_commands/hardwareProfiles'; |
| 25 | +import { |
| 26 | + createCleanLLMInferenceServiceConfig, |
| 27 | + cleanupLLMInferenceServiceConfig, |
| 28 | + checkLLMInferenceServiceConfigState, |
| 29 | +} from '../../../../utils/oc_commands/llmInferenceServiceConfig'; |
| 30 | +import { checkLLMInferenceServiceState } from '../../../../utils/oc_commands/modelServing'; |
| 31 | + |
| 32 | +let testData: DataScienceProjectData; |
| 33 | +let projectName: string; |
| 34 | +let modelName: string; |
| 35 | +const uuid = generateTestUUID(); |
| 36 | +let hardwareProfileResourceName: string; |
| 37 | +let modelURI: string; |
| 38 | +const llmInferenceServiceConfigName = 'kserve-config-llm-template-cpu'; |
| 39 | +const llmInferenceServiceConfigDisplayName = 'vLLM CPU LLMInferenceServiceConfig'; |
| 40 | +const llmInferenceServiceConfigYamlPath = |
| 41 | + 'resources/modelServing/llmd-inference-service-config.yaml'; |
| 42 | + |
| 43 | +describe('A user can deploy a model via vLLM on MaaS (LLMInferenceServiceConfig)', () => { |
| 44 | + retryableBefore(() => { |
| 45 | + cy.log('Loading test data'); |
| 46 | + return loadDSPFixture('e2e/dataScienceProjects/testDeployLLMDServing.yaml') |
| 47 | + .then((fixtureData: DataScienceProjectData) => { |
| 48 | + testData = fixtureData; |
| 49 | + projectName = `${testData.projectResourceName}-maas-${uuid}`; |
| 50 | + modelName = `${testData.singleModelName}-maas`; |
| 51 | + modelURI = testData.modelLocationURI; |
| 52 | + hardwareProfileResourceName = `${testData.hardwareProfileName}`; |
| 53 | + |
| 54 | + cy.log(`Loaded project name: ${projectName}`); |
| 55 | + createCleanProject(projectName); |
| 56 | + }) |
| 57 | + .then(() => { |
| 58 | + cy.log(`Load Hardware Profile Name: ${hardwareProfileResourceName}`); |
| 59 | + createCleanHardwareProfile('resources/yaml/llmd-hardware-profile.yaml'); |
| 60 | + }) |
| 61 | + .then(() => { |
| 62 | + cy.log(`Load LLMInferenceServiceConfig: ${llmInferenceServiceConfigName}`); |
| 63 | + createCleanLLMInferenceServiceConfig( |
| 64 | + llmInferenceServiceConfigName, |
| 65 | + llmInferenceServiceConfigYamlPath, |
| 66 | + ); |
| 67 | + }); |
| 68 | + }); |
| 69 | + |
| 70 | + after(() => { |
| 71 | + cy.log(`Cleaning up Hardware Profile: ${hardwareProfileResourceName}`); |
| 72 | + cleanupHardwareProfiles(hardwareProfileResourceName); |
| 73 | + cy.log(`Cleaning up LLMInferenceServiceConfig: ${llmInferenceServiceConfigName}`); |
| 74 | + cleanupLLMInferenceServiceConfig(llmInferenceServiceConfigName); |
| 75 | + // Delete provisioned Project - wait for completion due to RHOAIENG-19969 to support test retries, 5 minute timeout |
| 76 | + // TODO: Review this timeout once RHOAIENG-19969 is resolved |
| 77 | + deleteOpenShiftProject(projectName, { wait: true, ignoreNotFound: true, timeout: 300000 }); |
| 78 | + }); |
| 79 | + |
| 80 | + it( |
| 81 | + 'Verify User can deploy a model by selecting an LLMInferenceServiceConfig', |
| 82 | + { |
| 83 | + tags: ['@Smoke', '@SmokeSet3', '@Dashboard', '@ModelServing', '@NonConcurrent'], |
| 84 | + }, |
| 85 | + () => { |
| 86 | + cy.step('Log into the application as admin'); |
| 87 | + cy.visitWithLogin('/?devFeatureFlags=vLLMDeploymentOnMaaS=true', HTPASSWD_CLUSTER_ADMIN_USER); |
| 88 | + |
| 89 | + cy.step(`Navigate to the Project list tab and search for ${projectName}`); |
| 90 | + projectListPage.navigate(); |
| 91 | + projectListPage.filterProjectByName(projectName); |
| 92 | + projectListPage.findProjectLink(projectName).click(); |
| 93 | + |
| 94 | + cy.step('Open the deploy model wizard'); |
| 95 | + projectDetails.findSectionTab('model-server').click(); |
| 96 | + modelServingGlobal.selectSingleServingModelButtonIfExists(); |
| 97 | + modelServingGlobal.findDeployModelButton().click(); |
| 98 | + |
| 99 | + cy.step('Step 1: Model details - select Generative type'); |
| 100 | + modelServingWizard.findModelLocationSelectOption(ModelLocationSelectOption.URI).click(); |
| 101 | + modelServingWizard.findUrilocationInput().clear().type(modelURI); |
| 102 | + modelServingWizard.findSaveConnectionCheckbox().should('be.checked'); |
| 103 | + modelServingWizard |
| 104 | + .findSaveConnectionInput() |
| 105 | + .clear() |
| 106 | + .type(`${modelName}${testData.connectionNameSuffix}`); |
| 107 | + modelServingWizard.findModelTypeSelectOption(ModelTypeLabel.GENERATIVE).click(); |
| 108 | + |
| 109 | + cy.step('Verify legacy checkbox is unchecked (non-legacy MaaS path)'); |
| 110 | + modelServingWizard.findLegacyModeCheckbox().should('exist').should('not.be.checked'); |
| 111 | + modelServingWizard.findNextButton().should('be.enabled').click(); |
| 112 | + |
| 113 | + cy.step('Step 2: Model deployment - select vLLM CPU LLMInferenceServiceConfig'); |
| 114 | + modelServingWizard.findModelDeploymentNameInput().clear().type(modelName); |
| 115 | + modelServingWizard.findResourceNameButton().click(); |
| 116 | + modelServingWizard |
| 117 | + .findResourceNameInput() |
| 118 | + .should('be.visible') |
| 119 | + .invoke('val') |
| 120 | + .as('resourceName'); |
| 121 | + modelServingWizard.selectPotentiallyDisabledProfile(hardwareProfileResourceName); |
| 122 | + modelServingWizard.findServingRuntimeTemplateSearchSelector().click(); |
| 123 | + modelServingWizard |
| 124 | + .findGlobalScopedTemplateOption(llmInferenceServiceConfigDisplayName) |
| 125 | + .should('exist') |
| 126 | + .click(); |
| 127 | + modelServingWizard.findNextButton().should('be.enabled').click(); |
| 128 | + |
| 129 | + cy.step('Step 3: Advanced settings'); |
| 130 | + modelServingWizard.findTokenAuthenticationCheckbox().should('be.checked'); |
| 131 | + modelServingWizard.findNextButton().click(); |
| 132 | + |
| 133 | + cy.step('Step 4: Review and submit'); |
| 134 | + modelServingWizard.findSubmitButton().click(); |
| 135 | + |
| 136 | + cy.step('Verify the model is available in UI'); |
| 137 | + modelServingSection.findModelServerDeployedName(modelName); |
| 138 | + |
| 139 | + cy.step('Verify LLMInferenceService exists in the project namespace'); |
| 140 | + cy.get<string>('@resourceName').then((resourceName) => { |
| 141 | + checkLLMInferenceServiceState(resourceName, projectName, { checkReady: true }); |
| 142 | + }); |
| 143 | + |
| 144 | + cy.step('Verify LLMInferenceServiceConfig was copied to the project namespace'); |
| 145 | + checkLLMInferenceServiceConfigState(llmInferenceServiceConfigName, projectName, { |
| 146 | + containerImage: 'quay.io/pierdipi/vllm-cpu:latest', |
| 147 | + }); |
| 148 | + |
| 149 | + cy.step('Verify the model Row'); |
| 150 | + const deploymentRow = modelServingGlobal.getDeploymentRow(modelName); |
| 151 | + deploymentRow.findStatusLabel(ModelStateLabel.STARTED).should('exist'); |
| 152 | + deploymentRow.findKebab().click(); |
| 153 | + inferenceServiceActions.findDeleteInferenceServiceAction().click(); |
| 154 | + deleteModelServingModal.findInput().clear().type(modelName); |
| 155 | + deleteModelServingModal.findSubmitButton().should('be.enabled').click(); |
| 156 | + }, |
| 157 | + ); |
| 158 | +}); |
0 commit comments