使用pyral 0.9.3向TestCaseResults添加附件

2 投票
2 回答
877 浏览
提问于 2025-04-18 05:02

我正在尝试用pyral给一个测试结果添加附件,代码是这样的:

   testCaseResult = rally.create('TestCaseResult', {'TestCase': tc.ref , 'Build': revision,
                          'Verdict': verdict[test.result], 'Date': resultdate, 'Notes': note,
                          'Tester': tester, 'Duration': runtime })


   res = rally.addAttachment(testCaseResult.oid, file);

测试结果成功创建了,但返回的结果是False。

我哪里做错了呢?我是不是不应该使用oid?我试过传递testCaseResult、testCaseResult.oid,还有“TestCaseResult/” + testCaseResult.oid,但都不行……

更新:

根据Mark的回答(pyral并不直接支持给测试结果添加附件),我写了以下的子程序:

def addTestCaseResultAttachment(testCaseResult, filename, contentType='text/plain'):
    if not os.path.exists(filename):
        raise Exception('Named attachment filename: %s not found' % filename)
    if not os.path.isfile(filename):
        raise Exception('Named attachment filename: %s is not a regular file' % filename)

    attachment_file_name = os.path.basename(filename)
    attachment_file_size = os.path.getsize(filename)

    if attachment_file_size == 0:
        raise Exception('Cannot attach zero length file')

    if attachment_file_size > 5000000:
        raise Exception('Attachment file size too large, unable to attach to Rally Artifact')

    contents = ''
    with open(filename, 'r') as af:
        contents = base64.encodestring(af.read())

    # create an AttachmentContent item
    ac = rally.create('AttachmentContent', {"Content" : contents}, project=None)
    if not ac:
        raise RallyRESTAPIError('Unable to create AttachmentContent for %s' % attachment_file_name)

    attachment_info = { "Name"              :  attachment_file_name,
                        "Content"           :  ac.ref,       # ref to AttachmentContent
                        "ContentType"       :  contentType,
                        "Size"              :  attachment_file_size, # must be size before encoding!!
                        "User"              :  'user/%s' % me.oid,
                        "TestCaseResult"    :  testCaseResult.ref
                      }

    # and finally, create the Attachment
    attachment = rally.create('Attachment', attachment_info, project=None)
    if not attachment:
        raise RallyRESTAPIError('Unable to create Attachment for %s' % attachment_file_name)

2 个回答

1

Rally API中,addAttachment这个功能已经更新,可以支持测试用例的结果了:

# While it's actually possible to have an Attachment not linked to an Artifact,
# in most cases, it'll be far more useful to have the linkage to an Artifact than not.
# A special case is where the "Artifact" is actually a TestCaseResult, which is not a
# subclass of Artifact in the Rally data model, but the WSAPI has been adjusted to permit
# us to associate an Attachment with a TestCaseResult instance.
if artifact:  
    attachment_info["Artifact"] = artifact.ref
    if artifact._type == 'TestCaseResult':
        del attachment_info["Artifact"]
        attachment_info["TestCaseResult"] = artifact.ref

现在调用这个功能 rally.addAttachment(testCaseResult.oid, file); 应该可以正常工作了。

3

问题在于,pyral的restapi中的addAttachment方法,会把一个引用设置到附件对象的“Artifact”属性上,具体代码在restapi的1241到1251行。

    attachment_info = { "Name"        :  attachment_file_name,
                        "Content"     :  ac.ref,       # ref to AttachmentContent
                        "ContentType" :  mime_type,    
                        "Size"        :  attachment_file_size, # must be size before encoding!!
                        "User"        :  'user/%s' % self.contextHelper.user_oid,
                       #"Artifact"    :  artifact.ref  # (Artifact is an 'optional' field)
                      }

    # While it's actually possible to have an Attachment not linked to an Artifact,
    # in most cases, it'll be far more useful to have the linkage to an Artifact than not.
    if artifact:  
        attachment_info["Artifact"] = artifact.ref

因此,addAttachment方法实际上只适用于那些从Artifact继承的对象,比如故事、缺陷、任务、测试用例等。根据WSAPI文档,如果想把附件关联到TestCaseResult,实际上需要用到的属性是“TestCaseResult”。之所以这样写,是因为TestCaseResult实际上是一个WorkspaceDomainObject,而不是Artifact。

下面是一个示例,展示如何创建一个新的TestCaseResult并添加一个附件。

#!/usr/bin/env python

#################################################################################################
#
# create_tcr_and_attachment.py -- Create a New TestCaseResult and attach a file to it
#
USAGE = """
Usage: py create_tcr_and_attachment.py <TestCaseFormatedID> <filename>
"""
#################################################################################################

import sys, os
import re
import string
import base64

from pyral import Rally, rallySettings

#################################################################################################

errout = sys.stderr.write

ATTACHMENT_ATTRIBUTES = ['oid', 'ObjectID', '_type', '_ref', '_CreatedAt', 'Name',
                         'CreationDate', 'Description', 
                         'Content', 'ContentType', 'Size', 
                         'Subscription', 
                         'Workspace',
                         'Artifact', 
                         'User'
                        ] 

ATTACHMENT_IMPORTANT_ATTRS = """
    Subscription   ref     (supplied at creation)
    Workspace      ref     (supplied at creation)

    Name           STRING      Required    (name of the file, like foo.txt or ThePlan.doc)
    User           ref to User Required   Settable  (User who added the object)

    Content        ref to AttachmentContent
    Size           INTEGER     Required
    ContentType    STRING      Required


    Artifact       ref to Artifact            (optional field)

    Description    TEXT        Optional

"""

#################################################################################################

def main(args):
    options = [opt for opt in args if opt.startswith('--')]
    args    = [arg for arg in args if arg not in options]
    server = "rally1.rallydev.com"
    user = "user@company.com"
    password = "topsecret"
    workspace = "My Workspace"
    project = "My Project"
    print " ".join(["|%s|" % item for item in [server, user, '********', workspace, project]])
    rally = Rally(server, user, password, workspace=workspace, version="1.43")  # specify the Rally server and credentials
    rally.enableLogging('rally.hist.create_tcr_and_attachment') # name of file you want logging to go to

    if len(args) != 2:
        errout('ERROR: You must supply a Test Case FormattedID and an attachment file name')
        errout(USAGE)
        sys.exit(1)

    targetTCID, filename = args

    me = rally.getUserInfo(username=user).pop(0)
    print "%s user oid: %s" % (user, me.oid)

    target_project = rally.getProject()
    target_tc  = rally.get('TestCase', query='FormattedID = %s' % targetTCID, instance=True)    

    datestring = "2014-05-01"

    tcr_info = {
         "TestCase"     : target_tc.ref,
         "Build"        : "master-91321",
         "Date"         : datestring,
         "Verdict"      : "Pass",
         "Notes"        : "Honeycomb harvest project."
       }

    print "Creating Test Case Result ..."
    tcr = rally.put('TestCaseResult', tcr_info)
    print "Created  TCR: %s" % (tcr.oid)

    print "Creating AttachmentContent"

    if not os.path.exists(filename):
        raise Exception('Named attachment filename: %s not found' % filename)
    if not os.path.isfile(filename):
        raise Exception('Named attachment filename: %s is not a regular file' % filename)

    attachment_file_name = os.path.basename(filename)
    attachment_file_size = os.path.getsize(filename)
    if attachment_file_size > 5000000:
        raise Exception('Attachment file size too large, unable to attach to Rally Artifact')

    contents = ''
    with open(filename, 'r') as af:
        contents = base64.encodestring(af.read())

    # create an AttachmentContent item
    ac = rally.create('AttachmentContent', {"Content" : contents}, project=None)
    if not ac:
        raise RallyRESTAPIError('Unable to create AttachmentContent for %s' % attachment_file_name)

    attachment_info = { "Name"              :  attachment_file_name,
                        "Content"           :  ac.ref,       # ref to AttachmentContent
                        "ContentType"       :  "image/jpeg",    
                        "Size"              :  attachment_file_size, # must be size before encoding!!
                        "User"              :  'user/%s' % me.oid,
                        "TestCaseResult"    :  tcr.ref
                      }

    # and finally, create the Attachment
    attachment = rally.create('Attachment', attachment_info, project=None)
    if not attachment:
        raise RallyRESTAPIError('Unable to create Attachment for %s' % attachment_file_name)    


#################################################################################################
#################################################################################################

if __name__ == '__main__':
    main(sys.argv[1:])

撰写回答