Skip to content

Commit 273dbf8

Browse files
authored
backport #741 (#747)
Signed-off-by: Kaituo Li <kaituo@amazon.com>
1 parent 2715968 commit 273dbf8

7 files changed

+236
-98
lines changed

.github/workflows/build-and-test-workflow.yml

+6
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ jobs:
8888
run: |
8989
cd OpenSearch-Dashboards/plugins/anomaly-detection-dashboards-plugin
9090
yarn osd bootstrap --single-version=loose
91+
- name: Set npm to use bash for shell
92+
if: ${{ matrix.os == 'windows-latest' }}
93+
run: |
94+
# Sets Windows to use bash for npm shell so the script (e.g., environment variable resolution in package.json postbuild script)
95+
# commands work as intended
96+
npm config set script-shell "C:\\Program Files\\git\\bin\\bash.exe"
9197
- name: Build the plugin
9298
run: |
9399
cd OpenSearch-Dashboards/plugins/anomaly-detection-dashboards-plugin
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,175 @@
1-
# Running AD integ tests stored in https://github.com/opensearch-project/opensearch-dashboards-functional-test
2-
# In the future we should pull dependencies from bundled build snapshots. Because that is not available
3-
# yet we build the cluster from source (besides core Opensearch, which is a pulled min artifact).
4-
name: Remote integ tests workflow
5-
on:
6-
push:
7-
branches:
8-
- "*"
9-
pull_request:
10-
branches:
11-
- "*"
1+
name: FTR E2E AD Workbench Test
2+
3+
on: [pull_request, push]
4+
5+
env:
6+
CI: 1
7+
# avoid warnings like "tput: No value for $TERM and no -T specified"
8+
TERM: xterm
9+
OPENSEARCH_DASHBOARDS_VERSION: '2.x'
10+
1211
jobs:
13-
test-without-security:
14-
name: Run integ tests without security
12+
tests:
13+
name: Run FTR E2E AD Workbench Tests
1514
strategy:
15+
fail-fast: false
1616
matrix:
17-
os: [ubuntu-latest, windows-latest]
18-
java: [11]
19-
include:
20-
- os: windows-latest
21-
cypress_cache_folder: ~/AppData/Local/Cypress/Cache
22-
- os: ubuntu-latest
23-
cypress_cache_folder: ~/.cache/Cypress
17+
os: [ ubuntu-latest ]
18+
jdk: [ 11 ]
2419
runs-on: ${{ matrix.os }}
20+
2521
steps:
26-
- name: Set up Java 11
27-
uses: actions/setup-java@v3
22+
- name: Set up JDK
23+
uses: actions/setup-java@v1
2824
with:
29-
distribution: 'corretto'
30-
java-version: '11'
25+
java-version: ${{ matrix.jdk }}
3126

32-
- name: Enable longer filenames
33-
if: ${{ matrix.os == 'windows-latest' }}
34-
run: git config --system core.longpaths true
27+
- name: Checkout Anomaly-Detection
28+
uses: actions/checkout@v2
29+
with:
30+
path: anomaly-detection
31+
repository: opensearch-project/anomaly-detection
32+
ref: ${{ env.OPENSEARCH_DASHBOARDS_VERSION }}
33+
34+
- name: Run OpenSearch with plugin
35+
run: |
36+
cd anomaly-detection
37+
./gradlew run &
38+
timeout 300 bash -c 'while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:9200)" != "200" ]]; do sleep 5; done'
39+
shell: bash
40+
41+
- name: Check OpenSearch Running on Linux
42+
if: ${{ runner.os != 'Windows'}}
43+
run: curl http://localhost:9200/
44+
shell: bash
3545

3646
- name: Checkout OpenSearch Dashboards
3747
uses: actions/checkout@v2
3848
with:
39-
repository: opensearch-project/OpenSearch-Dashboards
40-
ref: '${{ github.base_ref }}'
4149
path: OpenSearch-Dashboards
50+
repository: opensearch-project/OpenSearch-Dashboards
51+
ref: ${{ env.OPENSEARCH_DASHBOARDS_VERSION }}
52+
fetch-depth: 0
53+
filter: |
54+
cypress
55+
test
4256
43-
- name: Checkout Anomaly Detection OpenSearch Dashboards plugin
57+
- name: Checkout AD in OpenSearch Dashboards Plugins Dir
4458
uses: actions/checkout@v2
4559
with:
46-
path: OpenSearch-Dashboards/plugins/anomaly-detection-dashboards-plugin
60+
path: OpenSearch-Dashboards/plugins/anomaly-detection-dashboards-plugin
4761

48-
- name: Setup Node
49-
uses: actions/setup-node@v3
50-
with:
51-
node-version-file: './OpenSearch-Dashboards/.nvmrc'
52-
registry-url: 'https://registry.npmjs.org'
53-
54-
- name: Install Yarn
55-
# Need to use bash to avoid having a windows/linux specific step
56-
shell: bash
62+
- id: tool-versions
5763
run: |
58-
YARN_VERSION=$(node -p "require('./OpenSearch-Dashboards/package.json').engines.yarn")
59-
echo "Installing yarn@$YARN_VERSION"
60-
npm i -g yarn@$YARN_VERSION
61-
62-
- run: node -v
63-
- run: yarn -v
64+
echo "node_version=$(cat .node-version)" >> $GITHUB_OUTPUT
65+
echo "yarn_version=$(jq -r '.engines.yarn' package.json)" >> $GITHUB_OUTPUT
66+
working-directory: OpenSearch-Dashboards
67+
shell: bash
6468

65-
- name: Checkout Anomaly-Detection
66-
uses: actions/checkout@v2
69+
- uses: actions/setup-node@v1
6770
with:
68-
path: anomaly-detection
69-
repository: opensearch-project/anomaly-detection
70-
ref: '${{ github.base_ref }}'
71+
node-version: ${{ steps.tool-versions.outputs.node_version }}
72+
registry-url: 'https://registry.npmjs.org'
7173

72-
- name: Run OpenSearch with plugin
74+
- name: Setup Opensearch Dashboards
7375
run: |
74-
cd anomaly-detection
75-
CONFIG_PATH=../OpenSearch-Dashboards/plugins/anomaly-detection-dashboards-plugin/opensearch_dashboards.json
76-
OPENSEARCH_VERSION=$(node -p "require('$CONFIG_PATH').opensearchDashboardsVersion")-SNAPSHOT
77-
echo "Using OpenSearch version $OPENSEARCH_VERSION"
78-
./gradlew run -Dopensearch.version=$OPENSEARCH_VERSION &
79-
timeout 300 bash -c 'while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:9200)" != "200" ]]; do sleep 5; done'
76+
npm uninstall -g yarn
77+
echo "Installing yarn ${{ steps.tool-versions.outputs.yarn_version }}"
78+
npm i -g yarn@${{ steps.tool-versions.outputs.yarn_version }}
79+
yarn cache clean
80+
yarn add sha.js
81+
working-directory: OpenSearch-Dashboards
8082
shell: bash
8183

82-
- name: Bootstrap the plugin
84+
- name: Boodstrap Opensearch Dashboards
8385
run: |
84-
cd OpenSearch-Dashboards/plugins/anomaly-detection-dashboards-plugin
8586
yarn osd bootstrap --single-version=loose
87+
working-directory: OpenSearch-Dashboards/plugins/anomaly-detection-dashboards-plugin
8688

87-
- name: Run OpenSearch Dashboards server
89+
- name: Run Opensearch Dashboards with AD Installed
8890
run: |
89-
cd OpenSearch-Dashboards
90-
yarn start --no-base-path --no-watch &
91-
shell: bash
91+
nohup yarn start --no-base-path --no-watch --server.host="0.0.0.0" | tee dashboard.log &
92+
working-directory: OpenSearch-Dashboards
9293

93-
# Window is slow so wait longer
94-
- name: Sleep until OSD server starts - windows
95-
if: ${{ matrix.os == 'windows-latest' }}
96-
run: Start-Sleep -s 400
97-
shell: powershell
94+
- name : Check If OpenSearch Dashboards Is Ready
95+
if: ${{ runner.os == 'Linux' }}
96+
run: |
97+
if timeout 600 grep -q "bundles compiled successfully after" <(tail -n0 -f dashboard.log); then
98+
echo "OpenSearch Dashboards compiled successfully."
99+
else
100+
echo "Timeout for 600 seconds reached. OpenSearch Dashboards did not finish compiling."
101+
exit 1
102+
fi
103+
working-directory: OpenSearch-Dashboards
104+
105+
- name: Show OpenSearch Dashboards Logs
106+
if: always()
107+
run: cat dashboard.log
108+
working-directory: OpenSearch-Dashboards
109+
110+
- name: Health check
111+
run: |
112+
timeout 600 bash -c 'while [[ "$(curl -k http://localhost:5601/api/status | jq -r '.status.overall.state')" != "green" ]]; do sleep 5; done'
113+
shell: bash
98114

99-
- name: Sleep until OSD server starts - non-windows
100-
if: ${{ matrix.os != 'windows-latest' }}
101-
run: sleep 300
115+
- name: Check OpenSearch Dashboards Running on Linux
116+
if: ${{ runner.os != 'Windows'}}
117+
run: curl http://localhost:5601/api/status
102118
shell: bash
103119

104-
- name: Checkout opensearch-dashboards-functional-test
120+
- name: Checkout Dashboards Functional Test Repo
105121
uses: actions/checkout@v2
106122
with:
107123
path: opensearch-dashboards-functional-test
108124
repository: opensearch-project/opensearch-dashboards-functional-test
109-
ref: '${{ github.base_ref }}'
125+
ref: ${{ env.OPENSEARCH_DASHBOARDS_VERSION }}
126+
fetch-depth: 0
127+
128+
- name: Install Cypress
129+
run: |
130+
npm install cypress --save-dev
131+
shell: bash
132+
working-directory: opensearch-dashboards-functional-test
110133

111134
- name: Get Cypress version
112135
id: cypress_version
113136
run: |
114-
echo "::set-output name=cypress_version::$(cat ./opensearch-dashboards-functional-test/package.json | jq '.devDependencies.cypress' | tr -d '"')"
137+
echo "::set-output name=cypress_version::$(cat ./package.json | jq '.dependencies.cypress' | tr -d '"')"
138+
working-directory: opensearch-dashboards-functional-test
115139

116-
- name: Cache Cypress
117-
id: cache-cypress
118-
uses: actions/cache@v1
140+
- name: Finding spec files and store to output
141+
id: finding-files
142+
run: |
143+
echo "::set-output name=FILELIST::$(find cypress/integration/plugins/anomaly-detection-dashboards-plugin -name '*.js' -print)"
144+
working-directory: opensearch-dashboards-functional-test
145+
146+
- name: Print spec files from output
147+
run: |
148+
IFS="," read -a myarray <<< ${{ steps.finding-files.outputs.FILELIST }}
149+
for i in "${myarray[@]}"; do
150+
echo "${i}"
151+
done
152+
working-directory: opensearch-dashboards-functional-test
153+
154+
- name: Run spec files from output
155+
run: |
156+
IFS="," read -a myarray <<< ${{ steps.finding-files.outputs.FILELIST }}
157+
for i in "${myarray[@]}"; do
158+
yarn cypress:run-without-security --browser electron --spec "${i}"
159+
sleep 60
160+
done
161+
working-directory: opensearch-dashboards-functional-test
162+
163+
- name: Capture failure screenshots
164+
uses: actions/upload-artifact@v1
165+
if: failure()
119166
with:
120-
path: ${{ matrix.cypress_cache_folder }}
121-
key: cypress-cache-v2-${{ runner.os }}-${{ hashFiles('**/package.json') }}
122-
env:
123-
CYPRESS_INSTALL_BINARY: ${{ steps.cypress_version.outputs.cypress_version }}
124-
- run: npx cypress cache list
125-
- run: npx cypress cache path
126-
127-
- name: Run AD cypress tests
128-
uses: cypress-io/github-action@v2
167+
name: cypress-screenshots-${{ matrix.os }}
168+
path: opensearch-dashboards-functional-test/cypress/screenshots
169+
170+
- name: Capture failure test video
171+
uses: actions/upload-artifact@v1
172+
if: failure()
129173
with:
130-
working-directory: opensearch-dashboards-functional-test
131-
command: yarn run cypress run --env SECURITY_ENABLED=false --spec cypress/integration/plugins/anomaly-detection-dashboards-plugin/**/*.js
132-
env:
133-
CYPRESS_CACHE_FOLDER: ${{ matrix.cypress_cache_folder }}
174+
name: cypress-videos-${{ matrix.os }}
175+
path: opensearch-dashboards-functional-test/cypress/videos

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
"description": "OpenSearch Anomaly Detection Dashboards Plugin",
55
"main": "index.js",
66
"config": {
7-
"plugin_version": "2.13.0.0",
8-
"plugin_name": "anomalyDetectionDashboards",
9-
"plugin_zip_name": "anomaly-detection-dashboards"
7+
"id": "anomalyDetectionDashboards",
8+
"zip_name": "anomaly-detection-dashboards"
109
},
1110
"scripts": {
1211
"osd": "node ../../scripts/osd",
1312
"opensearch": "node ../../scripts/opensearch",
1413
"lint": "node ../../scripts/eslint .",
1514
"plugin-helpers": "node ../../scripts/plugin_helpers",
1615
"test:jest": "../../node_modules/.bin/jest --config ./test/jest.config.js",
17-
"build": "yarn plugin-helpers build && echo Renaming artifact to $npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip && mv ./build/$npm_package_config_plugin_name*.zip ./build/$npm_package_config_plugin_zip_name-$npm_package_config_plugin_version.zip"
16+
"build": "yarn plugin-helpers build",
17+
"postbuild": "echo Renaming artifact to [$npm_package_config_zip_name-$npm_package_version.zip] && mv build/$npm_package_config_id*.zip build/$npm_package_config_zip_name-$npm_package_version.zip"
1818
},
1919
"lint-staged": {
2020
"*.{ts,tsx,js,jsx,json,css,md}": [

public/pages/DetectorResults/containers/AnomalyResults.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ export function AnomalyResults(props: AnomalyResultsProps) {
255255
endDate: adjustedCurrentTime.valueOf(),
256256
} as DateRange;
257257

258+
// build result search query params relative to data end time
258259
const params = buildParamsForGetAnomalyResultsWithDateRange(
259260
featureDataPointsRange.startDate,
260261
featureDataPointsRange.endDate

public/pages/utils/__tests__/anomalyResultUtils.test.ts

+57
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
getFeatureMissingDataAnnotations,
1414
getFeatureDataPointsForDetector,
1515
parsePureAnomalies,
16+
buildParamsForGetAnomalyResultsWithDateRange,
1617
} from '../anomalyResultUtils';
1718
import { getRandomDetector } from '../../../redux/reducers/__tests__/utils';
1819
import {
@@ -22,11 +23,16 @@ import {
2223
AnomalyData,
2324
} from '../../../models/interfaces';
2425
import { ANOMALY_RESULT_SUMMARY, PARSED_ANOMALIES } from './constants';
26+
import { MAX_ANOMALIES } from '../../../utils/constants';
27+
import { SORT_DIRECTION, AD_DOC_FIELDS } from '../../../../server/utils/constants';
2528

2629
describe('anomalyResultUtils', () => {
2730
let randomDetector_20_min: Detector;
2831
let randomDetector_20_sec: Detector;
2932
let feature_id = 'deny_max';
33+
const startTime = 1609459200000; // January 1, 2021
34+
const endTime = 1609545600000; // January 2, 2021
35+
3036
beforeAll(() => {
3137
randomDetector_20_min = {
3238
...getRandomDetector(true),
@@ -569,6 +575,57 @@ describe('anomalyResultUtils', () => {
569575
)
570576
).toEqual([]);
571577
});
578+
test('should correctly build parameters with default options', () => {
579+
const expected = {
580+
from: 0,
581+
size: MAX_ANOMALIES,
582+
sortDirection: SORT_DIRECTION.DESC,
583+
sortField: AD_DOC_FIELDS.DATA_END_TIME,
584+
startTime: startTime,
585+
endTime: endTime,
586+
fieldName: AD_DOC_FIELDS.DATA_END_TIME,
587+
anomalyThreshold: -1,
588+
entityList: undefined, // Default as an empty array stringified
589+
};
590+
591+
const result = buildParamsForGetAnomalyResultsWithDateRange(startTime, endTime);
592+
expect(result).toEqual(expected);
593+
});
594+
595+
test('should correctly handle `anomalyOnly` and non-empty `entityList`', () => {
596+
const entities = [{ id: '1', name: 'Entity1' }, { id: '2', name: 'Entity2' }];
597+
const expected = {
598+
from: 0,
599+
size: MAX_ANOMALIES,
600+
sortDirection: SORT_DIRECTION.DESC,
601+
sortField: AD_DOC_FIELDS.DATA_END_TIME,
602+
startTime: startTime,
603+
endTime: endTime,
604+
fieldName: AD_DOC_FIELDS.DATA_END_TIME,
605+
anomalyThreshold: 0, // because anomalyOnly is true
606+
entityList: JSON.stringify(entities),
607+
};
608+
609+
const result = buildParamsForGetAnomalyResultsWithDateRange(startTime, endTime, true, entities);
610+
expect(result).toEqual(expected);
611+
});
612+
613+
test('should handle undefined `entityList` as an empty array JSON string', () => {
614+
const expected = {
615+
from: 0,
616+
size: MAX_ANOMALIES,
617+
sortDirection: SORT_DIRECTION.DESC,
618+
sortField: AD_DOC_FIELDS.DATA_END_TIME,
619+
startTime: startTime,
620+
endTime: endTime,
621+
fieldName: AD_DOC_FIELDS.DATA_END_TIME,
622+
anomalyThreshold: -1, // default as anomalyOnly is false
623+
entityList: undefined, // Default for undefined entityList
624+
};
625+
626+
const result = buildParamsForGetAnomalyResultsWithDateRange(startTime, endTime, false, undefined);
627+
expect(result).toEqual(expected);
628+
});
572629
});
573630

574631
describe('parsePureAnomalies()', () => {

0 commit comments

Comments
 (0)