问题是pyral 的 restapi的 addAttachment 方法将 ref 设置为 Attachment 对象的“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 继承的对象,即 Stories、Defects、Tasks、TestCases 等。如WSAPI Docs中所见,要将Attachment 关联到 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:])