Skip to content

Commit e2e0db4

Browse files
jovancvetkovic3006amsiglan
authored andcommitted
Bugfix/interval field can be empty (opensearch-project#379)
* [FEATURE] Detector must have at least one alert set opensearch-project#288 Signed-off-by: Jovan Cvetkovic <[email protected]> * [BUG] Create detector | Interval field can be empty opensearch-project#378 Signed-off-by: Jovan Cvetkovic <[email protected]> * fix PR failed tests Signed-off-by: Jovan Cvetkovic <[email protected]> * fix PR failed tests Signed-off-by: Jovan Cvetkovic <[email protected]> * unit tests Signed-off-by: Jovan Cvetkovic <[email protected]> * unit tests Signed-off-by: Jovan Cvetkovic <[email protected]> * testing github-action v5 Signed-off-by: Jovan Cvetkovic <[email protected]> * testing github-action v5 Signed-off-by: Jovan Cvetkovic <[email protected]> * testing github-action v5 Signed-off-by: Jovan Cvetkovic <[email protected]> --------- Signed-off-by: Jovan Cvetkovic <[email protected]>
1 parent 2cc0202 commit e2e0db4

File tree

11 files changed

+69
-21
lines changed

11 files changed

+69
-21
lines changed

.github/workflows/cypress-workflow.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,12 @@ jobs:
111111
with:
112112
path: ${{ matrix.cypress_cache_folder }}
113113
key: cypress-cache-v2-${{ runner.os }}-${{ hashFiles('**/package.json') }}
114+
restore-keys: |
115+
cypress-cache-v2-${{ runner.os }}-${{ hashFiles('**/package.json') }}
114116
115117
# for now just chrome, use matrix to do all browsers later
116118
- name: Cypress tests
117-
uses: cypress-io/github-action@v2
119+
uses: cypress-io/github-action@v5
118120
with:
119121
working-directory: OpenSearch-Dashboards/plugins/security-analytics-dashboards-plugin
120122
command: yarn run cypress run

cypress.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
{
22
"viewportHeight": 900,
33
"viewportWidth": 1440,
4-
"defaultCommandTimeout": 20000,
4+
"defaultCommandTimeout": 30000,
5+
"requestTimeout": 300000,
6+
"responseTimeout": 300000,
57
"baseUrl": "http://localhost:5601",
68
"env": {
79
"opensearch_url": "localhost:9200",

cypress/integration/1_detectors.spec.js

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,29 @@ describe('Detectors', () => {
3838
before(() => {
3939
cy.cleanUpTests();
4040
// Create test index
41-
cy.createIndex(indexName, sample_index_settings);
42-
cy.request('POST', '_plugins/_security_analytics/rules/_search?prePackaged=true', {
43-
from: 0,
44-
size: 5000,
45-
query: {
46-
nested: {
47-
path: 'rule',
48-
query: { bool: { must: [{ match: { 'rule.category': 'windows' } }] } },
49-
},
50-
},
51-
});
41+
cy.createIndex(indexName, sample_index_settings).then(() =>
42+
cy
43+
.request('POST', '_plugins/_security_analytics/rules/_search?prePackaged=true', {
44+
from: 0,
45+
size: 5000,
46+
query: {
47+
nested: {
48+
path: 'rule',
49+
query: { bool: { must: [{ match: { 'rule.category': 'windows' } }] } },
50+
},
51+
},
52+
})
53+
.should('have.property', 'status', 200)
54+
);
5255

5356
cy.contains(detectorName).should('not.exist');
5457
});
5558

5659
beforeEach(() => {
60+
cy.intercept('/detectors/_search').as('detectorsSearch');
5761
// Visit Detectors page
5862
cy.visit(`${OPENSEARCH_DASHBOARDS_URL}/detectors`);
63+
cy.wait('@detectorsSearch').should('have.property', 'state', 'Complete');
5964

6065
// Check that correct page is showing
6166
cy.waitForPageLoad('detectors', {

cypress/integration/2_rules.spec.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,10 @@ const checkRulesFlyout = () => {
131131
describe('Rules', () => {
132132
before(() => cy.cleanUpTests());
133133
beforeEach(() => {
134+
cy.intercept('/rules/_search').as('rulesSearch');
134135
// Visit Rules page
135136
cy.visit(`${OPENSEARCH_DASHBOARDS_URL}/rules`);
137+
cy.wait('@rulesSearch').should('have.property', 'state', 'Complete');
136138

137139
// Check that correct page is showing
138140
cy.waitForPageLoad('rules', {
@@ -194,12 +196,12 @@ describe('Rules', () => {
194196
force: true,
195197
});
196198

199+
cy.wait('@getRules');
200+
197201
cy.waitForPageLoad('rules', {
198202
contains: 'Rules',
199203
});
200204

201-
cy.wait('@getRules');
202-
203205
checkRulesFlyout();
204206
});
205207

cypress/integration/3_alerts.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,10 @@ describe('Alerts', () => {
8484

8585
beforeEach(() => {
8686
// Visit Alerts table page
87+
cy.intercept('/detectors/_search').as('detectorsSearch');
88+
// Visit Detectors page
8789
cy.visit(`${OPENSEARCH_DASHBOARDS_URL}/alerts`);
90+
cy.wait('@detectorsSearch').should('have.property', 'state', 'Complete');
8891

8992
// Wait for page to load
9093
cy.waitForPageLoad('alerts', {

cypress/support/detectors.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,8 @@ Cypress.Commands.add('deleteAllDetectors', () => {
6868
method: 'DELETE',
6969
url: `${Cypress.env('opensearch')}/.opensearch-sap-detectors-config`,
7070
failOnStatusCode: false,
71+
}).as('deleteAllDetectors');
72+
cy.get('@deleteAllDetectors').should((response) => {
73+
expect(response.status).to.be.oneOf([200, 404]);
7174
});
7275
});

cypress/support/indexes.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
const { NODE_API } = require('./constants');
77

88
Cypress.Commands.add('createIndex', (index, settings = {}) => {
9-
cy.request('PUT', `${Cypress.env('opensearch')}/${index}`, settings);
9+
cy.request('PUT', `${Cypress.env('opensearch')}/${index}`, settings).should(
10+
'have.property',
11+
'status',
12+
200
13+
);
1014
});
1115

1216
Cypress.Commands.add('createIndexTemplate', (name, template) => {
@@ -43,5 +47,9 @@ Cypress.Commands.add('deleteAllIndices', () => {
4347
method: 'DELETE',
4448
url: `${Cypress.env('opensearch')}/index*,sample*,opensearch_dashboards*,test*,cypress*`,
4549
failOnStatusCode: false,
50+
}).as('deleteAllIndices');
51+
cy.get('@deleteAllIndices').should((response) => {
52+
// Both statuses are a pass, 200 means deleted successfully and 404 there was no index to delete
53+
expect(response.status).to.be.oneOf([200, 404]);
4654
});
4755
});

cypress/support/rules.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,14 @@ Cypress.Commands.add('deleteRule', (ruleName) => {
5151
});
5252

5353
Cypress.Commands.add('deleteAllCustomRules', () => {
54+
const url = `${Cypress.env('opensearch')}/.opensearch-sap-custom-rules-config`;
5455
cy.request({
5556
method: 'DELETE',
56-
url: `${Cypress.env('opensearch')}/.opensearch-sap-custom-rules-config`,
57+
url: url,
5758
failOnStatusCode: false,
5859
body: { query: { match_all: {} } },
60+
}).as('deleteAllCustomRules');
61+
cy.get('@deleteAllCustomRules').should((response) => {
62+
expect(response.status).to.be.oneOf([200, 404]);
5963
});
6064
});

cypress/support/typings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Cypress.Commands.add(
99
prevSubject: true,
1010
},
1111
(subject, text) => {
12-
return cy.get(subject).ospType(text).realPress('Enter');
12+
return cy.get(subject).clear().ospType(text).realPress('Enter');
1313
}
1414
);
1515

public/pages/CreateDetector/components/DefineDetector/components/DetectorSchedule/Interval.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,25 @@ export interface IntervalProps {
2020
onDetectorScheduleChange(schedule: PeriodSchedule): void;
2121
}
2222

23+
export interface IntervalState {
24+
isIntervalValid: boolean;
25+
}
26+
2327
const unitOptions: EuiSelectOption[] = [
2428
{ value: 'MINUTES', text: 'Minutes' },
2529
{ value: 'HOURS', text: 'Hours' },
2630
{ value: 'DAYS', text: 'Days' },
2731
];
2832

29-
export class Interval extends React.Component<IntervalProps> {
33+
export class Interval extends React.Component<IntervalProps, IntervalState> {
34+
state = {
35+
isIntervalValid: true,
36+
};
37+
3038
onTimeIntervalChange = (event: React.ChangeEvent<HTMLInputElement>) => {
39+
this.setState({
40+
isIntervalValid: !!event.target.value,
41+
});
3142
this.props.onDetectorScheduleChange({
3243
period: {
3344
...this.props.detector.schedule.period,
@@ -46,9 +57,14 @@ export class Interval extends React.Component<IntervalProps> {
4657
};
4758

4859
render() {
60+
const { isIntervalValid } = this.state;
4961
const { period } = this.props.detector.schedule;
5062
return (
51-
<EuiFormRow label={<FormFieldHeader headerTitle={'Run every'} />}>
63+
<EuiFormRow
64+
label={<FormFieldHeader headerTitle={'Run every'} />}
65+
isInvalid={!isIntervalValid}
66+
error={'Enter schedule interval.'}
67+
>
5268
<EuiFlexGroup>
5369
<EuiFlexItem>
5470
<EuiFieldNumber
@@ -57,6 +73,8 @@ export class Interval extends React.Component<IntervalProps> {
5773
value={period.interval}
5874
onChange={this.onTimeIntervalChange}
5975
data-test-subj={'detector-schedule-number-select'}
76+
required={true}
77+
isInvalid={!isIntervalValid}
6078
/>
6179
</EuiFlexItem>
6280
<EuiFlexItem>

0 commit comments

Comments
 (0)