Skip to content

Commit

Permalink
Added some infrastructure to run cypress tests. (#60)
Browse files Browse the repository at this point in the history
Signed-off-by: AWSHurneyt <[email protected]>

Signed-off-by: AWSHurneyt <[email protected]>
(cherry picked from commit aadba34)
  • Loading branch information
AWSHurneyt authored and github-actions[bot] committed Nov 4, 2022
1 parent 06bd81f commit 93b9dfc
Show file tree
Hide file tree
Showing 6 changed files with 354 additions and 0 deletions.
95 changes: 95 additions & 0 deletions .github/workflows/cypress-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
name: Cypress integration tests workflow
on:
pull_request:
branches:
- "*"
push:
branches:
- "*"
env:
OPENSEARCH_DASHBOARDS_VERSION: '2.4'
OPENSEARCH_VERSION: '2.4.0-SNAPSHOT'
jobs:
tests:
name: Run Cypress E2E tests
runs-on: ubuntu-latest
env:
# prevents extra Cypress installation progress messages
CI: 1
# avoid warnings like "tput: No value for $TERM and no -T specified"
TERM: xterm
steps:
- name: Set up JDK
uses: actions/setup-java@v1
with:
# TODO: Parse this from security analytics plugin
java-version: 11
- name: Checkout index management
uses: actions/checkout@v2
with:
path: security-analytics
repository: opensearch-project/security-analytics
ref: '2.4'
- name: Run opensearch with plugin
run: |
cd security-analytics
./gradlew run -Dopensearch.version=${{ env.OPENSEARCH_VERSION }} &
sleep 300
# timeout 300 bash -c 'while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:9200)" != "200" ]]; do sleep 5; done'
- name: Checkout Security Analytics Dashboards plugin
uses: actions/checkout@v2
with:
path: security-analytics-dashboards-plugin
- name: Checkout OpenSearch-Dashboards
uses: actions/checkout@v2
with:
repository: opensearch-project/OpenSearch-Dashboards
path: OpenSearch-Dashboards
ref: ${{ env.OPENSEARCH_DASHBOARDS_VERSION }}
- name: Get node and yarn versions
id: versions
run: |
echo "::set-output name=node_version::$(node -p "(require('./OpenSearch-Dashboards/package.json').engines.node).match(/[.0-9]+/)[0]")"
echo "::set-output name=yarn_version::$(node -p "(require('./OpenSearch-Dashboards/package.json').engines.yarn).match(/[.0-9]+/)[0]")"
- name: Setup node
uses: actions/setup-node@v1
with:
node-version: ${{ steps.versions.outputs.node_version }}
registry-url: 'https://registry.npmjs.org'
- name: Install correct yarn version for OpenSearch-Dashboards
run: |
npm uninstall -g yarn
echo "Installing yarn ${{ steps.versions_step.outputs.yarn_version }}"
npm i -g yarn@${{ steps.versions.outputs.yarn_version }}
- name: Bootstrap plugin/OpenSearch-Dashboards
run: |
mkdir -p OpenSearch-Dashboards/plugins
mv security-analytics-dashboards-plugin OpenSearch-Dashboards/plugins
cd OpenSearch-Dashboards/plugins/security-analytics-dashboards-plugin
yarn osd bootstrap
- name: Run OpenSearch-Dashboards server
run: |
cd OpenSearch-Dashboards
yarn start --no-base-path --no-watch &
sleep 300
# timeout 300 bash -c 'while [[ "$(curl -s localhost:5601/api/status | jq -r '.status.overall.state')" != "green" ]]; do sleep 5; done'
# for now just chrome, use matrix to do all browsers later
- name: Cypress tests
uses: cypress-io/github-action@v2
with:
working-directory: OpenSearch-Dashboards/plugins/security-analytics-dashboards-plugin
command: yarn run cypress run
wait-on: 'http://localhost:5601'
browser: chrome
# Screenshots are only captured on failure, will change this once we do visual regression tests
- uses: actions/upload-artifact@v1
if: failure()
with:
name: cypress-screenshots
path: OpenSearch-Dashboards/plugins/security-analytics-dashboards-plugin/cypress/screenshots
# Test run video was always captured, so this action uses "always()" condition
- uses: actions/upload-artifact@v1
if: always()
with:
name: cypress-videos
path: OpenSearch-Dashboards/plugins/security-analytics-dashboards-plugin/cypress/videos
45 changes: 45 additions & 0 deletions cypress/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)

// TODO: yarn osd bootstrap fails when trying to add below package as a dependency..
// const wp = require("@cypress/webpack-preprocessor");
//
/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on) => {
// const options = {
// webpackOptions: {
// resolve: {
// extensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
// },
// module: {
// rules: [
// {
// test: /\.tsx?$/,
// loader: "ts-loader",
// options: { transpileOnly: true },
// },
// ],
// },
// },
// };
//
// on("file:preprocessor", wp(options));
};
115 changes: 115 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

const { ADMIN_AUTH, INDICES, NODE_API, PLUGIN_NAME } = require('./constants');

// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })

Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
// Add the basic auth header when security enabled in the Opensearch cluster
// https://github.com/cypress-io/cypress/issues/1288
if (Cypress.env('security_enabled')) {
const ADMIN_AUTH = {
username: Cypress.env('username'),
password: Cypress.env('password'),
};
if (options) {
options.auth = ADMIN_AUTH;
} else {
options = { auth: ADMIN_AUTH };
}
// Add query parameters - select the default OSD tenant
options.qs = { security_tenant: 'private' };
return originalFn(url, options);
} else {
return originalFn(url, options);
}
});

// Be able to add default options to cy.request(), https://github.com/cypress-io/cypress/issues/726
Cypress.Commands.overwrite('request', (originalFn, ...args) => {
let defaults = {};
// Add the basic authentication header when security enabled in the Opensearch cluster
const ADMIN_AUTH = {
username: Cypress.env('username'),
password: Cypress.env('password'),
};
if (Cypress.env('security_enabled')) {
defaults.auth = ADMIN_AUTH;
}

let options = {};
if (typeof args[0] === 'object' && args[0] !== null) {
options = Object.assign({}, args[0]);
} else if (args.length === 1) {
[options.url] = args;
} else if (args.length === 2) {
[options.method, options.url] = args;
} else if (args.length === 3) {
[options.method, options.url, options.body] = args;
}

return originalFn(Object.assign({}, defaults, options));
});

Cypress.Commands.add('deleteAllIndices', () => {
cy.request('DELETE', `${Cypress.env('opensearch')}/index*,sample*,opensearch_dashboards*,test*`);
});

Cypress.Commands.add('createDetector', (detectorJSON) => {
cy.request('POST', `${Cypress.env('opensearch')}${NODE_API.DETECTORS_BASE}`, detectorJSON);
});

Cypress.Commands.add('updateDetector', (detectorId, detectorJSON) => {
cy.request(
'PUT',
`${Cypress.env('opensearch')}/${NODE_API.DETECTORS_BASE}/${detectorId}`,
detectorJSON
);
});

Cypress.Commands.add('createRule', (ruleJSON) => {
cy.request('POST', `${Cypress.env('opensearch')}${NODE_API.RULES_BASE}`, ruleJSON);
});

Cypress.Commands.add('updateRule', (ruleId, ruleJSON) => {
cy.request('PUT', `${Cypress.env('opensearch')}/${NODE_API.RULES_BASE}/${ruleId}`, ruleJSON);
});

Cypress.Commands.add('createIndex', (index, settings = {}) => {
cy.request('PUT', `${Cypress.env('opensearch')}/${index}`, settings);
});

Cypress.Commands.add('createIndexTemplate', (name, template) => {
cy.request(
'PUT',
`${Cypress.env('opensearch')}${NODE_API.INDEX_TEMPLATE_BASE}/${name}`,
template
);
});
21 changes: 21 additions & 0 deletions cypress/support/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { API } from '../../server/utils/constants';

export const TWENTY_SECONDS = 20000;

export const INDICES = {
DETECTORS_INDEX: '.opensearch-detectors-config',
PRE_PACKAGED_RULES_INDEX: '.opensearch-pre-packaged-rules-config',
CUSTOM_RULES_INDEX: '.opensearch-custom-rules-config',
};

export const PLUGIN_NAME = 'opensearch_index_management_dashboards';

export const NODE_API = {
...API,
INDEX_TEMPLATE_BASE: '/_index_template',
};
45 changes: 45 additions & 0 deletions cypress/support/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

/// <reference types="cypress" />

declare namespace Cypress {
interface Chainable<Subject> {
/**
* Deletes all indices in cluster
* @example
* cy.deleteAllIndices()
*/
deleteAllIndices(): Chainable<any>;

/**
* Creates a detector
* @example
* cy.createPolicy({ "detector_type": ... })
*/
createDetector(detectorJSON: object): Chainable<any>;

/**
* Updates settings for index
* @example
* cy.updateIndexSettings("some_index", settings)
*/
updateDetector(detectorId: string, detectorJSON: object): Chainable<any>;

/**
* Creates index with policy
* @example
* cy.createIndex("some_index", "some_policy")
*/
createIndex(index: string, settings?: object): Chainable<any>;

/**
* Creates an index template.
* @example
* cy.createIndexTemplate("some_index_template", { "index_patterns": "abc", "properties": { ... } })
*/
createIndexTemplate(name: string, template: object): Chainable<any>;
}
}
33 changes: 33 additions & 0 deletions cypress/support/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands';

// Alternatively you can use CommonJS syntax:
// require('./commands')

const resizeObserverLoopErrRe = /^[^(ResizeObserver loop limit exceeded)]/;
Cypress.on('uncaught:exception', (err) => {
/* returning false here prevents Cypress from failing the test */
if (resizeObserverLoopErrRe.test(err.message)) {
return false;
}
});

// Switch the base URL of Opensearch when security enabled in the cluster
// Not doing this for Dashboards because it can still use http when security enabled
if (Cypress.env('security_enabled')) {
Cypress.env('opensearch', `https://${Cypress.env('opensearch_url')}`);
} else {
Cypress.env('opensearch', `http://${Cypress.env('opensearch_url')}`);
}

0 comments on commit 93b9dfc

Please sign in to comment.