From 32ba4e502c2b4d1417e28f213602004c5e27de9a Mon Sep 17 00:00:00 2001 From: Bipul Adhikari Date: Mon, 10 Oct 2022 18:31:08 +0545 Subject: [PATCH] Write e2e tests for Compression Signed-off-by: Bipul Adhikari --- cypress/mocks/compression.ts | 141 ++++++++++++++++++++++++++++++ cypress/support.ts | 18 ++++ cypress/tests/compression.spec.ts | 64 ++++++++++++++ cypress/views/common.ts | 10 ++- 4 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 cypress/mocks/compression.ts create mode 100644 cypress/tests/compression.spec.ts diff --git a/cypress/mocks/compression.ts b/cypress/mocks/compression.ts new file mode 100644 index 000000000..09a382533 --- /dev/null +++ b/cypress/mocks/compression.ts @@ -0,0 +1,141 @@ +export const compressionPool = { + apiVersion: 'ceph.rook.io/v1', + kind: 'CephBlockPool', + metadata: { name: 'plasma-reactor-pool', namespace: 'openshift-storage' }, + spec: { + compressionMode: 'aggressive', + deviceClass: 'ssd', + failureDomain: 'zone', + parameters: { compression_mode: 'aggressive' }, + replicated: { size: 2 }, + }, +}; + +export const compressionStorageClass = { + kind: 'StorageClass', + apiVersion: 'storage.k8s.io/v1', + metadata: { + name: 'compression-class', + namespace: 'openshift-storage', + }, + provisioner: 'openshift-storage.rbd.csi.ceph.com', + parameters: { + 'csi.storage.k8s.io/fstype': 'ext4', + 'csi.storage.k8s.io/provisioner-secret-namespace': 'openshift-storage', + 'csi.storage.k8s.io/provisioner-secret-name': 'rook-csi-rbd-provisioner', + 'csi.storage.k8s.io/node-stage-secret-name': 'rook-csi-rbd-node', + 'csi.storage.k8s.io/controller-expand-secret-name': + 'rook-csi-rbd-provisioner', + imageFormat: '2', + clusterID: 'openshift-storage', + imageFeatures: 'layering,deep-flatten,exclusive-lock,object-map,fast-diff', + 'csi.storage.k8s.io/controller-expand-secret-namespace': + 'openshift-storage', + pool: 'plasma-reactor-pool', + 'csi.storage.k8s.io/node-stage-secret-namespace': 'openshift-storage', + }, + reclaimPolicy: 'Delete', + allowVolumeExpansion: true, + volumeBindingMode: 'Immediate', +}; + +export const fioPVC = { + kind: 'PersistentVolumeClaim', + apiVersion: 'v1', + metadata: { + name: 'fio-claim', + namespace: 'openshift-storage', + }, + spec: { + storageClassName: 'compression-class', + accessModes: ['ReadWriteOnce'], + volumeMode: 'Filesystem', + resources: { + requests: { + storage: '5Gi', + }, + }, + }, +}; + +export const fioConfig = `kind: ConfigMap +apiVersion: v1 +metadata: + name: fio-job-config + namespace: openshift-storage +data: + fio.job: |- + [global] + ioengine=psync + direct=1 + buffered=0 + size=1G + iodepth=1000 + numjobs=2 + group_reporting + refill_buffers + rwmixread=80 + norandommap + randrepeat=0 + percentage_random=0 + bs=512K + buffer_compress_percentage=50 + rw=read + [testjob] +`; + +export const fioJob = { + apiVersion: 'batch/v1', + kind: 'Job', + metadata: { + name: 'fio', + namespace: 'openshift-storage', + labels: { + app: 'fio', + }, + }, + spec: { + template: { + spec: { + containers: [ + { + name: 'fio', + image: 'quay.io/badhikar/fio:latest', + command: ['sh'], + args: [ + '-c', + // eslint-disable-next-line no-template-curly-in-string + 'echo ${HOSTNAME} && mkdir -p /scratch/${HOSTNAME} && fio /configs/fio.job --eta=never --directory=/scratch/${HOSTNAME}', + ], + volumeMounts: [ + { + name: 'fio-config-vol', + mountPath: '/configs', + }, + { + name: 'fio-data', + mountPath: '/scratch', + }, + ], + imagePullPolicy: 'Always', + }, + ], + restartPolicy: 'OnFailure', + volumes: [ + { + name: 'fio-config-vol', + configMap: { + name: 'fio-job-config', + }, + }, + { + name: 'fio-data', + persistentVolumeClaim: { + claimName: 'fio-claim', + }, + }, + ], + }, + }, + }, +}; diff --git a/cypress/support.ts b/cypress/support.ts index cc2a8dc8e..ec99fb1db 100644 --- a/cypress/support.ts +++ b/cypress/support.ts @@ -7,11 +7,13 @@ import { } from './consts'; import './support/selectors'; import './support/login'; +import { commandPoll } from './views/common'; declare global { namespace Cypress { interface Chainable { install(encrypted?: boolean): Chainable; + enableToolboxPod(): void; } } } @@ -77,3 +79,19 @@ Cypress.Commands.add('install', () => { } }); }); + +Cypress.Commands.add('enableToolboxPod', () => { + cy.exec( + `oc patch ocsinitialization ocsinit -n openshift-storage --type json --patch '[{ "op": "replace", "path": "/spec/enableCephTools", "value": true }]'` + ); + commandPoll( + 'oc get pod -l "app=rook-ceph-tools" -n openshift-storage', + null, + false, + 30, + 0 + ); + cy.exec( + `oc wait --for=condition=ready pod -l "app=rook-ceph-tools" -n openshift-storage` + ); +}); diff --git a/cypress/tests/compression.spec.ts b/cypress/tests/compression.spec.ts new file mode 100644 index 000000000..8ae9578ab --- /dev/null +++ b/cypress/tests/compression.spec.ts @@ -0,0 +1,64 @@ +import { + compressionPool, + compressionStorageClass, + fioConfig, + fioJob, + fioPVC, +} from '../mocks/compression'; +import { navigateToBlockPool } from '../views/block-pool'; +import { commandPoll } from '../views/common'; + +describe('Test Pool Compression', () => { + before(() => { + cy.login(); + cy.visit('/'); + cy.install(); + cy.enableToolboxPod(); + cy.exec(`echo '${JSON.stringify(compressionPool)}' | oc apply -f -`); + cy.exec( + `echo '${JSON.stringify(compressionStorageClass)}' | oc apply -f -` + ); + cy.exec(`echo '${fioConfig}' | oc apply -f -`); + cy.exec(`echo '${JSON.stringify(fioPVC)}' | oc apply -f -`); + cy.exec(`echo '${JSON.stringify(fioJob)}' | oc apply -f -`); + commandPoll('oc get job fio -n openshift-storage', null, false, 300, 0); + cy.exec(`oc wait --for=condition=complete job fio -n openshift-storage`, { + timeout: 120000, + }); + }); + + it('Tests compression statistics are correct on the BlockPool list Page', () => { + navigateToBlockPool(); + cy.byTestID('name-filter-input').type(compressionPool.metadata.name); + // TableData does not support data-test ids + // eslint-disable-next-line cypress/require-data-selectors + cy.get('#compressionStatus').should('have.text', 'Enabled'); + cy.exec( + `oc exec -it $(oc get pods -n openshift-storage -l app=rook-ceph-tools -o name) -n openshift-storage -- /usr/bin/rados df -f json` + ).then(({ stdout }) => { + const poolData = JSON.parse(stdout).pools; + const plasmaPool = poolData.find( + (pool) => pool.name === compressionPool.metadata.name + ); + const compressionSavings = plasmaPool.compress_bytes_used; + // TableData does not support data-test ids + // eslint-disable-next-line cypress/require-data-selectors + cy.get('#compressionSavings').contains( + (compressionSavings / 1024 ** 2).toFixed(1) + ); + }); + }); + + after(() => { + cy.exec(`echo ${JSON.stringify(fioJob)} | oc delete -f -`); + cy.exec(`echo ${JSON.stringify(fioPVC)} | oc delete -f -`); + cy.exec(`echo ${JSON.stringify(fioConfig)} | oc delete -f -`); + cy.exec( + `oc delete storageclass ${compressionStorageClass.metadata.name} --wait=false --grace-period=0` + ); + cy.exec( + `oc delete cephblockpool ${compressionPool.metadata.name} -n ${compressionPool.metadata.namespace} --grace-period=0 --force --wait=false` + ); + cy.logout(); + }); +}); diff --git a/cypress/views/common.ts b/cypress/views/common.ts index 58e800dd8..7711fa292 100644 --- a/cypress/views/common.ts +++ b/cypress/views/common.ts @@ -11,10 +11,14 @@ export const commandPoll = ( cmd: string, expected: string, failOnNonZeroExit: boolean = true, - retry: number = 300 + retry: number = 300, + expectedCode?: number ) => { cy.exec(cmd, { failOnNonZeroExit }).then((res) => { - if (res.stdout === expected) { + if ( + (res.stdout === expected || expectedCode === res.code) && + res.stderr === '' + ) { assert(true); return; } @@ -23,6 +27,6 @@ export const commandPoll = ( return; } - commandPoll(cmd, expected, failOnNonZeroExit, retry - 1); + commandPoll(cmd, expected, failOnNonZeroExit, retry - 1, expectedCode); }); };