diff --git a/client/driver/fabfile.py b/client/driver/fabfile.py index 1338790..4269590 100644 --- a/client/driver/fabfile.py +++ b/client/driver/fabfile.py @@ -807,3 +807,23 @@ def integration_tests(): assert response['status'] == 'good' LOG.info("\n\nIntegration Tests: PASSED!!\n") + + +@task +def task_status_ui_test(): + # Test GPR + upload_code = 'ottertuneTestTuningGPR' + response = requests.get(dconf.WEBSITE_URL + '/test/task_status/' + upload_code) + assert 'Success:' in get_content(response) + + # Test DNN: + upload_code = 'ottertuneTestTuningDNN' + response = requests.get(dconf.WEBSITE_URL + '/test/task_status/' + upload_code) + assert 'Success:' in get_content(response) + + # Test DDPG: + upload_code = 'ottertuneTestTuningDDPG' + response = requests.get(dconf.WEBSITE_URL + '/test/task_status/' + upload_code) + assert 'Success:' in get_content(response) + + LOG.info("\n\nTask Status UI Tests: PASSED!!\n") diff --git a/server/website/website/types.py b/server/website/website/types.py index e452f2f..f1c49a4 100644 --- a/server/website/website/types.py +++ b/server/website/website/types.py @@ -105,14 +105,14 @@ class WorkloadStatusType(BaseType): class TaskType(BaseType): PREPROCESS = 1 - RUN_WM = 2 - RUN_GPR = 3 + WORKLOAD_MAPPING = 2 + RECOMMENDATION = 3 # Should be in order of execution!! TYPE_NAMES = OrderedDict([ (PREPROCESS, "Preprocess"), - (RUN_WM, "Workload Mapping"), - (RUN_GPR, "Recommendation"), + (WORKLOAD_MAPPING, "Workload Mapping"), + (RECOMMENDATION, "Recommendation"), ]) diff --git a/server/website/website/urls.py b/server/website/website/urls.py index 7d67637..81627b8 100644 --- a/server/website/website/urls.py +++ b/server/website/website/urls.py @@ -81,6 +81,7 @@ urlpatterns = [ # Test url(r'^test/create/', website_views.create_test_website, name='create_test_website'), url(r'^test/pipeline/', website_views.pipeline_data_ready, name='pipeline_data_ready'), + url(r'^test/task_status/(?P[0-9a-zA-Z]+)$', website_views.tuner_status_test, name="tuner_status_test"), # Pipeline data url(r'^pipeline/data/(?P[0-9]+)', website_views.pipeline_data_view, name='pipeline_data_view') diff --git a/server/website/website/views.py b/server/website/website/views.py index 5d89352..d13d266 100644 --- a/server/website/website/views.py +++ b/server/website/website/views.py @@ -985,8 +985,7 @@ def pipeline_data_view(request, pipeline_id): return render(request, "pipeline_data.html", context) -@login_required(login_url=reverse_lazy('login')) -def tuner_status_view(request, project_id, session_id, result_id): # pylint: disable=unused-argument +def _tuner_statue_helper(project_id, session_id, result_id): # pylint: disable=unused-argument res = Result.objects.get(pk=result_id) task_tuple = JSONUtil.loads(res.task_ids) task_ids = TaskUtil.get_task_ids_from_tuple(task_tuple)[-3:] @@ -1010,7 +1009,12 @@ def tuner_status_view(request, project_id, session_id, result_id): # pylint: di "completion_time": completion_time, "total_runtime": total_runtime, "tasks": task_info} + return context + +@login_required(login_url=reverse_lazy('login')) +def tuner_status_view(request, project_id, session_id, result_id): # pylint: disable=unused-argument + context = _tuner_statue_helper(project_id, session_id, result_id) return render(request, "task_status.html", context) @@ -1662,3 +1666,58 @@ def create_test_website(request): # pylint: disable=unused-argument set_default_knobs(s4) response = HttpResponse("Success: create test website successfully") return response + + +# For tuner status UI test +@csrf_exempt +def tuner_status_test(request, upload_code): # pylint: disable=unused-argument,too-many-return-statements + try: + session = Session.objects.get(upload_code=upload_code) + except Session.DoesNotExist: + LOG.warning("Invalid upload code: %s", upload_code) + return HttpResponse("Invalid upload code: " + upload_code, status=400) + + result = Result.objects.filter(session=session).earliest('creation_time') + context = _tuner_statue_helper(session.project.id, session.id, result.id) + overall_status = context['overall_status'] + num_completed, num_total = context['num_completed'].replace(' ', '').split('/') + task_info = context['task_info'] + num_tasks = len(task_info) + if overall_status.lower() != 'success': + return HttpResponse("Failure: overall status {} should be success".format( + overall_status.lower())) + if num_completed != num_total: + return HttpResponse("Failure: #completed tasks {} != #total tasks {}".format( + num_completed, num_total)) + if num_tasks < 3: + return HttpResponse("Failure: number of tasks {} should >= 3".format(num_tasks)) + for i in range(num_tasks): + name, task = task_info[i] + result = task.result + if i == 0: + expected_name = TaskType.TYPE_NAMES[TaskType.PREPROCESS] + if name != expected_name: + return HttpResponse("Failure: the first task {} should be {}".format( + name, expected_name)) + elif i == 1: + expected_name = TaskType.TYPE_NAMES[TaskType.WORKLOAD_MAPPING] + if name != expected_name: + return HttpResponse("Failure: the second task {} should be {}".format( + name, expected_name)) + if session.tuning_session == "tuning_session": + if session.algorithm == AlgorithmType.GPR or session.algorithm == AlgorithmType.DNN: + if isinstance(result, dict) is False: + return HttpResponse("Failure: wrong result for task {}".format(name)) + if 'mapped_workload_id' not in result: + return HttpResponse("Failure: wrong result for task {}".format(name)) + elif i == 2: + expected_name = TaskType.TYPE_NAMES[TaskType.RECOMMENDATION] + if name != expected_name: + return HttpResponse("Failure: the third task {} should be {}".format( + name, expected_name)) + if isinstance(result, dict) is False: + return HttpResponse("Failure: wrong result for task {}".format(name)) + if 'recommendation' not in result: + return HttpResponse("Failure: wrong result for task {}".format(name)) + + return HttpResponse("Success: task status view test passes")