added svcapi ui and camunda code
[it/otf.git] / otf-frontend / server / src / agenda / controllers / test-execution-controller.js
1 /*  Copyright (c) 2019 AT&T Intellectual Property.                             #\r
2 #                                                                              #\r
3 #   Licensed under the Apache License, Version 2.0 (the "License");            #\r
4 #   you may not use this file except in compliance with the License.           #\r
5 #   You may obtain a copy of the License at                                    #\r
6 #                                                                              #\r
7 #       http://www.apache.org/licenses/LICENSE-2.0                             #\r
8 #                                                                              #\r
9 #   Unless required by applicable law or agreed to in writing, software        #\r
10 #   distributed under the License is distributed on an "AS IS" BASIS,          #\r
11 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #\r
12 #   See the License for the specific language governing permissions and        #\r
13 #   limitations under the License.                                             #\r
14 ##############################################################################*/\r
15 \r
16 \r
17 const logger = require('../../lib/logger');\r
18 const agenda = require('../agenda').agenda;\r
19 const emitter = require('../result-emitter').emitter;\r
20 const utils = require('../../lib/otf-util');\r
21 const nodeUtil = require('util');\r
22 \r
23 const ObjectId = require('mongoose').Types.ObjectId;\r
24 \r
25 const TestSchedule = require('../models/test-schedule');\r
26 \r
27 const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\r
28 \r
29 module.exports = function (app) {\r
30         let scheduleTestResponse = { status: '', message: '' };\r
31         let cancelTestResponse = { status: '', message: '' };\r
32 \r
33         // Main endpoint for scheduling\r
34         app.use('/' + app.get('base-path') + 'schedule-test', (req, res, next) => {\r
35                 const authorizationHeader = req.headers.authorization;\r
36 \r
37                 const testInstanceId = req.body.testInstanceId;\r
38                 const testInstanceStartDate = req.body.testInstanceStartDate;\r
39                 const testInstanceExecFreqInSeconds = req.body.testInstanceExecFreqInSeconds;\r
40                 const testInstanceEndDate = req.body.testInstanceEndDate;\r
41                 const async = req.body.async;\r
42                 const asyncTopic = req.body.asyncTopic;\r
43                 const asyncMode = req.body.asyncMode;\r
44                 const executorId = req.body.executorId;\r
45 \r
46                 let testSchedule = null;\r
47 \r
48                 try {\r
49                         testSchedule = new TestSchedule(testInstanceId, testInstanceStartDate, testInstanceExecFreqInSeconds,\r
50                                 testInstanceEndDate, async, asyncTopic, asyncMode, executorId);\r
51                 } catch (error) {\r
52                         scheduleTestResponse.status = 400;\r
53                         scheduleTestResponse.message = error.toString();\r
54                         next();\r
55 \r
56                         return;\r
57                 }\r
58 \r
59                 // The presence of this parameter indicates that we will be executing either job definition 2/3.\r
60                 if (testSchedule.testInstanceStartDate) {\r
61                         if (testSchedule.testInstanceExecFreqInSeconds) {\r
62                                 const job = agenda.create(\r
63                                         'executeTestAsync',\r
64                                         { testSchedule, authorizationHeader });\r
65                                 job.schedule(testSchedule.testInstanceStartDate).repeatEvery(testSchedule.testInstanceExecFreqInSeconds + ' seconds', {\r
66                                         timezone: timeZone\r
67                                 });\r
68                                 job.save().then(function onJobCreated (result) {\r
69                                                 logger.debug(JSON.stringify(result));\r
70                                                 scheduleTestResponse.status = 200;\r
71                                                 scheduleTestResponse.message = 'Successfully scheduled job.';\r
72                                                 next();\r
73                                         })\r
74                                         .catch(function onError (error) {\r
75                                                 logger.error(error);\r
76                                                 scheduleTestResponse.status = 500;\r
77                                                 scheduleTestResponse.message = 'Unable to schedule job.';\r
78                                                 next();\r
79                                         });\r
80                         } else if (!testSchedule.testInstanceExecFreqInSeconds && !testSchedule.testInstanceEndDate) {\r
81                                 agenda.schedule(\r
82                                         testSchedule._testInstanceStartDate,\r
83                                         'executeTestAsync',\r
84                                         { testSchedule, authorizationHeader })\r
85                                         .then(function onJobCreated (result) {\r
86                                                 scheduleTestResponse.status = 200;\r
87                                                 scheduleTestResponse.message = 'Successfully scheduled job.';\r
88                                                 next();\r
89                                         })\r
90                                         .catch(function onError (error) {\r
91                                                 logger.error('error: ' + error);\r
92                                                 scheduleTestResponse.status = 500;\r
93                                                 scheduleTestResponse.message = 'Unable to schedule job.';\r
94                                                 next();\r
95                                         });\r
96                                 return;\r
97                         } else if (testSchedule.testInstanceEndDate && !testSchedule.testInstanceExecFreqInSeconds) {\r
98                                 scheduleTestResponse.status = 400;\r
99                                 scheduleTestResponse.message = 'Must specify \'testInstanceExecFreqInSeconds\' to use \'testInstanceEndDate\'';\r
100 \r
101                                 next();\r
102                         }\r
103                 }\r
104 \r
105                 if (!testSchedule.testInstanceStartDate &&\r
106                         !testSchedule.testInstanceExecFreqInSeconds &&\r
107                         !testSchedule.testInstanceExecFreqInSeconds) {\r
108                         agenda.now(\r
109                                 'executeTestSync',\r
110                                 { testSchedule, authorizationHeader })\r
111                                 .then(function onJobCreated (result) {\r
112                                         emitter.once(result.attrs._id + '_error', (res) => {\r
113                                                 logger.info(res);\r
114                                                 scheduleTestResponse.message = res.message;\r
115                                                 scheduleTestResponse.status = res.statusCode;\r
116                                                 next();\r
117                                         });\r
118 \r
119                                         emitter.once(result.attrs._id + '_ok', (res) => {\r
120                                                 logger.info(res);\r
121                                                 scheduleTestResponse.message = res;\r
122                                                 scheduleTestResponse.status = 200;\r
123                                                 next();\r
124                                         });\r
125                                 })\r
126                                 .catch(function onError (err) {\r
127                                         logger.error(err);\r
128 \r
129                                         if (!Object.keys(scheduleTestResponse).includes('message')) {\r
130                                                 scheduleTestResponse.message = 'Unknown error.';\r
131                                         }\r
132 \r
133                                         if (!Object.keys(scheduleTestResponse).includes('status')) {\r
134                                                 scheduleTestResponse.status = 500;\r
135                                         }\r
136                                 });\r
137                 }\r
138         }, (req, res) => {\r
139                 res.type('json');\r
140                 res.status(scheduleTestResponse.status).send(scheduleTestResponse);\r
141                 logger.debug('Sent response with status %d and body %s', scheduleTestResponse.status, scheduleTestResponse.message);\r
142         });\r
143 \r
144         // Cancel\r
145         app.use('/' + app.get('base-path') + 'cancel-test', (req, res, next) => {\r
146                 // validate the request parameters\r
147                 if (req.body === null) {\r
148                         cancelTestResponse.status = 400;\r
149                         cancelTestResponse.message = 'Request data is invalid.';\r
150 \r
151                         next();\r
152                         return;\r
153                 }\r
154 \r
155                 let requestBody = req.body;\r
156 \r
157                 if (!requestBody.jobId) {\r
158                         cancelTestResponse.status = 400;\r
159                         cancelTestResponse.message = 'jobId is required.';\r
160 \r
161                         next();\r
162                         return;\r
163                 }\r
164 \r
165                 if (!utils.isValidObjectId(requestBody.jobId)) {\r
166                         cancelTestResponse.status = 400;\r
167                         cancelTestResponse.message = 'jobId must be a valid ObjectId.';\r
168 \r
169                         next();\r
170                         return;\r
171                 }\r
172 \r
173                 if (!requestBody.executorId) {\r
174                         cancelTestResponse.status = 400;\r
175                         cancelTestResponse.message = 'executorId is required.';\r
176 \r
177                         next();\r
178                         return;\r
179                 }\r
180 \r
181                 if (!utils.isValidObjectId(requestBody.executorId)) {\r
182                         cancelTestResponse.status = 400;\r
183                         cancelTestResponse.message = 'executorId must be a valid ObjectId.';\r
184 \r
185                         next();\r
186                         return;\r
187                 }\r
188 \r
189                 const jobId = new ObjectId(requestBody.jobId);\r
190                 const executorId = new ObjectId(requestBody.executorId);\r
191 \r
192                 agenda.cancel({ _id: jobId, 'data.testSchedule._executorId': executorId })\r
193                         .then(function onJobRemoved (numJobsRemoved) {\r
194                                 logger.info('Number of jobs removed: %s', numJobsRemoved);\r
195 \r
196                                 cancelTestResponse.status = 200;\r
197                                 cancelTestResponse.message = nodeUtil.format('Successfully removed job with Id %s', jobId);\r
198 \r
199                                 if (numJobsRemoved === 0) {\r
200                                         cancelTestResponse.status = 500;\r
201                                         cancelTestResponse.message =\r
202                                                 nodeUtil.format('Unable to find job with Id %s, belonging to user with Id %s.', jobId, executorId);\r
203                                 }\r
204 \r
205                                 next();\r
206                         })\r
207                         .catch(function onError (error) {\r
208                                 logger.error(error.toString());\r
209 \r
210                                 cancelTestResponse.status = 500;\r
211                                 cancelTestResponse.message = 'Unable to cancel the job due to an unexpected error.';\r
212 \r
213                                 next();\r
214                         });\r
215         }, (req, res) => {\r
216                 res.type('json');\r
217                 res.status(cancelTestResponse.status).send(cancelTestResponse);\r
218                 logger.debug('Sent response with status %d and body %s', cancelTestResponse.status, cancelTestResponse.message);\r
219         });\r
220 };\r