def test_get_selected_testcases_works_with_both_string_and_int_pks(self): """ Assures that tcms.testcases.views.get_selected_testcases returns the same results, regardless of whether the passed request contains the case pks as strings or integers, as long as they are the same in both occasions. """ case_int_pks = [ self.case.pk, self.case_1.pk, self.case_2.pk, self.case_3.pk ] case_str_pks = [] for _pk in case_int_pks: case_str_pks.append(str(_pk)) int_pk_query = get_selected_testcases(RequestFactory().post( reverse('testcases-clone'), {'case': case_int_pks})) str_pk_query = get_selected_testcases(RequestFactory().post( reverse('testcases-clone'), {'case': case_str_pks})) for case in TestCase.objects.filter(pk__in=case_int_pks): self.assertTrue(case in int_pk_query) self.assertTrue(case in str_pk_query)
def _write_cases_to_test_plan(request, plan_id): try: test_plan = TestPlan.objects.get(pk=int(plan_id)) except ObjectDoesNotExist: raise Http404 test_runs = TestRun.objects.filter(plan=plan_id).values('pk', 'summary', 'build__name', 'manager__username') # Ready to write cases to test plan test_cases = get_selected_testcases(request).values('pk', 'summary', 'author__username', 'create_date', 'category__name', 'priority__value', ) context_data = { 'plan_id': plan_id, 'plan': test_plan, 'test_runs': test_runs.iterator(), 'test_cases': test_cases.iterator(), } return render(request, 'plan/choose_testrun.html', context_data)
def get(self, request, plan_id): plan = TestPlan.objects.filter( pk=int(plan_id)).defer('product_version').first() if plan is None: raise Http404 # TODO: replace with plan.run.values(...) runs = TestRun.objects.filter(plan=plan_id).values( 'pk', 'summary', 'build__name', 'manager__username') cases = get_selected_testcases(request).values('pk', 'summary', 'author__username', 'create_date', 'category__name', 'priority__value') return render(request, self.template_name, context={ 'module': MODULE_NAME, 'sub_module': self.SUB_MODULE_NAME, 'plan_id': plan_id, 'plan': plan, 'test_runs': runs.iterator(), 'test_cases': cases, })
def post(self, request, plan_id): plan = get_object_or_404(TestPlan.objects.only('pk'), pk=int(plan_id)) if 'case' not in request.POST: return JsonResponse({ 'rc': 1, 'response': 'At least one case is required to delete.' }) cases = get_selected_testcases(request).only('pk') for case in cases: plan.delete_case(case=case) return JsonResponse({'rc': 0, 'response': 'ok'})
def delete_cases(self): if not request.POST.get('case'): ajax_response['rc'] = 1 ajax_response['response'] = 'At least one case is required to delete.' return JsonResponse(ajax_response) tcs = get_selected_testcases(request) # Log Action tp_log = TCMSLog(model=tp) for tc in tcs: tp_log.make(who=request.user, action='Remove case %s from plan %s' % (tc.case_id, tp.plan_id)) tc.log_action(who=request.user, action='Remove from plan %s' % tp.plan_id) tp.delete_case(case=tc) return JsonResponse(ajax_response)
def post(self, request, plan_id): plan = get_object_or_404(TestPlan.objects.only('pk'), pk=int(plan_id)) if 'case' not in request.POST: return JsonResponseBadRequest( {'message': 'At least one case is required to delete.'}) cases = get_selected_testcases(request).only('pk') # Log Action plan_log = TCMSLog(model=plan) for case in cases: plan_log.make( who=request.user, new_value=f'Remove case {case.pk} from plan {plan.pk}') case.log_action(who=request.user, new_value=f'Remove from plan {plan.pk}') plan.delete_case(case=case) return JsonResponse({})
def post(self, request, plan_id): plan = get_object_or_404(TestPlan.objects.only('pk'), pk=int(plan_id)) if 'case' not in request.POST: return JsonResponse({ 'rc': 1, 'response': 'At least one case is required to delete.' }) cases = get_selected_testcases(request).only('pk') # Log Action plan_log = TCMSLog(model=plan) for case in cases: plan_log.make( who=request.user, action='Remove case {} from plan {}'.format(case.pk, plan.pk)) case.log_action(who=request.user, action='Remove from plan {}'.format(plan.pk)) plan.delete_case(case=case) return JsonResponse({'rc': 0, 'response': 'ok'})
def post(self, request, plan_id): plan = get_object_or_404(TestPlan.objects.only('pk'), pk=int(plan_id)) if 'case' not in request.POST: return JsonResponse({ 'rc': 1, 'response': 'At least one case is required to delete.' }) cases = get_selected_testcases(request).only('pk') # Log Action plan_log = TCMSLog(model=plan) for case in cases: plan_log.make( who=request.user, new_value='Remove case {} from plan {}'.format(case.pk, plan.pk)) case.log_action( who=request.user, new_value='Remove from plan {}'.format(plan.pk)) plan.delete_case(case=case) return JsonResponse({'rc': 0, 'response': 'ok'})
def case(self): from tcms.testcases.views import get_selected_testcases return self.template_name, get_selected_testcases(self.request)
def post(self, request): # If from_plan does not exist will redirect to plans for select a plan plan_id = request.POST.get('from_plan') if not plan_id: messages.add_message( request, messages.ERROR, _('Creating a TestRun requires a TestPlan, select one')) return HttpResponseRedirect(reverse('plans-search')) if not request.POST.get('case'): messages.add_message( request, messages.ERROR, _('Creating a TestRun requires at least one TestCase')) return HttpResponseRedirect( reverse('test_plan_url_short', args=[plan_id])) # Ready to write cases to test plan test_cases = get_selected_testcases(request) test_plan = TestPlan.objects.get(pk=plan_id) # note: ordered by pk for test_show_create_new_run_page() tcs_values = test_cases.select_related('author', 'case_status', 'category', 'priority').order_by('pk') if request.POST.get('POSTING_TO_CREATE'): form = NewRunForm(request.POST) form.populate(product_id=test_plan.product_id) if form.is_valid(): # Process the data in form.cleaned_data default_tester = form.cleaned_data['default_tester'] test_run = TestRun.objects.create( product_version=test_plan.product_version, stop_date=None, summary=form.cleaned_data.get('summary'), notes=form.cleaned_data.get('notes'), plan=test_plan, build=form.cleaned_data['build'], manager=form.cleaned_data['manager'], default_tester=default_tester, ) loop = 1 for case in form.cleaned_data['case']: try: tcp = TestCasePlan.objects.get(plan=test_plan, case=case) sortkey = tcp.sortkey except ObjectDoesNotExist: sortkey = loop * 10 test_run.create_execution(case=case, sortkey=sortkey, assignee=default_tester) loop += 1 return HttpResponseRedirect( reverse('testruns-get', args=[ test_run.pk, ])) else: form = NewRunForm( initial={ 'summary': 'Test run for %s' % test_plan.name, 'manager': test_plan.author.email, 'default_tester': request.user.email, 'notes': '', }) form.populate(product_id=test_plan.product_id) context_data = { 'test_plan': test_plan, 'test_cases': tcs_values, 'form': form, } return render(request, self.template_name, context_data)
def new(request): """Display the create test run page.""" # If from_plan does not exist will redirect to plans for select a plan if not request.POST.get('from_plan'): messages.add_message( request, messages.ERROR, _('Creating a TestRun requires a TestPlan, select one')) return HttpResponseRedirect(reverse('plans-search')) plan_id = request.POST.get('from_plan') # case is required by a test run # NOTE: currently this is handled in JavaScript but in the TestRun creation # form cases can be deleted if not request.POST.get('case'): messages.add_message( request, messages.ERROR, _('Creating a TestRun requires at least one TestCase')) return HttpResponseRedirect( reverse('test_plan_url_short', args=[plan_id])) # Ready to write cases to test plan test_cases = get_selected_testcases(request) test_plan = TestPlan.objects.get(plan_id=plan_id) # note: ordered by case_id for test_show_create_new_run_page() tcs_values = test_cases.select_related('author', 'case_status', 'category', 'priority').order_by('case_id') if request.POST.get('POSTING_TO_CREATE'): form = NewRunForm(request.POST) form.populate(product_id=test_plan.product_id) if form.is_valid(): # Process the data in form.cleaned_data default_tester = form.cleaned_data['default_tester'] test_run = TestRun.objects.create( product_version=test_plan.product_version, stop_date=None, summary=form.cleaned_data.get('summary'), notes=form.cleaned_data.get('notes'), plan=test_plan, build=form.cleaned_data['build'], manager=form.cleaned_data['manager'], default_tester=default_tester, ) try: assignee_tester = User.objects.get(username=default_tester) except ObjectDoesNotExist: assignee_tester = None loop = 1 for case in form.cleaned_data['case']: try: tcp = TestCasePlan.objects.get(plan=test_plan, case=case) sortkey = tcp.sortkey except ObjectDoesNotExist: sortkey = loop * 10 test_run.add_case_run(case=case, sortkey=sortkey, assignee=assignee_tester) loop += 1 return HttpResponseRedirect( reverse('testruns-get', args=[ test_run.run_id, ])) else: form = NewRunForm( initial={ 'summary': 'Test run for %s' % test_plan.name, 'manager': test_plan.author.email, 'default_tester': request.user.email, 'notes': '', }) form.populate(product_id=test_plan.product_id) context_data = { 'test_plan': test_plan, 'test_cases': tcs_values, 'form': form, } return render(request, 'testruns/mutable.html', context_data)
def get_update_targets(self): self._update_objects = get_selected_testcases(self.request) return self._update_objects
def choose_run(request, plan_id, template_name='plan/choose_testrun.html'): """Choose one run to add cases""" # Define the default sub module SUB_MODULE_NAME = 'runs' if request.method == 'GET': try: plan_id = int(plan_id) tp = TestPlan.objects.filter( pk=plan_id).defer('product_version')[0] except IndexError: raise Http404 testruns = TestRun.objects.filter(plan=plan_id).values( 'pk', 'summary', 'build__name', 'manager__username') # Ready to write cases to test plan tcs = get_selected_testcases(request) tcs = tcs.values( 'pk', 'summary', 'author__username', 'create_date', 'category__name', 'priority__value', ) context_data = { 'module': MODULE_NAME, 'sub_module': SUB_MODULE_NAME, 'plan_id': plan_id, 'plan': tp, 'test_runs': testruns.iterator(), 'test_cases': tcs.iterator(), } return render(request, template_name, context=context_data) # Add cases to runs if request.method == 'POST': choosed_testrun_ids = request.POST.getlist('testrun_ids') to_be_added_cases = TestCase.objects.filter( pk__in=request.POST.getlist('case_ids')) # cases and runs are required in this process if not len(choosed_testrun_ids) or not len(to_be_added_cases): return HttpResponse( Prompt.render( request=request, info_type=Prompt.Info, info= 'At least one test run and one case is required to add cases to runs.', next=reverse('plan-get', args=[plan_id]), )) # Adding cases to runs by recursion for tr_id in choosed_testrun_ids: testrun = get_object_or_404(TestRun, run_id=tr_id) cases = TestCaseRun.objects.filter(run=tr_id) exist_cases_id = cases.values_list('case', flat=True) for testcase in to_be_added_cases: if testcase.case_id not in exist_cases_id: testrun.add_case_run(case=testcase) estimated_time = six.moves.reduce( lambda x, y: x + y, [nc.estimated_time for nc in to_be_added_cases]) testrun.estimated_time = testrun.estimated_time + estimated_time testrun.save() return HttpResponseRedirect(reverse('plan-get', args=[plan_id]))
def case(self): return self.template_name, get_selected_testcases(self.request)
def get_testcases(self): from tcms.testcases.views import get_selected_testcases return get_selected_testcases(self.request)
def choose_run(request, plan_id, template_name='plan/choose_testrun.html'): '''Choose one run to add cases''' if request.method == 'GET': try: plan_id = int(plan_id) tp = TestPlan.objects.filter(pk=plan_id).defer('product_version')[0] except IndexError: raise Http404 testruns = TestRun.objects.filter(plan=plan_id).values('pk', 'summary', 'build__name', 'manager__username') # Ready to write cases to test plan tcs = get_selected_testcases(request) tcs = tcs.values('pk', 'summary', 'author__username', 'create_date', 'category__name', 'priority__value', ) context_data = { 'plan_id': plan_id, 'plan': tp, 'test_runs': testruns.iterator(), 'test_cases': tcs.iterator(), } return render(request, template_name, context_data) # Add cases to runs if request.method == 'POST': chosen_testrun_ids = request.POST.getlist('testrun_ids') to_be_added_cases = TestCase.objects.filter(pk__in=request.POST.getlist('case_ids')) # Adding cases to runs by recursion cases_selected = 0 for tr_id in chosen_testrun_ids: testrun = get_object_or_404(TestRun, run_id=tr_id) cases = TestCaseRun.objects.filter(run=tr_id) existing_cases = cases.values_list('case', flat=True) for testcase in to_be_added_cases: # counter used as a flag that runs or cases were selected # in the form, regardless of whether or not they were actually added # used to produce an error message if user clicked the Update button # without selecting anything on the screen cases_selected += 1 if testcase.case_id not in existing_cases: testrun.add_case_run(case=testcase) estimated_time = reduce(lambda x, y: x + y, [nc.estimated_time for nc in to_be_added_cases]) testrun.estimated_time = testrun.estimated_time + estimated_time testrun.save() else: if not cases_selected: messages.add_message(request, messages.ERROR, _('Select at least one TestRun and one TestCase')) return HttpResponseRedirect(reverse('test_plan_url_short', args=[plan_id]))
def new(request, template_name='run/new.html'): """Display the create test run page.""" # If from_plan does not exist will redirect to plans for select a plan if not request.POST.get('from_plan'): return HttpResponseRedirect(reverse('plans-all')) plan_id = request.POST.get('from_plan') # case is required by a test run # NOTE: currently this is handled in JavaScript but in the TestRun creation # form cases can be deleted if not request.POST.get('case'): messages.add_message( request, messages.ERROR, _('Creating a TestRun requires at least one TestCase')) return HttpResponseRedirect( reverse('test_plan_url_short', args=[plan_id])) # Ready to write cases to test plan confirm_status = TestCaseStatus.get_CONFIRMED() test_cases = get_selected_testcases(request) # FIXME: optimize this query, only get necessary columns, not all fields # are necessary test_plan = TestPlan.objects.select_related().get(plan_id=plan_id) test_case_runs = TestCaseRun.objects.filter( case_run_id__in=request.POST.getlist('case_run_id')) num_unconfirmed_cases = test_cases.exclude( case_status=confirm_status).count() estimated_time = datetime.timedelta(seconds=0) tcs_values = test_cases.select_related('author', 'case_status', 'category', 'priority') # note: ordered for test_show_create_new_run_page() on PostgreSQL tcs_values = tcs_values.only('case_id', 'summary', 'estimated_time', 'author__email', 'create_date', 'category__name', 'priority__value', 'case_status__name').order_by('case_id') if request.POST.get('POSTING_TO_CREATE'): form = NewRunForm(request.POST) form.populate( product_id=request.POST.get('product', test_plan.product_id)) if form.is_valid(): # Process the data in form.cleaned_data default_tester = form.cleaned_data['default_tester'] test_run = TestRun.objects.create( product_version=form.cleaned_data['product_version'], stop_date=None, summary=form.cleaned_data.get('summary'), notes=form.cleaned_data.get('notes'), plan=test_plan, build=form.cleaned_data['build'], manager=form.cleaned_data['manager'], default_tester=default_tester, estimated_time=form.cleaned_data['estimated_time'], auto_update_run_status=form. cleaned_data['auto_update_run_status']) keep_status = form.cleaned_data['keep_status'] keep_assign = form.cleaned_data['keep_assignee'] try: assignee_tester = User.objects.get(username=default_tester) except ObjectDoesNotExist: assignee_tester = None loop = 1 # not reserve assignee and status, assignee will default set to # default_tester if not keep_assign and not keep_status: for case in form.cleaned_data['case']: try: tcp = TestCasePlan.objects.get(plan=test_plan, case=case) sortkey = tcp.sortkey except ObjectDoesNotExist: sortkey = loop * 10 test_run.add_case_run(case=case, sortkey=sortkey, assignee=assignee_tester) loop += 1 # Add case to the run for test_case_run in test_case_runs: if (keep_status and keep_assign): test_run.add_case_run( case=test_case_run.case, assignee=test_case_run.assignee, case_run_status=test_case_run.case_run_status, sortkey=test_case_run.sortkey or loop * 10) loop += 1 elif keep_status and not keep_assign: test_run.add_case_run( case=test_case_run.case, case_run_status=test_case_run.case_run_status, sortkey=test_case_run.sortkey or loop * 10) loop += 1 elif keep_assign and not keep_status: test_run.add_case_run(case=test_case_run.case, assignee=test_case_run.assignee, sortkey=test_case_run.sortkey or loop * 10) loop += 1 # Write the values into tcms_env_run_value_map table env_property_id_set = set(request.POST.getlist("env_property_id")) if env_property_id_set: args = list() for property_id in env_property_id_set: checkbox_name = 'select_property_id_%s' % property_id select_name = 'select_property_value_%s' % property_id checked = request.POST.getlist(checkbox_name) if checked: env_values = request.POST.getlist(select_name) if not env_values: continue if len(env_values) != len(checked): raise ValueError('Invalid number of env values.') for value_id in env_values: args.append( EnvRunValueMap(run=test_run, value_id=value_id)) EnvRunValueMap.objects.bulk_create(args) return HttpResponseRedirect( reverse('testruns-get', args=[ test_run.run_id, ])) else: estimated_time = reduce(lambda x, y: x + y, (tc.estimated_time for tc in tcs_values)) form = NewRunForm( initial={ 'summary': 'Test run for %s on %s' % (test_plan.name, test_plan.env_group.all() and test_plan.env_group.all()[0] or 'Unknown environment'), 'estimated_time': estimated_time, 'manager': test_plan.author.email, 'default_tester': request.user.email, 'product': test_plan.product_id, 'product_version': test_plan.product_version_id, }) form.populate(product_id=test_plan.product_id) # FIXME: pagination cases within Create New Run page. context_data = { 'from_plan': plan_id, 'test_plan': test_plan, 'test_cases': tcs_values, 'form': form, 'num_unconfirmed_cases': num_unconfirmed_cases, 'run_estimated_time': estimated_time.total_seconds(), } return render(request, template_name, context_data)
def choose_run(request, plan_id, template_name='plan/choose_testrun.html'): '''Choose one run to add cases''' # Define the default sub module SUB_MODULE_NAME = 'runs' if request.method == 'GET': try: plan_id = int(plan_id) tp = TestPlan.objects.filter(pk=plan_id).defer('product_version')[0] except IndexError: raise Http404 testruns = TestRun.objects.filter(plan=plan_id).values('pk', 'summary', 'build__name', 'manager__username') # Ready to write cases to test plan tcs = get_selected_testcases(request) tcs = tcs.values('pk', 'summary', 'author__username', 'create_date', 'category__name', 'priority__value', ) context_data = { 'module': MODULE_NAME, 'sub_module': SUB_MODULE_NAME, 'plan_id': plan_id, 'plan': tp, 'test_runs': testruns.iterator(), 'test_cases': tcs.iterator(), } return render_to_response(template_name, context_data, context_instance=RequestContext(request)) # Add cases to runs if request.method == 'POST': choosed_testrun_ids = request.POST.getlist('testrun_ids') to_be_added_cases = TestCase.objects.filter(pk__in=request.POST.getlist('case_ids')) # cases and runs are required in this process if not len(choosed_testrun_ids) or not len(to_be_added_cases): return HttpResponse(Prompt.render( request=request, info_type=Prompt.Info, info='At least one test run and one case is required to add cases to runs.', next=reverse('tcms.testplans.views.get', args=[plan_id]), )) # Adding cases to runs by recursion for tr_id in choosed_testrun_ids: testrun = get_object_or_404(TestRun, run_id=tr_id) cases = TestCaseRun.objects.filter(run=tr_id) exist_cases_id = cases.values_list('case', flat=True) for testcase in to_be_added_cases: if testcase.case_id not in exist_cases_id: testrun.add_case_run(case=testcase) estimated_time = reduce(lambda x, y: x + y, [nc.estimated_time for nc in to_be_added_cases]) testrun.estimated_time = testrun.estimated_time + estimated_time testrun.save() return HttpResponseRedirect(reverse('tcms.testplans.views.get', args=[plan_id]))
def new(request, template_name='run/new.html'): """Display the create test run page.""" SUB_MODULE_NAME = "new_run" # If from_plan does not exist will redirect to plans for select a plan if not request.POST.get('from_plan'): return HttpResponseRedirect(reverse('plans-all')) plan_id = request.POST.get('from_plan') # Case is required by a test run if not request.POST.get('case'): return prompt.info(request, 'At least one case is required by a run.', reverse('plan-get', args=[plan_id])) # Ready to write cases to test plan confirm_status = TestCaseStatus.get('CONFIRMED') tcs = get_selected_testcases(request) # FIXME: optimize this query, only get necessary columns, not all fields # are necessary tp = TestPlan.objects.select_related().get(plan_id=plan_id) tcrs = TestCaseRun.objects.filter( case_run_id__in=request.POST.getlist('case_run_id')) num_unconfirmed_cases = tcs.exclude(case_status=confirm_status).count() estimated_time = datetime.timedelta(seconds=0) tcs_values = tcs.select_related('author', 'case_status', 'category', 'priority').only( 'case_id', 'summary', 'create_date', 'estimated_time', 'author__email', 'case_status__name', 'priority__value', 'category__name').order_by('case_id') if request.POST.get('POSTING_TO_CREATE'): form = NewRunForm(request.POST) if request.POST.get('product'): form.populate(product_id=request.POST['product']) else: form.populate(product_id=tp.product_id) if form.is_valid(): # Process the data in form.cleaned_data default_tester = form.cleaned_data['default_tester'] tr = TestRun.objects.create( product_version=form.cleaned_data['product_version'], plan_text_version=tp.latest_text() and tp.latest_text().plan_text_version or 0, stop_date=None, summary=form.cleaned_data.get('summary'), notes=form.cleaned_data.get('notes'), plan=tp, build=form.cleaned_data['build'], manager=form.cleaned_data['manager'], default_tester=default_tester, estimated_time=form.cleaned_data['estimated_time'], auto_update_run_status=form. cleaned_data['auto_update_run_status']) keep_status = form.cleaned_data['keep_status'] keep_assign = form.cleaned_data['keep_assignee'] try: assignee_tester = User.objects.get(username=default_tester) except ObjectDoesNotExist: assignee_tester = None loop = 1 # not reserve assignee and status, assignee will default set to # default_tester if not keep_assign and not keep_status: for case in form.cleaned_data['case']: try: tcp = TestCasePlan.objects.get(plan=tp, case=case) sortkey = tcp.sortkey except ObjectDoesNotExist: sortkey = loop * 10 tr.add_case_run(case=case, sortkey=sortkey, assignee=assignee_tester) loop += 1 # Add case to the run for tcr in tcrs: if (keep_status and keep_assign): tr.add_case_run(case=tcr.case, assignee=tcr.assignee, case_run_status=tcr.case_run_status, sortkey=tcr.sortkey or loop * 10) loop += 1 elif keep_status and not keep_assign: tr.add_case_run(case=tcr.case, case_run_status=tcr.case_run_status, sortkey=tcr.sortkey or loop * 10) loop += 1 elif keep_assign and not keep_status: tr.add_case_run(case=tcr.case, assignee=tcr.assignee, sortkey=tcr.sortkey or loop * 10) loop += 1 # Write the values into tcms_env_run_value_map table env_property_id_set = set(request.POST.getlist("env_property_id")) if env_property_id_set: args = list() for property_id in env_property_id_set: checkbox_name = 'select_property_id_%s' % property_id select_name = 'select_property_value_%s' % property_id checked = request.POST.getlist(checkbox_name) if checked: env_values = request.POST.getlist(select_name) if not env_values: continue if len(env_values) != len(checked): raise ValueError('Invalid number of env values.') for value_id in env_values: args.append( TCMSEnvRunValueMap(run=tr, value_id=value_id)) TCMSEnvRunValueMap.objects.bulk_create(args) return HttpResponseRedirect(reverse('run-get', args=[tr.run_id])) else: estimated_time = functools.reduce(operator.add, (tc.estimated_time for tc in tcs_values)) form = NewRunForm( initial={ 'summary': 'Test run for {} on {}'.format( tp.name, tp.env_group.all() and tp.env_group.all()[0] or 'Unknown environment'), 'estimated_time': format_timedelta(estimated_time), 'manager': tp.author.email, 'default_tester': request.user.email, 'product': tp.product_id, 'product_version': tp.product_version_id, }) form.populate(product_id=tp.product_id) # FIXME: pagination cases within Create New Run page. context_data = { 'module': MODULE_NAME, 'sub_module': SUB_MODULE_NAME, 'from_plan': plan_id, 'test_plan': tp, 'test_cases': tcs_values, 'form': form, 'num_unconfirmed_cases': num_unconfirmed_cases, 'run_estimated_time': estimated_time, } return render(request, template_name, context=context_data)