fix testsuite name bugs and improve some ui details
[bottlenecks.git] / test-scheduler / server / src / rest / router.py
1 ##############################################################################
2 # Copyright (c) 2018 HUAWEI TECHNOLOGIES CO.,LTD and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10 from flask import Flask
11 from flask import jsonify
12 from flask import request
13 from flask_cors import CORS
14 import os
15 import json
16 import time
17 import pyaml
18 import yaml
19 import traceback
20
21 import src.test_parser as test_parser
22
23 BASE_DIR = unicode(os.path.abspath(os.path.dirname(__file__)), 'utf-8')
24 TESTSUITE_DIR = os.path.join(BASE_DIR, "..", "..", "test", "test_case")
25 SERVICE_DIR = os.path.join(BASE_DIR, "..", "env", "service")
26 CONTEXT_FILE_DIR = os.path.join(BASE_DIR, "..", "env", "context",
27                                 "context.yaml")
28 CONFIG_DIR = os.path.join(BASE_DIR, "..", "env", "config")
29 app = Flask(__name__)
30 CORS(app)
31
32
33 ###############
34 # 1. EXECUTE API
35 ###########################################################################
36 @app.route("/")
37 def hello():
38     return "Hello, World! This is a greet from parser." + SERVICE_DIR
39
40
41 @app.route("/execute/testcase", methods=['POST'])
42 def runTestcase():
43     suiteName = request.values.get('suiteName')
44     caseName = request.values.get('caseName')
45     try:
46         casePath = os.path.join(TESTSUITE_DIR, suiteName, caseName)
47         if os.path.exists(casePath):
48             workflowId = test_parser.parse(casePath)
49             if workflowId is None or workflowId == '':
50                 return jsonify({"code": 500, "error": "Server Error."})
51             return jsonify({"code": 200, "result": {"workflowId": workflowId}})
52         else:
53             return jsonify({"code": 300, "error": "no such test case:  %s" %
54                            (os.path.join(suiteName, caseName))})
55     except BaseException, e:
56         return returnServerError(e)
57
58
59 @app.route("/story-content")
60 def getStoryContent():
61     try:
62         story_name = request.args['story']
63         service_name = request.args['service']
64         storyFileDir = os.path.join("/tmp", "generate_workflow.json")
65         with open(storyFileDir, "r") as f:
66             storyContent = f.read()
67     except BaseException, e:
68         return returnServerError(e)
69
70     result = {"code": 200, "result":
71               {"service": service_name, "story": story_name,
72                "content": storyContent}}
73     return jsonify(result)
74
75
76 ###############
77 # 2. TESTCASE CRUD
78 ###########################################################################
79 @app.route("/testsuite/list")
80 def getAllSuite():
81     res = []
82     id = 1
83     try:
84         for fileName in os.listdir(TESTSUITE_DIR):
85             suiteInfo = {}
86             suiteInfo["id"] = id
87             suiteInfo["testsuite"] = fileName
88             res.append(suiteInfo)
89             id = id + 1
90     except BaseException, e:
91         print e
92         app.logger.error(traceback.format_exc())
93         return jsonify({"code": 500, "error": "Server error"})
94
95     return jsonify({"code": 200, "result": res})
96
97
98 @app.route("/testsuite/content")
99 def getSuiteContent():
100     res = []
101     id = 1
102     try:
103         suiteName = request.values.get("suiteName")
104         exSuitePath = os.path.join(TESTSUITE_DIR, suiteName)
105         if os.path.exists(exSuitePath):
106             for fileName in os.listdir(exSuitePath):
107                 tcInfo = {}
108                 tcInfo["id"] = id
109                 tcInfo["testcase"] = fileName
110                 res.append(tcInfo)
111                 id = id + 1
112         else:
113             return jsonify({"code": 300, "error": "no such test suite!"})
114     except BaseException, e:
115         print e
116         app.logger.error(traceback.format_exc())
117         return jsonify({"code": 500, "error": "Server error"})
118
119     return jsonify({"code": 200, "result": res})
120
121
122 @app.route("/testcase/content")
123 def getTCContent():
124     res = ""
125     editorRes = ""
126     try:
127         suiteName = request.values.get("suiteName")
128         caseName = request.values.get("caseName")
129         casePath = os.path.join(suiteName, caseName)
130         casePath = os.path.join(TESTSUITE_DIR, casePath)
131         if os.path.exists(casePath):
132             with open(casePath, "r") as f:
133                 fileContent = f.read()
134             res = fileContent
135             editorRes = test_parser.getWebTestcase(yaml.load(res))
136         else:
137             return jsonify({"code": 300, "error": "no such file!"})
138     except BaseException, e:
139         print e
140         app.logger.error(traceback.format_exc())
141         return jsonify({"code": 500, "error": "Server error"})
142
143     return jsonify({"code": 200, "result":
144                     {"content": res, "editorContent": editorRes}})
145
146
147 @app.route("/testsuite/new", methods=['POST'])
148 def addNewSuite():
149     try:
150         suiteName = request.values.get("suiteName")
151         for fileName in os.listdir(TESTSUITE_DIR):
152             if fileName == suiteName:
153                 return jsonify({"code": 300,
154                                 "error": "testsuite already exists!"})
155         testSuitePath = os.path.join(TESTSUITE_DIR, suiteName)
156         os.mkdir(testSuitePath)
157     except BaseException, e:
158         return returnServerError(e)
159
160     return jsonify({"code": 200, "result": "ok"})
161
162
163 @app.route("/testsuite/delete", methods=['POST'])
164 def deleteSuite():
165     try:
166         suiteName = request.values.get("suiteName")
167         for fileName in os.listdir(TESTSUITE_DIR):
168             if fileName == suiteName:
169                 testSuitePath = os.path.join(TESTSUITE_DIR, fileName)
170                 del_file(testSuitePath)
171                 os.rmdir(testSuitePath)
172                 return jsonify({"code": 200, "result": "ok"})
173     except BaseException, e:
174         return returnServerError(e)
175
176     return jsonify({"code": 300, "error": "no such testsuite!"})
177
178
179 def del_file(path):
180     for i in os.listdir(path):
181         path_file = os.path.join(path, i)
182         if os.path.isfile(path_file):
183             os.remove(path_file)
184         else:
185             del_file(path_file)
186
187
188 @app.route("/testcase/new", methods=['POST'])
189 def createTestcase():
190     try:
191         suiteName = request.values.get("suiteName")
192         caseName = request.values.get("caseName")
193         exSuitePath = os.path.join(TESTSUITE_DIR, suiteName)
194         if os.path.exists(exSuitePath):
195             for fileName in os.listdir(exSuitePath):
196                 if fileName == caseName:
197                     return jsonify({"code": 301,
198                                     "error": "testcase already exists!"})
199             casePath = os.path.join(exSuitePath, caseName)
200             with open(casePath, "w") as f:
201                 license_header = getLicense()
202                 f.write(license_header)
203         else:
204             return jsonify({"code": 300, "error": "no such test suite!"})
205     except BaseException, e:
206         return returnServerError(e)
207
208     return jsonify({"code": 200, "result": "ok"})
209
210
211 @app.route("/testcase/delete", methods=['POST'])
212 def deleteTestcase():
213     try:
214         suiteName = request.values.get("suiteName")
215         caseName = request.values.get("caseName")
216         exSuitePath = os.path.join(TESTSUITE_DIR, suiteName)
217         if os.path.exists(exSuitePath):
218             for fileName in os.listdir(exSuitePath):
219                 if fileName == caseName:
220                     casePath = os.path.join(exSuitePath, caseName)
221                     os.remove(casePath)
222                     return jsonify({"code": 200, "result": "ok"})
223             return jsonify({"code": 301, "error": "no such test case!"})
224         else:
225             return jsonify({"code": 300, "error": "no such test suite!"})
226     except BaseException, e:
227         return returnServerError(e)
228
229
230 @app.route("/testcase/save", methods=["POST"])
231 def saveTCContent():
232     try:
233         suiteName = request.values.get("suiteName")
234         caseName = request.values.get("caseName")
235         stepList = json.loads(request.values.get("stepList"))
236         subflowList = json.loads(request.values.get("subflowList"))
237         mainOrdersList = json.loads(request.values.get("mainOrdersList"))
238         jsonObj = {"stepList": stepList, "subflowList": subflowList,
239                    "mainOrdersList": mainOrdersList}
240         parseData = test_parser.parseWebTestcase(jsonObj)
241
242         casePath = os.path.join(suiteName, caseName)
243         casePath = os.path.join(TESTSUITE_DIR, casePath)
244         if os.path.exists(casePath):
245             with open(casePath, "w") as f:
246                 license_header = getLicense()
247                 f.write(license_header)
248                 pyaml.dump(parseData, f, safe=True)
249         else:
250             return jsonify({"code": 300, "error": "no such file!"})
251     except BaseException, e:
252         return returnServerError(e)
253
254     return jsonify({"code": 200, "result": "save success"})
255
256
257 ###############
258 # 3.1 API FOR SERVICE
259 ############################################################
260 @app.route("/service/list")
261 def getAllServices():
262     res = []
263     try:
264         for fileName in os.listdir(SERVICE_DIR):
265             serviceName = os.path.splitext(fileName)[0]
266             res.append(serviceName)
267     except BaseException, e:
268         return returnServerError(e)
269
270     return jsonify({"code": 200, "result": res})
271
272
273 @app.route("/service/content")
274 def getServiceContent():
275     res = {}
276     try:
277         serviceName = request.values.get("serviceName")
278         for fileName in os.listdir(SERVICE_DIR):
279             if serviceName == os.path.splitext(fileName)[0]:
280                 res["actions"] = []
281                 filePath = os.path.join(SERVICE_DIR, fileName)
282                 with open(filePath, "r") as f:
283                     content = yaml.load(f)
284                     apisArr = content[serviceName]['apis']
285                     for i in range(len(apisArr)):
286                         apisArr[i].pop("method")
287                         apisArr[i].pop("baseuri")
288                     res["actions"] = apisArr
289     except BaseException, e:
290         return returnServerError(e)
291
292     if res == {}:
293         return jsonify({"code": 300, "error": "no such service!"})
294
295     return jsonify({"code": 200, "result": res})
296
297
298 def paramTransform(paramDict):
299     res = []
300     for (key, value) in paramDict.items():
301         paramJson = {}
302         paramJson["name"] = key
303         paramJson["description"] = value["help"]
304         if "params" in value:
305             paramJson["params"] = paramTransform(value["params"])
306         res.append(paramJson)
307     return res
308
309
310 @app.route("/service/action_response")
311 def actionResponse():
312     res = {}
313     try:
314         serviceName = request.values.get("serviceName")
315         actionName = request.values.get("actionName")
316         for fileName in os.listdir(SERVICE_DIR):
317             if serviceName == os.path.splitext(fileName)[0]:
318                 res["responseParams"] = []
319                 filePath = os.path.join(SERVICE_DIR, fileName)
320                 with open(filePath, "r") as f:
321                     content = yaml.load(f)
322                     apisArr = content[serviceName]['apis']
323                 for i in range(len(apisArr)):
324                     if actionName == apisArr[i]['name'] and (
325                        "response" in apisArr[i]):
326                         res["responseParams"] = apisArr[i]["response"]
327     except BaseException, e:
328         return returnServerError(e)
329     if res == {}:
330         return jsonify({"code": 300, "error": "no such service!"})
331     return jsonify({"code": 200, "result": res})
332
333
334 ###############
335 # 3.2 API FOR ENVIRONMENT SERVICE AND CONTEXT
336 ###########################################################################
337 @app.route('/env/getAllServices')
338 def getAllService():
339     res = []
340     id = 1
341     try:
342         for fileName in os.listdir(SERVICE_DIR):
343             item = {}
344             item['id'] = id
345             item['name'] = os.path.splitext(fileName)[0]
346             filePath = os.path.join(SERVICE_DIR, fileName)
347             filemt = time.localtime(os.stat(filePath).st_mtime)
348             item['time'] = time.strftime("%Y-%m-%d", filemt)
349             res.append(item)
350             id = id + 1
351     except BaseException, e:
352         return returnServerError(e)
353     return jsonify({"code": 200, "result": res})
354
355
356 @app.route('/env/getService')
357 def getService():
358     try:
359         serviceName = request.values.get('serviceName')
360         serviceFile = serviceName + '.yaml'
361         servicePath = os.path.join(SERVICE_DIR, serviceFile)
362         if os.path.exists(servicePath):
363             with open(servicePath, "r") as f:
364                 serviceDict = yaml.load(f)
365                 serviceDict = serviceDict[serviceName]
366             return jsonify({"code": 200, "result": serviceDict})
367         else:
368             return jsonify({"code": 300, "error": "no such service!"})
369     except BaseException, e:
370         return returnServerError(e)
371
372
373 @app.route('/env/createService', methods=['POST'])
374 def createService():
375     try:
376         name = str(request.values.get('name'))
377         ip = str(request.values.get('ip'))
378         port = int(request.values.get('port'))
379         apis = json.loads(request.values.get('apis'))
380         service = {
381             name: {
382                 'ip': ip,
383                 'port': port,
384                 'apis': apis
385             }
386         }
387         serviceJson = json.dumps(service, indent=True)
388         print serviceJson
389         app.logger.debug(service)
390
391         serviceFile = name + '.yaml'
392         servicePath = os.path.join(SERVICE_DIR, serviceFile)
393         with open(servicePath, 'w') as f:
394             license_header = getLicense()
395             f.write(license_header)
396             pyaml.dump(service, f, safe=True)
397     except BaseException, e:
398         return returnServerError(e)
399     return jsonify({"code": 200, "result": "create success!"})
400
401
402 @app.route('/env/editService', methods=['POST'])
403 def editService():
404     try:
405         oldName = str(request.values.get('oldName'))
406         name = str(request.values.get('newName'))
407         ip = str(request.values.get('ip'))
408         port = int(request.values.get('port'))
409         apis = json.loads(request.values.get('apis'))
410         app.logger.debug(apis)
411         service = {
412             name: {
413                 'ip': ip,
414                 'port': port,
415                 'apis': apis
416             }
417         }
418         serviceJson = json.dumps(service, indent=True)
419         print serviceJson
420         app.logger.debug(service)
421
422         for fileName in os.listdir(SERVICE_DIR):
423             serviceName = os.path.splitext(fileName)[0]
424             if serviceName == oldName:
425                 filePath = os.path.join(SERVICE_DIR, fileName)
426                 os.remove(filePath)
427
428         serviceFile = name + '.yaml'
429         servicePath = os.path.join(SERVICE_DIR, serviceFile)
430         with open(servicePath, 'w') as f:
431             license_header = getLicense()
432             f.write(license_header)
433             pyaml.dump(service, f, safe=True)
434     except BaseException, e:
435         return returnServerError(e)
436     return jsonify({"code": 200, "result": "edit success!"})
437
438
439 @app.route('/env/deleteService', methods=['POST'])
440 def deleteService():
441     try:
442         name = str(request.values.get('serviceName'))
443
444         for fileName in os.listdir(SERVICE_DIR):
445             serviceName = os.path.splitext(fileName)[0]
446             if serviceName == name:
447                 filePath = os.path.join(SERVICE_DIR, fileName)
448                 os.remove(filePath)
449     except BaseException, e:
450         return returnServerError(e)
451     return jsonify({"code": 200, "result": "delete success!"})
452
453
454 @app.route('/env/getContext')
455 def getContext():
456     try:
457         with open(CONTEXT_FILE_DIR, "r") as f:
458             fileContent = f.read()
459         res = fileContent
460     except BaseException, e:
461         return returnServerError(e)
462     return jsonify({"code": 200, "result": {"context": res}})
463
464
465 @app.route('/env/editContext', methods=['POST'])
466 def editContext():
467     try:
468         context = request.values.get("context")
469         test = yaml.load(context)
470         print test
471         with open(CONTEXT_FILE_DIR, "w") as f:
472             f.write(context)
473     except yaml.constructor.ConstructorError, e:
474         app.logger.error(traceback.format_exc())
475         return jsonify({"code": 500, "error":
476                         "context content error: not a .yaml file!"})
477     except BaseException, e:
478         return returnServerError(e)
479
480     return jsonify({"code": 200, "result": "edit context success!"})
481
482
483 def getLicense():
484     licenseDir = os.path.join(CONFIG_DIR, "license")
485     with open(licenseDir, 'r') as f:
486         content = f.read()
487     if content is None:
488         return ''
489     return content + '\n---\n\n'
490
491 ###########################################################################
492
493
494 def returnServerError(e, msg="Server Error"):
495     print e
496     app.logger.error(traceback.format_exc())
497     return jsonify({"code": 500, "error": msg})
498
499
500 if __name__ == "__main__":
501     app.run(host='0.0.0.0', port=5310)