def unlink_plan(requst, case_id, plan_id): """ Description: Unlink a test case from the given plan. If only one plan is linked, this will delete the test case. Params: $case_ids - Integer/String: An integer or alias representing the ID in the database. $plan_id - Integer: An integer representing the ID in the database. Returns: Array: Array of plans hash still linked if any, empty if not. Example: >>> TestCase.unlink_plan(12345, 137) """ from tcms.apps.testplans.models import TestPlan try: tc = TestCase.objects.get(case_id = case_id) tp = tc.plan.get(plan_id = plan_id) except: raise tc.remove_plan(plan = tp) plan_ids = tc.plan.values_list('plan_id', flat = True) query = {'plan_id__in': plan_ids} return TestPlan.to_xmlrpc(query)
def test_to_xmlrpc(self): result = TestPlan.to_xmlrpc(query={'pk__in': self.plan_pks}) self.assertEqual(len(result), 2) # Verify fields sample_testplan = result[0] sample_fields = set([name for name in sample_testplan.keys()]) test_fields = set(self.test_fields) test_result = list(sample_fields ^ test_fields) self.assertEqual(test_result, []) result = dict([(item['plan_id'], item) for item in result]) plan = result[self.plan_pks[0]] sample_plan = TestPlan.objects.get(pk=self.plan_pks[0]) self.assertEqual(plan['default_product_version'], sample_plan.default_product_version) self.assertEqual(plan['name'], sample_plan.name) self.assertEqual(plan['is_active'], sample_plan.is_active) components = plan['component'] components.sort() sample_components = [item.pk for item in sample_plan.component.all()] sample_components.sort() self.assertEqual(components, sample_components) plan = result[self.plan_pks[1]] sample_plan = TestPlan.objects.get(pk=self.plan_pks[1]) self.assertEqual(plan['default_product_version'], sample_plan.default_product_version) self.assertEqual(plan['name'], sample_plan.name) self.assertEqual(plan['is_active'], sample_plan.is_active)
def ajax_search(request, template_name='plan/common/json_plans.txt'): """Display all testplans""" # Define the default sub module SUB_MODULE_NAME = 'plans' # If it's not a search the page will be blank tps = TestPlan.objects.none() query_result = False # if it's a search request the page will be fill if request.REQUEST.items(): search_form = SearchPlanForm(request.REQUEST) if request.REQUEST.get('product'): search_form.populate(product_id=request.REQUEST['product']) else: search_form.populate() if search_form.is_valid(): # Detemine the query is the user's plans and change the sub module value if request.REQUEST.get('author__email__startswith') and len(search_form.changed_data) == 1: if request.user.is_authenticated(): if request.REQUEST['author__email__startswith'] == request.user.username \ or request.REQUEST['author__email__startswith'] == request.user.email: user_email = request.REQUEST['author__email__startswith'] tps = TestPlan.objects.filter(Q(author__email__startswith=user_email) | Q(owner__email__startswith=user_email)).distinct() else: tps = TestPlan.list(search_form.cleaned_data) tps = tps.select_related('author', 'type', 'product') query_result = True # We want to get the number of cases and runs, without doing # lots of per-test queries. # # Ideally we would get the case/run counts using m2m field tricks # in the ORM # Unfortunately, Django's select_related only works on ForeignKey # relationships, not on ManyToManyField attributes # See http://code.djangoproject.com/ticket/6432 # SQLAlchemy can handle this kind of thing in several ways. # Unfortunately we're using Django # The cleanest way I can find to get it into one query is to # use QuerySet.extra() # See http://docs.djangoproject.com/en/dev/ref/models/querysets tps = tps.extra(select={ 'num_cases': RawSQL.num_cases, 'num_runs': RawSQL.num_runs, 'num_children': RawSQL.num_plans, }) else: # Set search active plans only by default # I wish to use 'default' argument, as the same as in ModelForm # But it does not seem to work search_form = SearchPlanForm(initial={'is_active': True}) #columnIndexNameMap is required for correct sorting behavior, 5 should be product, but we use run.build.product columnIndexNameMap = { 0: '', 1: 'plan_id', 2: 'name', 3: 'author__username', 4: 'owner__username', 5: 'product', 6: 'default_product_version', 7: 'type', 8: 'num_cases', 9: 'num_runs', 10: ''} return ajax_response(request, tps, columnIndexNameMap, jsonTemplatePath='plan/common/json_plans.txt')
def get_plans(request, case_id): """ Description: Get the list of plans that this case is linked to. Params: $case_id - Integer/String: An integer representing the ID in the database Returns: Array: An array of test plan object hashes. Example: >>> TestCase.get_plans(12345) """ from tcms.apps.testplans.models import TestPlan try: tc = TestCase.objects.get(case_id = case_id) except: raise plan_ids = tc.plan.values_list('plan_id', flat = True) query = {'plan_id__in': plan_ids} return TestPlan.to_xmlrpc(query)
def get_plans(request, product): """ Description: Get the list of plans associated with this product. Params: $product - Integer/String Integer: product_id of the product in the Database String: Product name Returns: Array: Returns an array of Test Plan objects. Example: # Get with product id >>> Product.get_plans(61) # Get with product name >>> Product.get_plans('Red Hat Enterprise Linux 5') """ from tcms.apps.testplans.models import TestPlan p = pre_check_product(values = product) query = {'product': p} return TestPlan.to_xmlrpc(query)
def unlink_plan(requst, case_id, plan_id): """ Description: Unlink a test case from the given plan. If only one plan is linked, this will delete the test case. Params: $case_ids - Integer/String: An integer or alias representing the ID in the database. $plan_id - Integer: An integer representing the ID in the database. Returns: Array: Array of plans hash still linked if any, empty if not. Example: >>> TestCase.unlink_plan(12345, 137) """ sql = 'DELETE FROM test_case_plans WHERE plan_id = %s and case_id = %s' cursor = connection.cursor() cursor.execute(sql, [int(plan_id), int(case_id)]) transaction.commit_unless_managed() plan_pks = TestCasePlan.objects.filter(case=case_id).values_list('plan', flat=True) return TestPlan.to_xmlrpc(query={'pk__in': plan_pks})
def filter(request, values = {}): """ Description: Performs a search and returns the resulting list of test plans. Params: $values - Hash: keys must match valid search fields. +------------------------------------------------------------+ | Plan Search Parameters | +----------------------------------------------------------+ | Key | Valid Values | | author | ForeignKey: Auth.User | | attachment | ForeignKey: Attachment | | case | ForeignKey: Test Case | | create_date | DateTime | | default_product_version | String | | env_group | ForeignKey: Environment Group | | name | String | | plan_id | Integer | | product | ForeignKey: Product | | tag | ForeignKey: Tag | | text | ForeignKey: Test Plan Text | | type | ForeignKey: Test Plan Type | +------------------------------------------------------------+ Returns: Array: Matching test plans are retuned in a list of plan object hashes. Example: # Get all of plans contain 'TCMS' in name >>> TestPlan.filter({'name__icontain': 'TCMS'}) # Get all of plans create by xkuang >>> TestPlan.filter({'author__username': '******'}) # Get all of plans the author name starts with x >>> TestPlan.filter({'author__username__startswith': 'x'}) # Get plans contain the case ID 12345, 23456, 34567 >>> TestPlan.filter({'case__case_id__in': [12345, 23456, 34567]}) """ return TestPlan.to_xmlrpc(values)
def update(request, plan_ids, values): """ Description: Updates the fields of the selected test plan. Params: $plan_ids - Integer: A single TestPlan ID. $values - Hash of keys matching TestPlan fields and the new values to set each field to. +------------------------+----------------+------------------------------------+ | Field | Type | Description | +-------------------------+----------------+------------------------------------+ | product | Integer | ID of product | | name | String | | | type | Integer | ID of plan type | | default_product_version | Integer | | | parent | Integer | Parent plan ID | | is_active | Boolean | True/False | | env_group | Integer | | +-------------------------+----------------+------------------------------------+ Returns: Hash: The updated test plan object. Example: # Update product to 61 for plan 207 and 208 >>> TestPlan.update([207, 208], {'product': 61}) """ from tcms.core import forms from tcms.apps.testplans.forms import XMLRPCEditPlanForm if values.get('is_active') in (False, True): if values.get('is_active') == False: values['is_active'] = 0 else: values['is_active'] = 1 form = XMLRPCEditPlanForm(values) if values.get('default_product_version') and not values.get('product'): raise ValueError('Product value is required by default product version') if values.get('default_product_version') and values.get('product'): form.populate(product_id = values['product']) tps = TestPlan.objects.filter(pk__in = pre_process_ids(value = plan_ids)) if form.is_valid(): if form.cleaned_data['name']: tps.update(name = form.cleaned_data['name']) if form.cleaned_data['type']: tps.update(type = form.cleaned_data['type']) if form.cleaned_data['product']: tps.update(product = form.cleaned_data['product']) if form.cleaned_data['default_product_version']: tps.update(default_product_version = form.cleaned_data['default_product_version']) if form.cleaned_data['parent']: tps.update(parent = form.cleaned_data['parent']) if isinstance(form.cleaned_data['is_active'], int): tps.update(is_active = form.cleaned_data['is_active']) if form.cleaned_data['env_group']: for tp in tps: tp.clear_env_groups() tp.add_env_group(form.cleaned_data['env_group']) else: return forms.errors_to_list(form) query = {'pk__in': tps.values_list('pk', flat = True)} return TestPlan.to_xmlrpc(query)
def update(request, plan_ids, values): """ Description: Updates the fields of the selected test plan. Params: $plan_ids - Integer: A single TestPlan ID. $values - Hash of keys matching TestPlan fields and the new values to set each field to. +------------------------+----------------+------------------------------------+ | Field | Type | Description | +-------------------------+----------------+------------------------------------+ | product | Integer | ID of product | | name | String | | | type | Integer | ID of plan type | | default_product_version | Integer | | | parent | Integer | Parent plan ID | | is_active | Boolean | True/False | | env_group | Integer | | +-------------------------+----------------+------------------------------------+ Returns: Hash: The updated test plan object. Example: # Update product to 61 for plan 207 and 208 >>> TestPlan.update([207, 208], {'product': 61}) """ from tcms.core import forms from tcms.apps.testplans.forms import XMLRPCEditPlanForm if values.get('is_active') in (False, True): if values.get('is_active') == False: values['is_active'] = 0 else: values['is_active'] = 1 form = XMLRPCEditPlanForm(values) if values.get('default_product_version') and not values.get('product'): raise ValueError( 'Product value is required by default product version') if values.get('default_product_version') and values.get('product'): form.populate(product_id=values['product']) tps = TestPlan.objects.filter(pk__in=pre_process_ids(value=plan_ids)) if form.is_valid(): _values = dict() if form.cleaned_data['name']: _values['name'] = form.cleaned_data['name'] if form.cleaned_data['type']: _values['type'] = form.cleaned_data['type'] if form.cleaned_data['product']: _values['product'] = form.cleaned_data['product'] if form.cleaned_data['default_product_version']: _values['default_product_version'] = form.cleaned_data[ 'default_product_version'] if form.cleaned_data['parent']: _values['parent'] = form.cleaned_data['parent'] if isinstance(form.cleaned_data['is_active'], int): _values['is_active'] = form.cleaned_data['is_active'] tps.update(**_values) if form.cleaned_data['env_group']: for tp in tps.iterator(): tp.clear_env_groups() tp.add_env_group(form.cleaned_data['env_group']) else: raise ValueError(forms.errors_to_list(form)) query = {'pk__in': tps.values_list('pk', flat=True)} return TestPlan.to_xmlrpc(query)
def all(request, template_name='plan/all.html'): """Display all testplans""" # Define the default sub module SUB_MODULE_NAME = 'plans' # If it's not a search the page will be blank tps = TestPlan.objects.none() query_result = False order_by = request.REQUEST.get('order_by', 'create_date') asc = bool(request.REQUEST.get('asc', None)) # if it's a search request the page will be fill if request.REQUEST.items(): search_form = SearchPlanForm(request.REQUEST) if request.REQUEST.get('product'): search_form.populate(product_id=request.REQUEST['product']) else: search_form.populate() if search_form.is_valid(): # Detemine the query is the user's plans and change the sub module value if request.REQUEST.get('author'): if request.user.is_authenticated(): if request.REQUEST['author'] == request.user.username \ or request.REQUEST['author'] == request.user.email: SUB_MODULE_NAME = "my_plans" query_result = True # build a QuerySet: tps = TestPlan.list(search_form.cleaned_data) tps = tps.select_related('author', 'type', 'product') # We want to get the number of cases and runs, without doing # lots of per-test queries. # # Ideally we would get the case/run counts using m2m field tricks # in the ORM # Unfortunately, Django's select_related only works on ForeignKey # relationships, not on ManyToManyField attributes # See http://code.djangoproject.com/ticket/6432 # SQLAlchemy can handle this kind of thing in several ways. # Unfortunately we're using Django # The cleanest way I can find to get it into one query is to # use QuerySet.extra() # See http://docs.djangoproject.com/en/dev/ref/models/querysets tps = tps.extra(select={ 'num_cases': RawSQL.num_cases, 'num_runs': RawSQL.num_runs, 'num_children': RawSQL.num_plans, }) tps = order_plan_queryset(tps, order_by, asc) else: # Set search active plans only by default # I wish to use 'default' argument, as the same as in ModelForm # But it does not seem to work search_form = SearchPlanForm(initial={'is_active': True}) if request.REQUEST.get('action') == 'clone_case': template_name = 'case/clone_select_plan.html' tps = tps.order_by('name') if request.REQUEST.get('t') == 'ajax': return HttpResponse(serializers.serialize( request.REQUEST.get('f', 'json'), tps, extras=('num_cases','num_runs', 'num_children', 'get_url_path') )) if request.REQUEST.get('t') == 'html': if request.REQUEST.get('f') == 'preview': template_name = 'plan/preview.html' query_url = remove_from_request_path(request, 'order_by') if asc: query_url = remove_from_request_path(query_url, 'asc') else: query_url = '%s&asc=True' % query_url page_type = request.REQUEST.get('page_type', 'pagination') query_url_page_type = remove_from_request_path(request, 'page_type') if query_url_page_type: query_url_page_type = remove_from_request_path(query_url_page_type, 'page') return direct_to_template(request, template_name, { 'module': MODULE_NAME, 'sub_module': SUB_MODULE_NAME, 'test_plans' : tps, 'query_result' : query_result, 'search_plan_form' : search_form, 'query_url': query_url, 'query_url_page_type': query_url_page_type, 'page_type': page_type })