Skip to content Skip to sidebar Skip to footer

Rally Apis: How To Copy Test Folder And Member Test Cases

This question was asked by a different user earlier: Copying Test Cases and Test Folder using Rally Python or Ruby API [closed] but closed by moderators as being an overly broad qu

Solution 1:

An improvement of the same Python script that adds the following features

  • Test Folders (source and destination) are passed in arguments instead of hard coded
  • Creation is done recursively (i.e. copy Test Folders and Test Cases in it)
  • Test Cases are replaced if they already exist (based on the Name)
  • Usage of API Key to connect rather than password
  • Try 5 times to connect to Rally before giving up

To use it to copy TF10 to TF99 (which already exists): python copy_test_folder TF10 TF99

#!/usr/bin/env python###################################################################################################  copy_test_folder.py -- Copy all Test Cases in Source Test Folder to Target. Includes Test Steps#                         and attachments. Target Test Folder must exist (i.e. the script will not#                         create a new targeet Test Folder for you)#
USAGE = """
Usage: copy_test_folder.py TF_src TF_dest
"""################################################################################################## import needed python libsimport sys, os
import re
import string
import base64

from pprint import pprint

# import needed pyral libsfrom pyral import Rally, rallySettings, RallyRESTAPIError

errout = sys.stderr.write

my_server      = "rally1.rallydev.com"
my_user        = "name@domain.com"
my_password    = "<PASSWORD>"
my_workspace   = "<WORKSPACE>"
my_project     = "<PROJECT>"
my_key         = "<API KEY>"defconnect(nb_attempts=5):
    '''Connect to Rally'''global is_connected
    global rally
    #Connectifnot is_connected and nb_attempts>0:
        print"...Attempting to connect to Rally for project %s..." % my_project
        try:
            # rally = Rally(my_server, my_user, my_password, workspace=my_workspace, project=my_project)
            rally = Rally(my_server, apikey=my_key, workspace=my_workspace, project=my_project)
            print"Connected to Rally for project %s (%s)" % (my_project, my_workspace)
            is_connected=True
            rally.enableLogging('copy_test_folder.log')
        #Errors during connection (attempting to connect again)# except Exception, details: except AttributeError: 
            if nb_attempts>1:
                connect(nb_attempts-1)
            else:
                errout('Error during connection to Rally (%s)\n' % details)
                exit(4)
    else: passdefcopyTF(src_TF, dest_TF):
    '''Copy Test Cases from one folder into another (including children Test Folders)'''# List names and FormattedID of existing Test Cases in destination
    dest_TCs = dest_TF.TestCases
    existing_dest_TC = {tc.Name:tc.FormattedID for tc in dest_TCs} 

    # Copy Test Cases to destination folder (replace if Test Case with same name exists)
    src_TCs = src_TF.TestCases
    for src_TC in src_TCs:
        # Create update fields for target Test Case# Does NOT associate new Test Case to original Test Case's WorkProduct (i.e. Defect, User Story)# Does NOT copy Discussion items - as the old Discussions are likely not desired on new Test Case# Does NOT copy Last Build, Last Run, Last Update Date, Last Verdict as new Test Case will effectively# be "blank" and not have any results associated to it
        tcName = src_TC.Name
        dest_TC_fields = {
            "Package": src_TC.Package,
            "Description": src_TC.Description,
            "Method": src_TC.Method,
            "Name": tcName,
            "Objective": src_TC.Objective,
            "Owner": getattr(src_TC.Owner, 'ref', None),
            "PostConditions": src_TC.PostConditions,
            "PreConditions": src_TC.PreConditions,
            "Priority": src_TC.Priority,
            "Project": src_TC.Project.ref,
            "Risk": src_TC.Risk,
            "ValidationInput": src_TC.ValidationInput,
            "ValidationExpectedResult": src_TC.ValidationExpectedResult,
            "TestFolder": dest_TF.ref,
         }

        # Create/Update the target test casetry:
            if existing_dest_TC.has_key(tcName):
                operation = "Update"
                dest_TC_fields['FormattedID'] = existing_dest_TC[tcName]
                dest_TC = rally.update("TestCase", dest_TC_fields)
            else:
                #Create
                operation = "Create"
                dest_TC = rally.create("TestCase", dest_TC_fields)

            message = operation + "d Source Test Case: " + src_TC.FormattedID + \
                " To: " + dest_TF.FormattedID + ": " + dest_TF.Name + \
                ": " + dest_TC.FormattedID
            print message

        except RallyRESTAPIError, details:
            sys.stderr.write('ERROR: %s \n' % details)
            sys.exit(2)


        # Copy Test Steps#Cleared-up all Test Steps in destination if Test Case is updatedif operation == "Update":
            dest_TC_steps = dest_TC.Steps
            for dest_step in dest_TC_steps:
                rally.delete('TestCaseStep', dest_step.oid)
            print"===> Cleared all Test Steps"# Add Test Case Steps
        src_TC_steps = src_TC.Steps
        for src_step in src_TC_steps:
            target_step_fields = {
                "TestCase"          : dest_TC.ref,
                "StepIndex"         : src_step.StepIndex,
                "Input"             : src_step.Input,
                "ExpectedResult"    : src_step.ExpectedResult                                                   
            }
            dest_TC_step = rally.put('TestCaseStep', target_step_fields)
            print"===> Copied  TestCaseStep: %s   OID: %s" % (dest_TC_step.StepIndex, dest_TC_step.oid)                 

        # Copy Attachments
        source_attachments = rally.getAttachments(src_TC)

        for source_attachment in source_attachments:
            # First copy the content
            source_attachment_content = source_attachment.Content
            target_attachment_content_fields = {
                "Content": base64.encodestring(source_attachment_content)
            }

            try:
                target_attachment_content = rally.put('AttachmentContent', target_attachment_content_fields)
                print"===> Copied AttachmentContent: %s" % target_attachment_content.ref
            except RallyRESTAPIError, details:
                sys.stderr.write('ERROR: %s \n' % details)
                sys.exit(2)

            # Next copy the attachment object
            target_attachment_fields = {
                "Name": source_attachment.Name,
                "Description": source_attachment.Description,
                "Content": target_attachment_content.ref,
                "ContentType": source_attachment.ContentType,
                "Size": source_attachment.Size,
                "Artifact": dest_TC.ref,
                "User": source_attachment.User.ref
            }
            try:
                target_attachment = rally.put('Attachment', target_attachment_fields)
                print"===> Copied Attachment: %s" % target_attachment.ref
            except RallyRESTAPIError, details:
                sys.stderr.write('ERROR: %s \n' % details)
                sys.exit(2)


        # Copy Tags
        source_tags = src_TC.Tags;
        target_tags = list()
        for source_tag in source_tags:
            target_tags.append({"_ref":source_tag.ref})

        dest_TC_fields = {
            "FormattedID": dest_TC.FormattedID,
            "Tags": target_tags
         }

        try:
            update_response = rally.update('TestCase', dest_TC_fields)
        except RallyRESTAPIError, details:
            sys.stderr.write('ERROR: %s \n' % details)
            sys.exit(2)

    # Recursive call for each child Test Folder (after creating it)
    src_children_TFs = src_TF.Children
    dest_children_TFs = dest_TF.Children
    existing_dest_TF = {tf.Name:tf for tf in dest_children_TFs} 
    for src_child_TF in src_children_TFs:
        tfName = src_child_TF.Name
        # Create Test Folder if neededif existing_dest_TF.has_key(tfName):
            dest_child_TF = existing_dest_TF[tfName]
        else:
            target_TF_fields = {
                'Name': tfName,
                'Parent': dest_TF.ref
            }
            dest_child_TF = rally.put('TestFolder', target_TF_fields)
            print"Created Test folder %s (%s)" % (tfName, dest_child_TF.FormattedID)
        # Copy Test Cases of this folder
        copyTF(src_child_TF, dest_child_TF)

if'__main__'in __name__:

    # Get source and destination test folders
    src_TF_formatted_id = sys.argv[1]
    dest_TF_formatted_id = sys.argv[2]

    # Connect to Rallyglobal is_connected
    is_connected = False
    connect(5)

    # Query for source and target test foldersglobal rally
    src_TF_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % src_TF_formatted_id)
    dest_TF_response = rally.get('TestFolder', fetch=True, query='FormattedID = %s' % dest_TF_formatted_id)

    # Check to make sure folders existif src_TF_response.resultCount == 0:
        errout('No Source Test Folder Found matching Formatted ID: %s\n' % (src_TF_formatted_id))
        sys.exit(4)

    if dest_TF_response.resultCount == 0:
        errout('No Target Test Folder Found matching Formatted ID: %s\n. Target Test Folder must be created before copying.' % (dest_TF_formatted_id))
        sys.exit(4)

    # Get Objects of source and target Test Folders                
    src_TF = src_TF_response.next()
    dest_TF = dest_TF_response.next()

    # Copy file
    copyTF(src_TF, dest_TF)

Post a Comment for "Rally Apis: How To Copy Test Folder And Member Test Cases"