From 5b072ebaa02315f314a204cf08ff7d01d8e50751 Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Mon, 27 Jul 2020 10:50:25 -0700 Subject: [PATCH 1/5] Add support for running CI with security --- .../ad/dashboard/ad_dashboard.spec.ts | 20 ++-- .../ad/detectorList/detector_list.spec.ts | 36 +++--- .../ad/workflow/create_detector.spec.ts | 2 +- .cypress/support/commands.ts | 25 +++-- .cypress/support/index.d.ts | 1 + .github/configurations/docker-compose.yml | 46 ++++++++ .github/workflows/CD.yml | 5 +- .github/workflows/e2e-tests-workflow.yml | 106 ++++++++++++++++-- .github/workflows/unit-tests-workflow.yml | 5 +- cypress.json | 6 +- 10 files changed, 193 insertions(+), 59 deletions(-) create mode 100644 .github/configurations/docker-compose.yml diff --git a/.cypress/integration/ad/dashboard/ad_dashboard.spec.ts b/.cypress/integration/ad/dashboard/ad_dashboard.spec.ts index f01d0fc0..d450d0a6 100644 --- a/.cypress/integration/ad/dashboard/ad_dashboard.spec.ts +++ b/.cypress/integration/ad/dashboard/ad_dashboard.spec.ts @@ -19,21 +19,21 @@ import { buildAdAppUrl } from '../../../utils/helpers'; context('AD Dashboard', () => { it('Empty dashboard - no detector index', () => { cy.mockGetDetectorOnAction('no_detector_index_response.json', () => { - cy.visit(buildAdAppUrl(DASHBOARD)); + cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); }); cy.contains('h2', 'You have no detectors'); }); it('Empty dashboard - empty detector index', () => { cy.mockGetDetectorOnAction('empty_detector_index_response.json', () => { - cy.visit(buildAdAppUrl(DASHBOARD)); + cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); }); cy.contains('h2', 'You have no detectors'); }); it('AD dashboard - single stopped detector', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visit(buildAdAppUrl(DASHBOARD)); + cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); }); cy.contains('h3', 'Live anomalies'); @@ -45,7 +45,7 @@ context('AD Dashboard', () => { it('AD dashboard - redirect to create detector', () => { cy.mockGetDetectorOnAction('no_detector_index_response.json', () => { - cy.visit(buildAdAppUrl(DASHBOARD)); + cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); }); cy.mockSearchIndexOnAction('search_index_response.json', () => { @@ -59,7 +59,7 @@ context('AD Dashboard', () => { it('Filter by detector', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visit(buildAdAppUrl(DASHBOARD)); + cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); }); cy.contains('stopped-detector'); @@ -68,9 +68,7 @@ context('AD Dashboard', () => { cy.get('[data-test-subj=comboBoxToggleListButton]') .first() .click({ force: true }); - cy.get('.euiFilterSelectItem') - .first() - .click({ force: true }); + cy.get('.euiFilterSelectItem').first().click({ force: true }); cy.get('.euiPageSideBar').click({ force: true }); cy.contains('feature-required-detector'); // first one in the list returned by multiple_detectors_response.json @@ -80,7 +78,7 @@ context('AD Dashboard', () => { it('Filter by detector state', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visit(buildAdAppUrl(DASHBOARD)); + cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); }); cy.contains('stopped-detector'); @@ -89,9 +87,7 @@ context('AD Dashboard', () => { cy.get('[data-test-subj=comboBoxToggleListButton]') .eq(1) .click({ force: true }); - cy.get('.euiFilterSelectItem') - .first() - .click({ force: true }); + cy.get('.euiFilterSelectItem').first().click({ force: true }); cy.get('.euiPageSideBar').click({ force: true }); cy.contains('stopped-detector'); // because stopped is the first item in the detector state dropdown diff --git a/.cypress/integration/ad/detectorList/detector_list.spec.ts b/.cypress/integration/ad/detectorList/detector_list.spec.ts index 369f3ec9..c7ee92f6 100644 --- a/.cypress/integration/ad/detectorList/detector_list.spec.ts +++ b/.cypress/integration/ad/detectorList/detector_list.spec.ts @@ -20,7 +20,7 @@ import { buildAdAppUrl } from '../../../utils/helpers'; context('Detector list', () => { it('Empty detectors - no detector index', () => { cy.mockGetDetectorOnAction('no_detector_index_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); cy.contains('p', '(0)'); @@ -33,7 +33,7 @@ context('Detector list', () => { it('Empty detectors - empty detector index', () => { cy.mockGetDetectorOnAction('empty_detector_index_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); cy.contains('p', '(0)'); @@ -46,7 +46,7 @@ context('Detector list', () => { it('One detector - single stopped detector index', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); cy.contains('p', '(1)'); @@ -58,7 +58,7 @@ context('Detector list', () => { it('Multiple detectors - multiple detectors index', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); cy.contains('p', '(4)'); @@ -79,7 +79,7 @@ context('Detector list', () => { it('Redirect to create detector', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); cy.get('[data-test-subj=addDetector]').click({ force: true }); cy.contains('h1', 'Create detector'); @@ -87,11 +87,9 @@ context('Detector list', () => { it('Start single detector', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); - cy.get('.euiCheckbox__input') - .last() - .click({ force: true }); + cy.get('.euiCheckbox__input').last().click({ force: true }); cy.get('[data-test-subj=listActionsButton]').click({ force: true }); cy.get('[data-test-subj=startDetectors]').click({ force: true }); cy.contains('The following detectors will begin initializing.'); @@ -108,11 +106,9 @@ context('Detector list', () => { it('Stop single detector', () => { cy.mockGetDetectorOnAction('single_running_detector_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); - cy.get('.euiCheckbox__input') - .last() - .click({ force: true }); + cy.get('.euiCheckbox__input').last().click({ force: true }); cy.get('[data-test-subj=listActionsButton]').click({ force: true }); cy.get('[data-test-subj=stopDetectors]').click({ force: true }); cy.contains('The following detectors will be stopped.'); @@ -129,11 +125,9 @@ context('Detector list', () => { it('Delete single detector', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); - cy.get('.euiCheckbox__input') - .last() - .click({ force: true }); + cy.get('.euiCheckbox__input').last().click({ force: true }); cy.get('[data-test-subj=listActionsButton]').click({ force: true }); cy.get('[data-test-subj=deleteDetectors]').click({ force: true }); cy.contains( @@ -157,7 +151,7 @@ context('Detector list', () => { it('Filter by detector search', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); cy.contains('stopped-detector'); @@ -174,7 +168,7 @@ context('Detector list', () => { it('Filter by detector state', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visit(buildAdAppUrl(DETECTORS)); + cy.visitWithAuth(buildAdAppUrl(DETECTORS)); }); cy.contains('stopped-detector'); @@ -183,9 +177,7 @@ context('Detector list', () => { cy.get('[data-test-subj=comboBoxToggleListButton]') .first() .click({ force: true }); - cy.get('.euiFilterSelectItem') - .first() - .click({ force: true }); + cy.get('.euiFilterSelectItem').first().click({ force: true }); cy.get('.euiPageSideBar').click({ force: true }); cy.contains('stopped-detector'); // because stopped is the first item in the detector state dropdown diff --git a/.cypress/integration/ad/workflow/create_detector.spec.ts b/.cypress/integration/ad/workflow/create_detector.spec.ts index 6fc76915..7e5f7b46 100644 --- a/.cypress/integration/ad/workflow/create_detector.spec.ts +++ b/.cypress/integration/ad/workflow/create_detector.spec.ts @@ -18,7 +18,7 @@ import { buildAdAppUrl } from '../../../utils/helpers'; context('Create detector', () => { it('Create detector - from dashboard', () => { cy.mockSearchIndexOnAction('search_index_response.json', () => { - cy.visit(buildAdAppUrl(CREATE_AD)); + cy.visitWithAuth(buildAdAppUrl(CREATE_AD)); }); cy.contains('h1', 'Create detector'); diff --git a/.cypress/support/commands.ts b/.cypress/support/commands.ts index b9e99e73..4e8500dd 100644 --- a/.cypress/support/commands.ts +++ b/.cypress/support/commands.ts @@ -23,7 +23,16 @@ import { } from '../utils/constants'; import { buildAdApiUrl } from '../utils/helpers'; -Cypress.Commands.add('mockGetDetectorOnAction', function( +Cypress.Commands.add('visitWithAuth', function (appUrl: string) { + cy.visit(appUrl, { + auth: { + username: 'admin', + password: 'admin', + }, + }); +}); + +Cypress.Commands.add('mockGetDetectorOnAction', function ( fixtureFileName: string, funcMockedOn: VoidFunction ) { @@ -39,7 +48,7 @@ Cypress.Commands.add('mockGetDetectorOnAction', function( cy.wait('@getDetectors'); }); -Cypress.Commands.add('mockCreateDetectorOnAction', function( +Cypress.Commands.add('mockCreateDetectorOnAction', function ( fixtureFileName: string, funcMockedOn: VoidFunction ) { @@ -55,7 +64,7 @@ Cypress.Commands.add('mockCreateDetectorOnAction', function( cy.wait('@createDetector'); }); -Cypress.Commands.add('mockSearchIndexOnAction', function( +Cypress.Commands.add('mockSearchIndexOnAction', function ( fixtureFileName: string, funcMockedOn: VoidFunction ) { @@ -71,7 +80,7 @@ Cypress.Commands.add('mockSearchIndexOnAction', function( cy.wait('@getIndices'); }); -Cypress.Commands.add('mockSearchOnAction', function( +Cypress.Commands.add('mockSearchOnAction', function ( fixtureFileName: string, funcMockedOn: VoidFunction ) { @@ -85,7 +94,7 @@ Cypress.Commands.add('mockSearchOnAction', function( cy.wait('@searchES'); }); -Cypress.Commands.add('mockGetIndexMappingsOnAction', function( +Cypress.Commands.add('mockGetIndexMappingsOnAction', function ( fixtureFileName: string, funcMockedOn: VoidFunction ) { @@ -101,7 +110,7 @@ Cypress.Commands.add('mockGetIndexMappingsOnAction', function( cy.wait('@getMappings'); }); -Cypress.Commands.add('mockStartDetectorOnAction', function( +Cypress.Commands.add('mockStartDetectorOnAction', function ( fixtureFileName: string, detectorId: string, funcMockedOn: VoidFunction @@ -118,7 +127,7 @@ Cypress.Commands.add('mockStartDetectorOnAction', function( cy.wait('@startDetector'); }); -Cypress.Commands.add('mockStopDetectorOnAction', function( +Cypress.Commands.add('mockStopDetectorOnAction', function ( fixtureFileName: string, detectorId: string, funcMockedOn: VoidFunction @@ -135,7 +144,7 @@ Cypress.Commands.add('mockStopDetectorOnAction', function( cy.wait('@stopDetector'); }); -Cypress.Commands.add('mockDeleteDetectorOnAction', function( +Cypress.Commands.add('mockDeleteDetectorOnAction', function ( fixtureFileName: string, detectorId: string, funcMockedOn: VoidFunction diff --git a/.cypress/support/index.d.ts b/.cypress/support/index.d.ts index 57c43ec3..7fbc2a9e 100644 --- a/.cypress/support/index.d.ts +++ b/.cypress/support/index.d.ts @@ -14,6 +14,7 @@ */ declare namespace Cypress { interface Chainable { + visitWithAuth(appUrl: string): Chainable; mockGetDetectorOnAction( fixtureFileName: string, funcMockedOn: VoidFunction diff --git a/.github/configurations/docker-compose.yml b/.github/configurations/docker-compose.yml new file mode 100644 index 00000000..ceb8cf9f --- /dev/null +++ b/.github/configurations/docker-compose.yml @@ -0,0 +1,46 @@ +version: '3' +services: + odfe-node1: + image: odfe-ad:test + container_name: odfe-node1 + environment: + - cluster.name=odfe-cluster + - node.name=odfe-node1 + - discovery.seed_hosts=odfe-node1 + - cluster.initial_master_nodes=odfe-node1 + - bootstrap.memory_lock=true # along with the memlock settings below, disables swapping + - 'ES_JAVA_OPTS=-Xms512m -Xmx512m' # minimum and maximum Java heap size, recommend setting both to 50% of system RAM + ulimits: + memlock: + soft: -1 + hard: -1 + nofile: + soft: 65536 # maximum number of open files for the Elasticsearch user, set to at least 65536 on modern systems + hard: 65536 + volumes: + - odfe-data1:/usr/share/elasticsearch/data + ports: + - 9200:9200 + - 9600:9600 # required for Performance Analyzer + expose: + - '9200' + networks: + - odfe-net + kibana: + image: odfe-ad-kibana:test + container_name: odfe-kibana + ports: + - 5601:5601 + expose: + - '5601' + environment: + ELASTICSEARCH_URL: https://odfe-node1:9200 + ELASTICSEARCH_HOSTS: https://odfe-node1:9200 + networks: + - odfe-net + +volumes: + odfe-data1: + +networks: + odfe-net: diff --git a/.github/workflows/CD.yml b/.github/workflows/CD.yml index 5e1a6910..6f673e2b 100644 --- a/.github/workflows/CD.yml +++ b/.github/workflows/CD.yml @@ -3,7 +3,8 @@ on: push: tags: - v* - +env: + KIBANA_VERSION: 7.8.0 jobs: Build-and-upload: name: Build and upload artifacts @@ -20,7 +21,7 @@ jobs: uses: actions/checkout@v2 with: repository: opendistro-for-elasticsearch/kibana-oss - ref: 7.8.0 + ref: ${{ env.KIBANA_VERSION }} token: ${{ secrets.KIBANA_OSS_ACCESS }} path: kibana diff --git a/.github/workflows/e2e-tests-workflow.yml b/.github/workflows/e2e-tests-workflow.yml index 74c978f3..0c9f521b 100644 --- a/.github/workflows/e2e-tests-workflow.yml +++ b/.github/workflows/e2e-tests-workflow.yml @@ -2,10 +2,99 @@ name: E2E tests workflow on: push: branches: - - master + - securityCI +env: + KIBANA_VERSION: 7.8.0 + ODFE_VERSION: 1.9.0 jobs: - tests: - name: Run e2e tests + test-with-security: + name: Run e2e tests with security + strategy: + matrix: + os: [ubuntu-16.04] # use ubuntu-16.04 as required by cypress: https://github.com/marketplace/actions/cypress-io#important + java: [14] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout Kibana + uses: actions/checkout@v2 + with: + repository: opendistro-for-elasticsearch/kibana-oss + ref: ${{ env.KIBANA_VERSION }} + token: ${{ secrets.KIBANA_OSS_ACCESS }} + path: kibana + + - name: Get node and yarn versions + id: versions_step + run: | + echo "::set-output name=node_version::$(node -p "(require('./kibana/package.json').engines.node).match(/[.0-9]+/)[0]")" + echo "::set-output name=yarn_version::$(node -p "(require('./kibana/package.json').engines.yarn).match(/[.0-9]+/)[0]")" + + - name: Setup node + uses: actions/setup-node@v1 + with: + node-version: ${{ steps.versions_step.outputs.node_version }} + registry-url: 'https://registry.npmjs.org' + + - name: Install correct yarn version for Kibana + run: | + npm uninstall -g yarn + echo "Installing yarn ${{ steps.versions_step.outputs.yarn_version }}" + npm i -g yarn@${{ steps.versions_step.outputs.yarn_version }} + + - name: Checkout Anomaly Detection Kibana plugin + uses: actions/checkout@v2 + with: + path: kibana/plugins/anomaly-detection-kibana-plugin + + - name: Bootstrap the plugin + run: | + cd kibana/plugins/anomaly-detection-kibana-plugin + yarn kbn bootstrap + + - name: Build the artifact + run: | + cd kibana/plugins/anomaly-detection-kibana-plugin + yarn build + + - name: Create tagged images for ES and Kibana + run: | + cd kibana/plugins/anomaly-detection-kibana-plugin + odfe_version=$ODFE_VERSION + plugin_version=$(node -pe "require('./package.json').version") + echo odfe version: $odfe_version + echo plugin version: $plugin_version + if docker pull opendistroforelasticsearch/opendistroforelasticsearch:$odfe_version + then + ## Populate the Dockerfiles + echo "FROM opendistroforelasticsearch/opendistroforelasticsearch:$odfe_version" >> Dockerfile-AD + echo "FROM opendistroforelasticsearch/opendistroforelasticsearch-kibana:$odfe_version" >> Dockerfile-AD-Kibana + echo "COPY build/opendistro-anomaly-detection-kibana-$plugin_version.zip ." >> Dockerfile-AD-Kibana + ## Uninstall existing AD artifact and install new one + echo "RUN if [ -d /usr/share/kibana/plugins/opendistro-anomaly-detection-kibana ]; then /usr/share/kibana/bin/kibana-plugin remove opendistro-anomaly-detection-kibana; fi" >> Dockerfile-AD-Kibana + echo "RUN bin/kibana-plugin install file:///usr/share/kibana/opendistro-anomaly-detection-kibana-$plugin_version.zip;" >> Dockerfile-AD-Kibana + + ## Create the tagged images + docker build -f ./Dockerfile-AD -t odfe-ad:test . + docker build -f ./Dockerfile-AD-Kibana -t odfe-ad-kibana:test . + fi + docker images + + - name: Start ES and Kibana + run: | + cd kibana/plugins/anomaly-detection-kibana-plugin/.github/configurations + ## Need to increase max map count for running the docker container + sudo sysctl -w vm.max_map_count=262144 + docker-compose up -d + sleep 180 + + - name: Run e2e tests + uses: cypress-io/github-action@v1 + with: + working-directory: kibana/plugins/anomaly-detection-kibana-plugin + command: yarn cy:run + + test-without-security: + name: Run e2e tests without security strategy: matrix: os: [ubuntu-16.04] # use ubuntu-16.04 as required by cypress: https://github.com/marketplace/actions/cypress-io#important @@ -14,11 +103,11 @@ jobs: steps: - name: Pull and Run Docker run: | - version=1.9.0 - echo $version - if docker pull opendistroforelasticsearch/opendistroforelasticsearch:$version + odfe_version=$ODFE_VERSION + echo odfe version: $odfe_version + if docker pull opendistroforelasticsearch/opendistroforelasticsearch:$odfe_version then - echo "FROM opendistroforelasticsearch/opendistroforelasticsearch:$version" >> Dockerfile + echo "FROM opendistroforelasticsearch/opendistroforelasticsearch:$odfe_version" >> Dockerfile ## The ESRestTest Client uses http by default. ## Need to disable the security plugin to call the rest api over http. echo "RUN if [ -d /usr/share/elasticsearch/plugins/opendistro_security ]; then /usr/share/elasticsearch/bin/elasticsearch-plugin remove opendistro_security; fi" >> Dockerfile @@ -29,12 +118,11 @@ jobs: docker run -p 9200:9200 -d -p 9600:9600 -e "discovery.type=single-node" odfe-ad:test sleep 90 curl -XGET http://localhost:9200/_cat/plugins - - name: Checkout Kibana uses: actions/checkout@v2 with: repository: opendistro-for-elasticsearch/kibana-oss - ref: 7.8.0 + ref: ${{ env.KIBANA_VERSION }} token: ${{ secrets.KIBANA_OSS_ACCESS }} path: kibana - name: Get node and yarn versions diff --git a/.github/workflows/unit-tests-workflow.yml b/.github/workflows/unit-tests-workflow.yml index 7e92837a..2cecd6da 100644 --- a/.github/workflows/unit-tests-workflow.yml +++ b/.github/workflows/unit-tests-workflow.yml @@ -3,7 +3,8 @@ on: push: branches: - master - +env: + KIBANA_VERSION: 7.8.0 jobs: tests: name: Run unit tests @@ -16,7 +17,7 @@ jobs: uses: actions/checkout@v2 with: repository: opendistro-for-elasticsearch/kibana-oss - ref: 7.8.0 + ref: ${{ env.KIBANA_VERSION }} token: ${{ secrets.KIBANA_OSS_ACCESS }} path: kibana - name: Get node and yarn versions diff --git a/cypress.json b/cypress.json index e5441904..ba17fddb 100644 --- a/cypress.json +++ b/cypress.json @@ -7,7 +7,7 @@ "screenshotsFolder": ".cypress/screenshots", "supportFile": ".cypress/support/index.js", "videosFolder": ".cypress/videos", - "requestTimeout": 60000, - "responseTimeout": 60000, - "defaultCommandTimeout": 60000 + "requestTimeout": 90000, + "responseTimeout": 90000, + "defaultCommandTimeout": 90000 } From 9d27c5921926a15bb62a7bd5c10e5bd5f2f853d2 Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Wed, 29 Jul 2020 11:26:23 -0700 Subject: [PATCH 2/5] Change back to master --- .github/workflows/e2e-tests-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e-tests-workflow.yml b/.github/workflows/e2e-tests-workflow.yml index 0c9f521b..8483f63f 100644 --- a/.github/workflows/e2e-tests-workflow.yml +++ b/.github/workflows/e2e-tests-workflow.yml @@ -2,7 +2,7 @@ name: E2E tests workflow on: push: branches: - - securityCI + - master env: KIBANA_VERSION: 7.8.0 ODFE_VERSION: 1.9.0 From 2ba5bddd12ab80712528bd2109b08935895a3f3a Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Wed, 29 Jul 2020 15:29:12 -0700 Subject: [PATCH 3/5] Change to overwrite existing visit() --- .../ad/dashboard/ad_dashboard.spec.ts | 12 +++++------ .../ad/detectorList/detector_list.spec.ts | 20 +++++++++---------- .../ad/workflow/create_detector.spec.ts | 2 +- .cypress/support/commands.ts | 18 ++++++++++------- .cypress/support/index.d.ts | 1 - .github/workflows/e2e-tests-workflow.yml | 4 ++-- cypress.json | 5 ++++- 7 files changed, 34 insertions(+), 28 deletions(-) diff --git a/.cypress/integration/ad/dashboard/ad_dashboard.spec.ts b/.cypress/integration/ad/dashboard/ad_dashboard.spec.ts index d450d0a6..6161e947 100644 --- a/.cypress/integration/ad/dashboard/ad_dashboard.spec.ts +++ b/.cypress/integration/ad/dashboard/ad_dashboard.spec.ts @@ -19,21 +19,21 @@ import { buildAdAppUrl } from '../../../utils/helpers'; context('AD Dashboard', () => { it('Empty dashboard - no detector index', () => { cy.mockGetDetectorOnAction('no_detector_index_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); + cy.visit(buildAdAppUrl(DASHBOARD)); }); cy.contains('h2', 'You have no detectors'); }); it('Empty dashboard - empty detector index', () => { cy.mockGetDetectorOnAction('empty_detector_index_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); + cy.visit(buildAdAppUrl(DASHBOARD)); }); cy.contains('h2', 'You have no detectors'); }); it('AD dashboard - single stopped detector', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); + cy.visit(buildAdAppUrl(DASHBOARD)); }); cy.contains('h3', 'Live anomalies'); @@ -45,7 +45,7 @@ context('AD Dashboard', () => { it('AD dashboard - redirect to create detector', () => { cy.mockGetDetectorOnAction('no_detector_index_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); + cy.visit(buildAdAppUrl(DASHBOARD)); }); cy.mockSearchIndexOnAction('search_index_response.json', () => { @@ -59,7 +59,7 @@ context('AD Dashboard', () => { it('Filter by detector', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); + cy.visit(buildAdAppUrl(DASHBOARD)); }); cy.contains('stopped-detector'); @@ -78,7 +78,7 @@ context('AD Dashboard', () => { it('Filter by detector state', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DASHBOARD)); + cy.visit(buildAdAppUrl(DASHBOARD)); }); cy.contains('stopped-detector'); diff --git a/.cypress/integration/ad/detectorList/detector_list.spec.ts b/.cypress/integration/ad/detectorList/detector_list.spec.ts index c7ee92f6..d9944c7c 100644 --- a/.cypress/integration/ad/detectorList/detector_list.spec.ts +++ b/.cypress/integration/ad/detectorList/detector_list.spec.ts @@ -20,7 +20,7 @@ import { buildAdAppUrl } from '../../../utils/helpers'; context('Detector list', () => { it('Empty detectors - no detector index', () => { cy.mockGetDetectorOnAction('no_detector_index_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.contains('p', '(0)'); @@ -33,7 +33,7 @@ context('Detector list', () => { it('Empty detectors - empty detector index', () => { cy.mockGetDetectorOnAction('empty_detector_index_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.contains('p', '(0)'); @@ -46,7 +46,7 @@ context('Detector list', () => { it('One detector - single stopped detector index', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.contains('p', '(1)'); @@ -58,7 +58,7 @@ context('Detector list', () => { it('Multiple detectors - multiple detectors index', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.contains('p', '(4)'); @@ -79,7 +79,7 @@ context('Detector list', () => { it('Redirect to create detector', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.get('[data-test-subj=addDetector]').click({ force: true }); cy.contains('h1', 'Create detector'); @@ -87,7 +87,7 @@ context('Detector list', () => { it('Start single detector', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.get('.euiCheckbox__input').last().click({ force: true }); cy.get('[data-test-subj=listActionsButton]').click({ force: true }); @@ -106,7 +106,7 @@ context('Detector list', () => { it('Stop single detector', () => { cy.mockGetDetectorOnAction('single_running_detector_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.get('.euiCheckbox__input').last().click({ force: true }); cy.get('[data-test-subj=listActionsButton]').click({ force: true }); @@ -125,7 +125,7 @@ context('Detector list', () => { it('Delete single detector', () => { cy.mockGetDetectorOnAction('single_stopped_detector_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.get('.euiCheckbox__input').last().click({ force: true }); cy.get('[data-test-subj=listActionsButton]').click({ force: true }); @@ -151,7 +151,7 @@ context('Detector list', () => { it('Filter by detector search', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.contains('stopped-detector'); @@ -168,7 +168,7 @@ context('Detector list', () => { it('Filter by detector state', () => { cy.mockGetDetectorOnAction('multiple_detectors_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(DETECTORS)); + cy.visit(buildAdAppUrl(DETECTORS)); }); cy.contains('stopped-detector'); diff --git a/.cypress/integration/ad/workflow/create_detector.spec.ts b/.cypress/integration/ad/workflow/create_detector.spec.ts index 7e5f7b46..6fc76915 100644 --- a/.cypress/integration/ad/workflow/create_detector.spec.ts +++ b/.cypress/integration/ad/workflow/create_detector.spec.ts @@ -18,7 +18,7 @@ import { buildAdAppUrl } from '../../../utils/helpers'; context('Create detector', () => { it('Create detector - from dashboard', () => { cy.mockSearchIndexOnAction('search_index_response.json', () => { - cy.visitWithAuth(buildAdAppUrl(CREATE_AD)); + cy.visit(buildAdAppUrl(CREATE_AD)); }); cy.contains('h1', 'Create detector'); diff --git a/.cypress/support/commands.ts b/.cypress/support/commands.ts index 4e8500dd..0299eab2 100644 --- a/.cypress/support/commands.ts +++ b/.cypress/support/commands.ts @@ -23,13 +23,17 @@ import { } from '../utils/constants'; import { buildAdApiUrl } from '../utils/helpers'; -Cypress.Commands.add('visitWithAuth', function (appUrl: string) { - cy.visit(appUrl, { - auth: { - username: 'admin', - password: 'admin', - }, - }); +Cypress.Commands.overwrite('visit', (orig, url, options) => { + if (Cypress.env('SECURITY_ENABLED')) { + orig(url, options, { + auth: { + username: 'admin', + password: 'admin', + }, + }); + } else { + orig(url, options); + } }); Cypress.Commands.add('mockGetDetectorOnAction', function ( diff --git a/.cypress/support/index.d.ts b/.cypress/support/index.d.ts index 7fbc2a9e..57c43ec3 100644 --- a/.cypress/support/index.d.ts +++ b/.cypress/support/index.d.ts @@ -14,7 +14,6 @@ */ declare namespace Cypress { interface Chainable { - visitWithAuth(appUrl: string): Chainable; mockGetDetectorOnAction( fixtureFileName: string, funcMockedOn: VoidFunction diff --git a/.github/workflows/e2e-tests-workflow.yml b/.github/workflows/e2e-tests-workflow.yml index 8483f63f..fb3a8418 100644 --- a/.github/workflows/e2e-tests-workflow.yml +++ b/.github/workflows/e2e-tests-workflow.yml @@ -2,7 +2,7 @@ name: E2E tests workflow on: push: branches: - - master + - securityCI env: KIBANA_VERSION: 7.8.0 ODFE_VERSION: 1.9.0 @@ -91,7 +91,7 @@ jobs: uses: cypress-io/github-action@v1 with: working-directory: kibana/plugins/anomaly-detection-kibana-plugin - command: yarn cy:run + command: yarn cy:run --env SECURITY_ENABLED=true test-without-security: name: Run e2e tests without security diff --git a/cypress.json b/cypress.json index ba17fddb..e4ef2026 100644 --- a/cypress.json +++ b/cypress.json @@ -9,5 +9,8 @@ "videosFolder": ".cypress/videos", "requestTimeout": 90000, "responseTimeout": 90000, - "defaultCommandTimeout": 90000 + "defaultCommandTimeout": 90000, + "env": { + "SECURITY_ENABLED": false + } } From af862033c5b491859f9c5b3842156331034593df Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Wed, 29 Jul 2020 16:35:22 -0700 Subject: [PATCH 4/5] Mimic cy.visit() behavior --- .cypress/support/commands.ts | 17 +++++++++++++---- README.md | 5 +++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.cypress/support/commands.ts b/.cypress/support/commands.ts index 0299eab2..e41b7105 100644 --- a/.cypress/support/commands.ts +++ b/.cypress/support/commands.ts @@ -25,12 +25,21 @@ import { buildAdApiUrl } from '../utils/helpers'; Cypress.Commands.overwrite('visit', (orig, url, options) => { if (Cypress.env('SECURITY_ENABLED')) { - orig(url, options, { - auth: { + let newOptions = options; + if (options) { + newOptions['auth'] = { username: 'admin', password: 'admin', - }, - }); + }; + } else { + newOptions = { + auth: { + username: 'admin', + password: 'admin', + }, + }; + } + orig(url, newOptions); } else { orig(url, options); } diff --git a/README.md b/README.md index 309e7533..23de8fd9 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,11 @@ Example output: `./build/opendistro-anomaly-detection-kibana-1.9.0.0.zip` Start Kibana, wait for it to be available on `localhost:5601`, and runs end-to-end tests. +- `yarn cy:run` + + Runs end-to-end tests on a currently running Kibana server. Defaults to run the tests on `localhost:5601`, although you can change this to run on any + Kibana server with the command `yarn cy:run --config baseUrl=` + ## Contributing to Open Distro for Elasticsearch Anomaly detection Kibana We welcome you to get involved in development, documentation, testing the anomaly detection plugin. See our [CONTRIBUTING.md](./CONTRIBUTING.md) and join in. From 5943ac0d5c4db0c3f6902cef9431b549bc90bafc Mon Sep 17 00:00:00 2001 From: Tyler Ohlsen Date: Wed, 29 Jul 2020 16:49:51 -0700 Subject: [PATCH 5/5] Add yarn script --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 88ade999..9f52ac66 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "start-cy-server": "yarn start --no-base-path --oss", "cy:open": "cypress open", "cy:run": "cypress run", + "cy:run-with-security": "cypress run --env SECURITY_ENABLED=true", "test:e2e": "CHOKIDAR_USEPOLLING=1 CYPRESS_responseTimeout=180000 WAIT_ON_TIMEOUT=900000 start-server-and-test 'yarn start-cy-server' http-get://localhost:5601/app/opendistro-anomaly-detection-kibana 'echo sleeping to wait for server to get ready && sleep 180 && yarn cy:run'" }, "lint-staged": {