diff --git a/TestResultSummaryService/routes/getTestBySearch.js b/TestResultSummaryService/routes/getTestBySearch.js index f8556cb9..d8287265 100644 --- a/TestResultSummaryService/routes/getTestBySearch.js +++ b/TestResultSummaryService/routes/getTestBySearch.js @@ -103,6 +103,7 @@ searchOutputId = async (build) => { testResult: test.testResult, duration: test.duration, machine: build.machine, + timestamp: build.timestamp, }; }); } diff --git a/TestResultSummaryService/routes/getTestByTestName.js b/TestResultSummaryService/routes/getTestByTestName.js new file mode 100644 index 00000000..482c9450 --- /dev/null +++ b/TestResultSummaryService/routes/getTestByTestName.js @@ -0,0 +1,48 @@ +const { TestResultsDB, ObjectID } = require('../Database'); +module.exports = async (req, res) => { + const { testName, buildNames, beforeTimestamp } = req.query; + const db = new TestResultsDB(); + let query = {}; + if (buildNames) { + const buildNameArray = buildNames.split(','); + const rootBuildIds = []; + await Promise.all( + buildNameArray.map(async (buildName) => { + const buildData = await db.getData({ buildName }).toArray(); + buildData.forEach((build) => { + rootBuildIds.push(new ObjectID(build._id)); + }); + }) + ); + query.rootBuildId = { $in: rootBuildIds }; + } + if (beforeTimestamp) { + query.timestamp = { $lt: parseInt(beforeTimestamp) }; + } + const history = await db.aggregate([ + { + $match: query, + }, + { $unwind: '$tests' }, + { + $match: { + 'tests.testName': testName, + }, + }, + { + $project: { + parentId: 1, + buildName: 1, + buildNum: 1, + machine: 1, + buildUrl: 1, + tests: 1, + timestamp: 1, + javaVersion: 1, + }, + }, + { $sort: { timestamp: -1 } }, + ]); + + res.send(history); +}; diff --git a/TestResultSummaryService/routes/getTestNames.js b/TestResultSummaryService/routes/getTestNames.js new file mode 100644 index 00000000..a957cdba --- /dev/null +++ b/TestResultSummaryService/routes/getTestNames.js @@ -0,0 +1,13 @@ +const { TestResultsDB, ObjectID } = require('../Database'); +module.exports = async (req, res) => { + const testResultsDB = new TestResultsDB(); + const data = await testResultsDB.aggregate([ + { $group: { _id: '$tests.testName' } }, + { $unwind: '$_id' }, + { $group: { _id: '$_id' } }, + { $sort: { _id: 1 } }, + ]); + testNames = data.map(({ _id }) => _id); + + res.send(testNames); +}; diff --git a/TestResultSummaryService/routes/index.js b/TestResultSummaryService/routes/index.js index 9c01bbbe..22d541c6 100644 --- a/TestResultSummaryService/routes/index.js +++ b/TestResultSummaryService/routes/index.js @@ -42,6 +42,8 @@ app.get('/getTestBuildsByMachine', wrap(require('./getTestBuildsByMachine'))); app.get('/getTestById', wrap(require('./getTestById'))); app.get('/getTestBySearch', wrap(require('./getTestBySearch'))); app.get('/getTestByVersionInfo', wrap(require('./getTestByVersionInfo'))); +app.get('/getTestNames', wrap(require('./getTestNames'))); +app.get('/getTestByTestName', wrap(require('./getTestByTestName'))); app.get('/getTestPerPlatform', wrap(require('./getTestPerPlatform'))); app.get('/getTopLevelBuildNames', wrap(require('./getTopLevelBuildNames'))); app.get('/getTotals', wrap(require('./getTotals'))); diff --git a/test-result-summary-client/src/AdvancedSearch/AdvancedSearch.jsx b/test-result-summary-client/src/AdvancedSearch/AdvancedSearch.jsx new file mode 100644 index 00000000..3099c329 --- /dev/null +++ b/test-result-summary-client/src/AdvancedSearch/AdvancedSearch.jsx @@ -0,0 +1,85 @@ +import React, { Component } from 'react'; +import { Space, Button } from 'antd'; +import { fetchData } from '../utils/Utils'; +import InputAutoComplete from './InputAutoComplete'; +import InputSelect from './InputSelect'; +import SearchTestResult from '../Search/SearchTestResult'; + +export default class AdvancedSearch extends Component { + constructor(props) { + super(props); + this.state = { + testName: '', + testNameOptions: [], + buildNameOptions: [], + }; + } + async componentDidMount() { + await this.updateData(); + } + + async updateData() { + const data = await fetchData(`/api/getTopLevelBuildNames?type=Test`); + let buildNames = []; + if (data) { + buildNames = data.map((value) => { + return value._id.buildName; + }); + } + const testNames = await fetchData(`/api/getTestNames`); + + this.setState({ + buildNameOptions: buildNames.sort(), + testNameOptions: testNames, + }); + } + handleSubmit = async () => { + const { testName, buildNames } = this.state; + const buildNamesStr = buildNames.join(','); + const data = await fetchData( + `/api/getTestByTestName?testName=${testName}&buildNames=${buildNamesStr}` + ); + + const result = data.map((element) => ({ + ...element, + ...element.tests, + })); + + this.setState({ result }); + }; + onBuildNameChange = (value) => { + this.setState({ buildNames: value }); + }; + + onTestNameChange = (value) => { + this.setState({ testName: value }); + }; + onSelect = (value) => { + this.setState({ value }); + }; + render() { + const { buildNameOptions, testNameOptions, testName, result } = + this.state; + return ( + + + + +
+ {result ? : ''} +
+ ); + } +} diff --git a/test-result-summary-client/src/AdvancedSearch/InputAutoComplete.jsx b/test-result-summary-client/src/AdvancedSearch/InputAutoComplete.jsx new file mode 100644 index 00000000..0990e6e2 --- /dev/null +++ b/test-result-summary-client/src/AdvancedSearch/InputAutoComplete.jsx @@ -0,0 +1,24 @@ +import React, { Component } from 'react'; +import { AutoComplete } from 'antd'; + +export default class InputAutoComplete extends Component { + render() { + return ( + ({ value }))} + style={{ + width: 600, + }} + onSelect={this.props.onSelect} + onChange={this.props.onChange} + placeholder={this.props.message} + filterOption={(inputValue, option) => + option.value + .toUpperCase() + .includes(inputValue.toUpperCase()) + } + /> + ); + } +} diff --git a/test-result-summary-client/src/AdvancedSearch/InputSelect.jsx b/test-result-summary-client/src/AdvancedSearch/InputSelect.jsx new file mode 100644 index 00000000..88002094 --- /dev/null +++ b/test-result-summary-client/src/AdvancedSearch/InputSelect.jsx @@ -0,0 +1,20 @@ +import React, { Component } from 'react'; +import { Select } from 'antd'; + +export default class InoutSelect extends Component { + render() { + const options = this.props.options.map((value) => ({ value })); + return ( +