-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Archive and restore registered models
- Loading branch information
1 parent
f336007
commit 412d440
Showing
33 changed files
with
1,175 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
280 changes: 280 additions & 0 deletions
280
frontend/src/__tests__/cypress/cypress/e2e/modelRegistry/RegisteredModelArchive.cy.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,280 @@ | ||
/* eslint-disable camelcase */ | ||
import { mockK8sResourceList } from '~/__mocks__'; | ||
import { mockDashboardConfig } from '~/__mocks__/mockDashboardConfig'; | ||
import { MODEL_REGISTRY_API_VERSION } from '~/concepts/modelRegistry/const'; | ||
import { mockModelRegistry } from '~/__mocks__/mockModelRegistry'; | ||
import { mockRegisteredModelList } from '~/__mocks__/mockRegisteredModelsList'; | ||
import { ModelRegistryModel } from '~/__tests__/cypress/cypress/utils/models'; | ||
import { mockModelVersion } from '~/__mocks__/mockModelVersion'; | ||
import { ModelState, ModelVersion, RegisteredModel } from '~/concepts/modelRegistry/types'; | ||
import { mockRegisteredModel } from '~/__mocks__/mockRegisteredModel'; | ||
import { verifyRelativeURL } from '~/__tests__/cypress/cypress/utils/url'; | ||
import { labelModal, modelRegistry } from '~/__tests__/cypress/cypress/pages/modelRegistry'; | ||
import { | ||
archiveModelModal, | ||
registeredModelArchive, | ||
restoreModelModal, | ||
} from '~/__tests__/cypress/cypress/pages/modelRegistry/registeredModelArchive'; | ||
import { mockModelVersionList } from '~/__mocks__/mockModelVersionList'; | ||
|
||
type HandlersProps = { | ||
registeredModelsSize?: number; | ||
registeredModels?: RegisteredModel[]; | ||
modelVersions?: ModelVersion[]; | ||
}; | ||
|
||
const initIntercepts = ({ | ||
registeredModelsSize = 4, | ||
registeredModels = [ | ||
mockRegisteredModel({ | ||
name: 'model 1', | ||
id: '1', | ||
labels: [ | ||
'Financial data', | ||
'Fraud detection', | ||
'Test label', | ||
'Machine learning', | ||
'Next data to be overflow', | ||
'Test label x', | ||
'Test label y', | ||
'Test label z', | ||
], | ||
state: ModelState.ARCHIVED, | ||
}), | ||
mockRegisteredModel({ id: '2', name: 'model 2', state: ModelState.ARCHIVED }), | ||
mockRegisteredModel({ id: '3', name: 'model 3' }), | ||
mockRegisteredModel({ id: '4', name: 'model 4' }), | ||
], | ||
modelVersions = [ | ||
mockModelVersion({ author: 'Author 1' }), | ||
mockModelVersion({ name: 'model version' }), | ||
], | ||
}: HandlersProps) => { | ||
cy.interceptOdh( | ||
'GET /api/config', | ||
mockDashboardConfig({ | ||
disableModelRegistry: false, | ||
}), | ||
); | ||
|
||
cy.interceptK8sList( | ||
ModelRegistryModel, | ||
mockK8sResourceList([mockModelRegistry({}), mockModelRegistry({ name: 'test-registry' })]), | ||
); | ||
|
||
cy.interceptK8s(ModelRegistryModel, mockModelRegistry({})); | ||
|
||
cy.interceptOdh( | ||
`GET /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/registered_models`, | ||
{ | ||
path: { serviceName: 'modelregistry-sample', apiVersion: MODEL_REGISTRY_API_VERSION }, | ||
}, | ||
mockRegisteredModelList({ size: registeredModelsSize }), | ||
); | ||
|
||
cy.interceptOdh( | ||
`GET /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/registered_models`, | ||
{ | ||
path: { serviceName: 'modelregistry-sample', apiVersion: MODEL_REGISTRY_API_VERSION }, | ||
}, | ||
mockRegisteredModelList({ items: registeredModels }), | ||
); | ||
|
||
cy.interceptOdh( | ||
`GET /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/registered_models/:registeredModelId/versions`, | ||
{ | ||
path: { | ||
serviceName: 'modelregistry-sample', | ||
apiVersion: MODEL_REGISTRY_API_VERSION, | ||
registeredModelId: 1, | ||
}, | ||
}, | ||
mockModelVersionList({ items: modelVersions }), | ||
); | ||
|
||
cy.interceptOdh( | ||
'GET /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/registered_models/:registeredModelId', | ||
{ | ||
path: { | ||
serviceName: 'modelregistry-sample', | ||
apiVersion: MODEL_REGISTRY_API_VERSION, | ||
registeredModelId: 2, | ||
}, | ||
}, | ||
mockRegisteredModel({ id: '2', name: 'model 2', state: ModelState.ARCHIVED }), | ||
); | ||
}; | ||
|
||
describe('Model archive list', () => { | ||
it('No archive models in the selected model registry', () => { | ||
initIntercepts({ | ||
registeredModels: [], | ||
}); | ||
registeredModelArchive.visitModelList(); | ||
verifyRelativeURL('/modelRegistry/modelregistry-sample'); | ||
registeredModelArchive.findTableKebabMenu().findDropdownItem('View archived models').click(); | ||
registeredModelArchive.shouldArchiveVersionsEmpty(); | ||
}); | ||
|
||
it('Archive models list', () => { | ||
initIntercepts({}); | ||
registeredModelArchive.visit(); | ||
verifyRelativeURL('/modelRegistry/modelregistry-sample/registeredModels/archive'); | ||
|
||
//breadcrumb | ||
registeredModelArchive.findArchiveModelBreadcrumbItem().contains('Archived models'); | ||
|
||
// name, last modified, owner, labels modal | ||
registeredModelArchive.findArchiveModelTable().should('be.visible'); | ||
registeredModelArchive.findArchiveModelsTableRows().should('have.length', 2); | ||
|
||
const archiveModelRow = registeredModelArchive.getRow('model 1'); | ||
|
||
archiveModelRow.findLabelModalText().contains('5 more'); | ||
archiveModelRow.findLabelModalText().click(); | ||
labelModal.shouldContainsModalLabels([ | ||
'Financial', | ||
'Financial data', | ||
'Fraud detection', | ||
'Test label', | ||
'Machine learning', | ||
'Next data to be overflow', | ||
'Test label x', | ||
'Test label y', | ||
'Test label y', | ||
]); | ||
labelModal.findCloseModal().click(); | ||
}); | ||
}); | ||
|
||
describe('Restoring archive model', () => { | ||
it('Restore from archive models table', () => { | ||
cy.interceptOdh( | ||
'PATCH /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/registered_models/:registeredModelId', | ||
{ | ||
path: { | ||
serviceName: 'modelregistry-sample', | ||
apiVersion: MODEL_REGISTRY_API_VERSION, | ||
registeredModelId: 2, | ||
}, | ||
}, | ||
mockRegisteredModel({ id: '2', name: 'model 2', state: ModelState.LIVE }), | ||
).as('modelRestored'); | ||
|
||
initIntercepts({}); | ||
registeredModelArchive.visit(); | ||
|
||
// Bypass patternfly ExpandableSection error https://github.com/patternfly/patternfly-react/issues/10410 | ||
// Cannot destructure property 'offsetWidth' of 'this.expandableContentRef.current' as it is null. | ||
Cypress.on('uncaught:exception', () => false); | ||
|
||
const archiveModelRow = registeredModelArchive.getRow('model 2'); | ||
archiveModelRow.findKebabAction('Restore model').click(); | ||
|
||
restoreModelModal.findRestoreButton().click(); | ||
|
||
cy.wait('@modelRestored').then((interception) => { | ||
expect(interception.request.body).to.eql({ | ||
customProperties: {}, | ||
description: '', | ||
externalID: '1234132asdfasdf', | ||
state: 'LIVE', | ||
}); | ||
}); | ||
}); | ||
|
||
it('Restore from archive model details', () => { | ||
cy.interceptOdh( | ||
'PATCH /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/registered_models/:registeredModelId', | ||
{ | ||
path: { | ||
serviceName: 'modelregistry-sample', | ||
apiVersion: MODEL_REGISTRY_API_VERSION, | ||
registeredModelId: 2, | ||
}, | ||
}, | ||
mockRegisteredModel({ id: '2', name: 'model 2', state: ModelState.LIVE }), | ||
).as('modelRestored'); | ||
|
||
initIntercepts({}); | ||
registeredModelArchive.visitArchiveModelDetail(); | ||
|
||
registeredModelArchive.findRestoreButton().click(); | ||
restoreModelModal.findRestoreButton().click(); | ||
|
||
cy.wait('@modelRestored').then((interception) => { | ||
expect(interception.request.body).to.eql({ | ||
customProperties: {}, | ||
description: '', | ||
externalID: '1234132asdfasdf', | ||
state: 'LIVE', | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('Archiving model', () => { | ||
it('Archive model from registered models table', () => { | ||
cy.interceptOdh( | ||
'PATCH /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/registered_models/:registeredModelId', | ||
{ | ||
path: { | ||
serviceName: 'modelregistry-sample', | ||
apiVersion: MODEL_REGISTRY_API_VERSION, | ||
registeredModelId: 3, | ||
}, | ||
}, | ||
mockRegisteredModel({ id: '3', name: 'model 3', state: ModelState.ARCHIVED }), | ||
).as('modelArchived'); | ||
|
||
initIntercepts({}); | ||
registeredModelArchive.visitModelList(); | ||
|
||
const modelRow = modelRegistry.getRow('model 3'); | ||
modelRow.findKebabAction('Archive model').click(); | ||
archiveModelModal.findArchiveButton().should('be.disabled'); | ||
archiveModelModal.findModalTextInput().fill('model 3'); | ||
archiveModelModal.findArchiveButton().should('be.enabled').click(); | ||
cy.wait('@modelArchived').then((interception) => { | ||
expect(interception.request.body).to.eql({ | ||
customProperties: {}, | ||
description: '', | ||
externalID: '1234132asdfasdf', | ||
state: 'ARCHIVED', | ||
}); | ||
}); | ||
}); | ||
|
||
it('Archive model from model details', () => { | ||
cy.interceptOdh( | ||
'PATCH /api/service/modelregistry/:serviceName/api/model_registry/:apiVersion/registered_models/:registeredModelId', | ||
{ | ||
path: { | ||
serviceName: 'modelregistry-sample', | ||
apiVersion: MODEL_REGISTRY_API_VERSION, | ||
registeredModelId: 2, | ||
}, | ||
}, | ||
mockRegisteredModel({ id: '2', name: 'model 2', state: ModelState.ARCHIVED }), | ||
).as('modelArchived'); | ||
|
||
initIntercepts({}); | ||
registeredModelArchive.visitModelDetails(); | ||
registeredModelArchive | ||
.findModelVersionsDetailsHeaderAction() | ||
.findDropdownItem('Archive model') | ||
.click(); | ||
|
||
archiveModelModal.findArchiveButton().should('be.disabled'); | ||
archiveModelModal.findModalTextInput().fill('model 2'); | ||
archiveModelModal.findArchiveButton().should('be.enabled').click(); | ||
cy.wait('@modelArchived').then((interception) => { | ||
expect(interception.request.body).to.eql({ | ||
customProperties: {}, | ||
description: '', | ||
externalID: '1234132asdfasdf', | ||
state: 'ARCHIVED', | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.