added svcapi ui and camunda code
[it/otf.git] / otf-frontend / server / src / agenda / controllers / test-execution-controller.js
diff --git a/otf-frontend/server/src/agenda/controllers/test-execution-controller.js b/otf-frontend/server/src/agenda/controllers/test-execution-controller.js
new file mode 100644 (file)
index 0000000..56f07a2
--- /dev/null
@@ -0,0 +1,220 @@
+/*  Copyright (c) 2019 AT&T Intellectual Property.                             #\r
+#                                                                              #\r
+#   Licensed under the Apache License, Version 2.0 (the "License");            #\r
+#   you may not use this file except in compliance with the License.           #\r
+#   You may obtain a copy of the License at                                    #\r
+#                                                                              #\r
+#       http://www.apache.org/licenses/LICENSE-2.0                             #\r
+#                                                                              #\r
+#   Unless required by applicable law or agreed to in writing, software        #\r
+#   distributed under the License is distributed on an "AS IS" BASIS,          #\r
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
+#   See the License for the specific language governing permissions and        #\r
+#   limitations under the License.                                             #\r
+##############################################################################*/\r
+\r
+\r
+const logger = require('../../lib/logger');\r
+const agenda = require('../agenda').agenda;\r
+const emitter = require('../result-emitter').emitter;\r
+const utils = require('../../lib/otf-util');\r
+const nodeUtil = require('util');\r
+\r
+const ObjectId = require('mongoose').Types.ObjectId;\r
+\r
+const TestSchedule = require('../models/test-schedule');\r
+\r
+const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\r
+\r
+module.exports = function (app) {\r
+       let scheduleTestResponse = { status: '', message: '' };\r
+       let cancelTestResponse = { status: '', message: '' };\r
+\r
+       // Main endpoint for scheduling\r
+       app.use('/' + app.get('base-path') + 'schedule-test', (req, res, next) => {\r
+               const authorizationHeader = req.headers.authorization;\r
+\r
+               const testInstanceId = req.body.testInstanceId;\r
+               const testInstanceStartDate = req.body.testInstanceStartDate;\r
+               const testInstanceExecFreqInSeconds = req.body.testInstanceExecFreqInSeconds;\r
+               const testInstanceEndDate = req.body.testInstanceEndDate;\r
+               const async = req.body.async;\r
+               const asyncTopic = req.body.asyncTopic;\r
+               const asyncMode = req.body.asyncMode;\r
+               const executorId = req.body.executorId;\r
+\r
+               let testSchedule = null;\r
+\r
+               try {\r
+                       testSchedule = new TestSchedule(testInstanceId, testInstanceStartDate, testInstanceExecFreqInSeconds,\r
+                               testInstanceEndDate, async, asyncTopic, asyncMode, executorId);\r
+               } catch (error) {\r
+                       scheduleTestResponse.status = 400;\r
+                       scheduleTestResponse.message = error.toString();\r
+                       next();\r
+\r
+                       return;\r
+               }\r
+\r
+               // The presence of this parameter indicates that we will be executing either job definition 2/3.\r
+               if (testSchedule.testInstanceStartDate) {\r
+                       if (testSchedule.testInstanceExecFreqInSeconds) {\r
+                               const job = agenda.create(\r
+                                       'executeTestAsync',\r
+                                       { testSchedule, authorizationHeader });\r
+                               job.schedule(testSchedule.testInstanceStartDate).repeatEvery(testSchedule.testInstanceExecFreqInSeconds + ' seconds', {\r
+                                       timezone: timeZone\r
+                               });\r
+                               job.save().then(function onJobCreated (result) {\r
+                                               logger.debug(JSON.stringify(result));\r
+                                               scheduleTestResponse.status = 200;\r
+                                               scheduleTestResponse.message = 'Successfully scheduled job.';\r
+                                               next();\r
+                                       })\r
+                                       .catch(function onError (error) {\r
+                                               logger.error(error);\r
+                                               scheduleTestResponse.status = 500;\r
+                                               scheduleTestResponse.message = 'Unable to schedule job.';\r
+                                               next();\r
+                                       });\r
+                       } else if (!testSchedule.testInstanceExecFreqInSeconds && !testSchedule.testInstanceEndDate) {\r
+                               agenda.schedule(\r
+                                       testSchedule._testInstanceStartDate,\r
+                                       'executeTestAsync',\r
+                                       { testSchedule, authorizationHeader })\r
+                                       .then(function onJobCreated (result) {\r
+                                               scheduleTestResponse.status = 200;\r
+                                               scheduleTestResponse.message = 'Successfully scheduled job.';\r
+                                               next();\r
+                                       })\r
+                                       .catch(function onError (error) {\r
+                                               logger.error('error: ' + error);\r
+                                               scheduleTestResponse.status = 500;\r
+                                               scheduleTestResponse.message = 'Unable to schedule job.';\r
+                                               next();\r
+                                       });\r
+                               return;\r
+                       } else if (testSchedule.testInstanceEndDate && !testSchedule.testInstanceExecFreqInSeconds) {\r
+                               scheduleTestResponse.status = 400;\r
+                               scheduleTestResponse.message = 'Must specify \'testInstanceExecFreqInSeconds\' to use \'testInstanceEndDate\'';\r
+\r
+                               next();\r
+                       }\r
+               }\r
+\r
+               if (!testSchedule.testInstanceStartDate &&\r
+                       !testSchedule.testInstanceExecFreqInSeconds &&\r
+                       !testSchedule.testInstanceExecFreqInSeconds) {\r
+                       agenda.now(\r
+                               'executeTestSync',\r
+                               { testSchedule, authorizationHeader })\r
+                               .then(function onJobCreated (result) {\r
+                                       emitter.once(result.attrs._id + '_error', (res) => {\r
+                                               logger.info(res);\r
+                                               scheduleTestResponse.message = res.message;\r
+                                               scheduleTestResponse.status = res.statusCode;\r
+                                               next();\r
+                                       });\r
+\r
+                                       emitter.once(result.attrs._id + '_ok', (res) => {\r
+                                               logger.info(res);\r
+                                               scheduleTestResponse.message = res;\r
+                                               scheduleTestResponse.status = 200;\r
+                                               next();\r
+                                       });\r
+                               })\r
+                               .catch(function onError (err) {\r
+                                       logger.error(err);\r
+\r
+                                       if (!Object.keys(scheduleTestResponse).includes('message')) {\r
+                                               scheduleTestResponse.message = 'Unknown error.';\r
+                                       }\r
+\r
+                                       if (!Object.keys(scheduleTestResponse).includes('status')) {\r
+                                               scheduleTestResponse.status = 500;\r
+                                       }\r
+                               });\r
+               }\r
+       }, (req, res) => {\r
+               res.type('json');\r
+               res.status(scheduleTestResponse.status).send(scheduleTestResponse);\r
+               logger.debug('Sent response with status %d and body %s', scheduleTestResponse.status, scheduleTestResponse.message);\r
+       });\r
+\r
+       // Cancel\r
+       app.use('/' + app.get('base-path') + 'cancel-test', (req, res, next) => {\r
+               // validate the request parameters\r
+               if (req.body === null) {\r
+                       cancelTestResponse.status = 400;\r
+                       cancelTestResponse.message = 'Request data is invalid.';\r
+\r
+                       next();\r
+                       return;\r
+               }\r
+\r
+               let requestBody = req.body;\r
+\r
+               if (!requestBody.jobId) {\r
+                       cancelTestResponse.status = 400;\r
+                       cancelTestResponse.message = 'jobId is required.';\r
+\r
+                       next();\r
+                       return;\r
+               }\r
+\r
+               if (!utils.isValidObjectId(requestBody.jobId)) {\r
+                       cancelTestResponse.status = 400;\r
+                       cancelTestResponse.message = 'jobId must be a valid ObjectId.';\r
+\r
+                       next();\r
+                       return;\r
+               }\r
+\r
+               if (!requestBody.executorId) {\r
+                       cancelTestResponse.status = 400;\r
+                       cancelTestResponse.message = 'executorId is required.';\r
+\r
+                       next();\r
+                       return;\r
+               }\r
+\r
+               if (!utils.isValidObjectId(requestBody.executorId)) {\r
+                       cancelTestResponse.status = 400;\r
+                       cancelTestResponse.message = 'executorId must be a valid ObjectId.';\r
+\r
+                       next();\r
+                       return;\r
+               }\r
+\r
+               const jobId = new ObjectId(requestBody.jobId);\r
+               const executorId = new ObjectId(requestBody.executorId);\r
+\r
+               agenda.cancel({ _id: jobId, 'data.testSchedule._executorId': executorId })\r
+                       .then(function onJobRemoved (numJobsRemoved) {\r
+                               logger.info('Number of jobs removed: %s', numJobsRemoved);\r
+\r
+                               cancelTestResponse.status = 200;\r
+                               cancelTestResponse.message = nodeUtil.format('Successfully removed job with Id %s', jobId);\r
+\r
+                               if (numJobsRemoved === 0) {\r
+                                       cancelTestResponse.status = 500;\r
+                                       cancelTestResponse.message =\r
+                                               nodeUtil.format('Unable to find job with Id %s, belonging to user with Id %s.', jobId, executorId);\r
+                               }\r
+\r
+                               next();\r
+                       })\r
+                       .catch(function onError (error) {\r
+                               logger.error(error.toString());\r
+\r
+                               cancelTestResponse.status = 500;\r
+                               cancelTestResponse.message = 'Unable to cancel the job due to an unexpected error.';\r
+\r
+                               next();\r
+                       });\r
+       }, (req, res) => {\r
+               res.type('json');\r
+               res.status(cancelTestResponse.status).send(cancelTestResponse);\r
+               logger.debug('Sent response with status %d and body %s', cancelTestResponse.status, cancelTestResponse.message);\r
+       });\r
+};\r