Hello community,

here is the log from the commit of package python-rt for openSUSE:Factory 
checked in at 2019-12-04 13:53:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-rt (Old)
 and      /work/SRC/openSUSE:Factory/.python-rt.new.4691 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-rt"

Wed Dec  4 13:53:16 2019 rev:4 rq:753272 version:1.0.12

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-rt/python-rt.changes      2018-12-24 
11:43:35.265335321 +0100
+++ /work/SRC/openSUSE:Factory/.python-rt.new.4691/python-rt.changes    
2019-12-04 14:20:09.982427327 +0100
@@ -1,0 +2,13 @@
+Tue Nov 26 14:36:32 UTC 2019 - Sebastian Wagner <[email protected]>
+
+- update to version 1.0.12:
+ - Travis CI Docker tests
+ - RT 4.4 fixes
+ - Support multiline CF values in create_ticket and edit_ticket.
+ - Fix support for custom field names containing colons
+ - In search(), replace splitlines() with lines array split on \n.
+ - Add debug_mode flag for response logging
+ - Add platform independent url joining / Allow testing on Windows
+ - Add numerical_id to get_ticket result
+
+-------------------------------------------------------------------

Old:
----
  rt-1.0.11.tar.gz

New:
----
  rt-1.0.12.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-rt.spec ++++++
--- /var/tmp/diff_new_pack.eLAuX1/_old  2019-12-04 14:20:10.514427775 +0100
+++ /var/tmp/diff_new_pack.eLAuX1/_new  2019-12-04 14:20:10.518427778 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-rt
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,12 +19,12 @@
 # Tests require internet connection
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-rt
-Version:        1.0.11
+Version:        1.0.12
 Release:        0
 Summary:        Python interface to Request Tracker API
 License:        GPL-3.0-only
 Group:          Development/Languages/Python
-Url:            https://github.com/CZ-NIC/python-rt
+URL:            https://github.com/CZ-NIC/python-rt
 Source:         
https://files.pythonhosted.org/packages/source/r/rt/rt-%{version}.tar.gz
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes

++++++ rt-1.0.11.tar.gz -> rt-1.0.12.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rt-1.0.11/CHANGES new/rt-1.0.12/CHANGES
--- old/rt-1.0.11/CHANGES       2018-07-16 14:39:22.000000000 +0200
+++ new/rt-1.0.12/CHANGES       2019-10-25 15:05:33.000000000 +0200
@@ -1,7 +1,20 @@
-v1.0.11, unreleased
+v1.0.12, 2019-10-25
+- Travis CI Docker tests
+- RT 4.4 fixes
+- Support multiline CF values in create_ticket and edit_ticket.
+- Fix support for custom field names containing colons
+- In search(), replace splitlines() with lines array split on \n.
+- Add debug_mode flag for response logging
+- Add platform independent url joining / Allow testing on Windows
+- Add numerical_id to get_ticket result
+
+v1.0.11, 2018-07-16
 - Added parameter to set the content type in reply() and comment() (#12).
 - Added parameter Format to search() (#17).
 - Tests: Update to new demo instance, fixing tests.
+- Tests: Disable tests in Travis, the existing test instance closed the REST 
interface (#28).
+- Fix support for custom field names containing colons (#37).
+- Fix support for custom field values containing newlines (#11).
 
 v1.0.10, 2017-02-22
 - PEP8 fixes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rt-1.0.11/PKG-INFO new/rt-1.0.12/PKG-INFO
--- old/rt-1.0.11/PKG-INFO      2018-07-16 14:51:02.000000000 +0200
+++ new/rt-1.0.12/PKG-INFO      2019-10-25 15:06:55.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: rt
-Version: 1.0.11
+Version: 1.0.12
 Summary: Python interface to Request Tracker API
 Home-page: https://github.com/CZ-NIC/python-rt
 Author: Jiri Machalek
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rt-1.0.11/rt.egg-info/PKG-INFO 
new/rt-1.0.12/rt.egg-info/PKG-INFO
--- old/rt-1.0.11/rt.egg-info/PKG-INFO  2018-07-16 14:51:02.000000000 +0200
+++ new/rt-1.0.12/rt.egg-info/PKG-INFO  2019-10-25 15:06:55.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: rt
-Version: 1.0.11
+Version: 1.0.12
 Summary: Python interface to Request Tracker API
 Home-page: https://github.com/CZ-NIC/python-rt
 Author: Jiri Machalek
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rt-1.0.11/rt.py new/rt-1.0.12/rt.py
--- old/rt-1.0.11/rt.py 2018-07-16 14:47:27.000000000 +0200
+++ new/rt-1.0.12/rt.py 2019-10-25 14:58:58.000000000 +0200
@@ -27,13 +27,21 @@
 
 import os
 import re
+import sys
+
 import warnings
+import datetime
 
 import requests
 from requests.auth import HTTPBasicAuth, HTTPDigestAuth
 from six import iteritems
 from six.moves import range
 
+if sys.version_info.major == 2:
+    from urlparse import urljoin
+else:
+    from urllib.parse import urljoin
+
 __license__ = """ Copyright (C) 2012 CZ.NIC, z.s.p.o.
     Copyright (c) 2015 Genome Research Ltd.
 
@@ -61,6 +69,9 @@
 
 ALL_QUEUES = object()
 
+DEBUG_MODE = False
+""" Flag to enable debug mode for all Rt instances """
+
 
 class RtError(Exception):
     """ Super class of all Rt Errors """
@@ -160,18 +171,18 @@
         'deleted_link_pattern': re.compile('.* Deleted link '),
         'merge_successful_pattern': re.compile('^# Merge completed.|^Merge 
Successful$'),
         'bad_request_pattern': re.compile('.* 400 Bad Request$'),
-        'user_pattern': re.compile('^# User ([0-9]*) (?:updated|created)\.$'),
-        'queue_pattern': re.compile('^# Queue (\w*) (?:updated|created)\.$'),
-        'ticket_created_pattern': re.compile('^# Ticket ([0-9]+) created\.$'),
-        'does_not_exist_pattern': re.compile('^# (?:Queue|User|Ticket) \w* 
does not exist\.$'),
-        'does_not_exist_pattern_bytes': re.compile(b'^# (?:Queue|User|Ticket) 
\w* does not exist\.$'),
-        'not_related_pattern': re.compile('^# Transaction \d+ is not related 
to Ticket \d+'),
-        'invalid_attachment_pattern_bytes': re.compile(b'^# Invalid attachment 
id: \d+$'),
+        'user_pattern': re.compile(r'^# User ([0-9]*) (?:updated|created)\.$'),
+        'queue_pattern': re.compile(r'^# Queue (\w*) (?:updated|created)\.$'),
+        'ticket_created_pattern': re.compile(r'^# Ticket ([0-9]+) created\.$'),
+        'does_not_exist_pattern': re.compile(r'^# (?:Queue|User|Ticket) \w* 
does not exist\.$'),
+        'does_not_exist_pattern_bytes': re.compile(br'^# (?:Queue|User|Ticket) 
\w* does not exist\.$'),
+        'not_related_pattern': re.compile(r'^# Transaction \d+ is not related 
to Ticket \d+'),
+        'invalid_attachment_pattern_bytes': re.compile(br'^# Invalid 
attachment id: \d+$'),
     }
 
     def __init__(self, url, default_login=None, default_password=None, 
proxy=None,
                  default_queue=DEFAULT_QUEUE, basic_auth=None, 
digest_auth=None,
-                 skip_login=False, verify_cert=True):
+                 skip_login=False, verify_cert=True, debug_mode=False):
         """ API initialization.
 
         :keyword url: Base URL for Request Tracker API.
@@ -188,7 +199,11 @@
                              need to call login, because it is managed by
                              requests library instantly.
         """
+        # ensure trailing slash
+        if not url.endswith("/"):
+            url = url + "/"
         self.url = url
+        self.debug_mode = debug_mode
         self.default_login = default_login
         self.default_password = default_password
         self.default_queue = default_queue
@@ -236,7 +251,7 @@
         try:
             if (not self.login_result) and (not without_login):
                 raise AuthorizationError('First login by calling method 
`login`.')
-            url = str(os.path.join(self.url, selector))
+            url = str(urljoin(self.url, selector))
             if not files:
                 if post_data:
                     response = self.session.post(url, data=post_data)
@@ -247,6 +262,17 @@
                 for i, file_pair in enumerate(files):
                     files_data['attachment_{:d}'.format(i + 1)] = file_pair
                 response = self.session.post(url, data=post_data, 
files=files_data)
+            if self.debug_mode or DEBUG_MODE:
+                method = "GET"
+                if post_data or files:
+                    method = "POST"
+                print("### {0}".format(datetime.datetime.now().isoformat()))
+                print("Request URL: {0}".format(url))
+                print("Request method: {0}".format(method))
+                print("Respone status code: {0}".format(response.status_code))
+                print("Response content:")
+                print(response.content.decode())
+
             if response.status_code == 401:
                 raise AuthorizationError('Server could not verify that you are 
authorized to access the requested document.')
             if response.status_code != 200:
@@ -281,7 +307,7 @@
         """
         try:
             return int(msg.split('\n')[0].split(' ')[1])
-        except:
+        except Exception:
             return None
 
     def __check_response(self, msg):
@@ -496,7 +522,7 @@
                     raise UnexpectedMessageFormat('Missing line starting with 
`Requestors:`.')
                 for i in range(req_id):
                     if ': ' in msg[i]:
-                        header, content = msg[i].split(': ', 1)
+                        header, content = self.split_header(msg[i])
                         pairs[header.strip()] = content.strip()
                 requestors = [msg[req_id][12:]]
                 req_id += 1
@@ -506,7 +532,7 @@
                 pairs['Requestors'] = self.__normalize_list(requestors)
                 for i in range(req_id, len(msg)):
                     if ': ' in msg[i]:
-                        header, content = msg[i].split(': ', 1)
+                        header, content = self.split_header(msg[i])
                         pairs[header.strip()] = content.strip()
                 if pairs:
                     items.append(pairs)
@@ -515,20 +541,30 @@
                     pairs['Cc'] = self.__normalize_list(pairs['Cc'])
                 if 'AdminCc' in pairs:
                     pairs['AdminCc'] = self.__normalize_list(pairs['AdminCc'])
+
+                if 'id' not in pairs and not 
pairs['id'].startswitch('ticket/'):
+                    raise UnexpectedMessageFormat('Response from RT didn\'t 
contain a valid ticket_id')
+                else:
+                    pairs['numerical_id'] = pairs['id'].split('ticket/')[1]
+
             return items
         elif Format == 's':
             items = []
-            msgs = msg.splitlines()[2:]
+            msgs = lines[2:]
             for msg in msgs:
-                ticket_id, subject = msg.split(': ', 1)
-                items.append({'id': 'ticket/' + ticket_id, 'Subject': subject})
+                if "" == msg:  # Ignore blank line at the end
+                    continue
+                ticket_id, subject = self.split_header(msg)
+                items.append({'id': 'ticket/' + ticket_id, 'numerical_id': 
ticket_id, 'Subject': subject})
             return items
         elif Format == 'i':
             items = []
-            msgs = msg.splitlines()[2:]
+            msgs = lines[2:]
             for msg in msgs:
+                if "" == msg:  # Ignore blank line at the end
+                    continue
                 _, ticket_id = msg.split('/', 1)
-                items.append({'id': 'ticket/' + ticket_id})
+                items.append({'id': 'ticket/' + ticket_id, 'numerical_id': 
ticket_id})
             return items
 
     def get_ticket(self, ticket_id):
@@ -540,6 +576,7 @@
                   *ticket_id* or None if ticket does not exist. List of keys:
 
                       * id
+                      * numerical_id
                       * Queue
                       * Owner
                       * Creator
@@ -575,7 +612,7 @@
                 raise UnexpectedMessageFormat('Missing line starting with 
`Requestors:`.')
             for i in range(req_id):
                 if ': ' in msg[i]:
-                    header, content = msg[i].split(': ', 1)
+                    header, content = self.split_header(msg[i])
                     pairs[header.strip()] = content.strip()
             requestors = [msg[req_id][12:]]
             req_id += 1
@@ -585,7 +622,7 @@
             pairs['Requestors'] = self.__normalize_list(requestors)
             for i in range(req_id, len(msg)):
                 if ': ' in msg[i]:
-                    header, content = msg[i].split(': ', 1)
+                    header, content = self.split_header(msg[i])
                     pairs[header.strip()] = content.strip()
 
             if 'Cc' in pairs:
@@ -593,10 +630,36 @@
             if 'AdminCc' in pairs:
                 pairs['AdminCc'] = self.__normalize_list(pairs['AdminCc'])
 
+            if 'id' not in pairs and not pairs['id'].startswitch('ticket/'):
+                raise UnexpectedMessageFormat('Response from RT didn\'t 
contain a valid ticket_id')
+            else:
+                pairs['numerical_id'] = pairs['id'].split('ticket/')[1]
+
             return pairs
         else:
             raise UnexpectedMessageFormat('Received status code is {:d} 
instead of 200.'.format(status_code))
 
+    def __ticket_post_data(self, data_source):
+        """Convert a dictionary of RT ticket data into a REST POST data string.
+
+        :param data_source: Dictionary with ticket fields and values.
+
+        :returns: Equivalent string to POST to the RT REST interface.
+        """
+        post_data = []
+        for key in data_source:
+            if key.startswith('CF_'):
+                rt_key = 'CF.{{{}}}'.format(key[3:])
+            else:
+                rt_key = key
+            value = data_source[key]
+            if isinstance(value, (list, tuple)):
+                value = ', '.join(value)
+            value_lines = iter(value.splitlines())
+            post_data.append('{}: {}'.format(rt_key, next(value_lines, '')))
+            post_data.extend(' ' + line for line in value_lines)
+        return '\n'.join(post_data)
+
     def create_ticket(self, Queue=None, files=[], **kwargs):
         """ Create new ticket and set given parameters.
 
@@ -639,14 +702,9 @@
         :returns: ID of new ticket or ``-1``, if creating failed
         """
 
-        post_data = 'id: ticket/new\nQueue: {}\n'.format(Queue or 
self.default_queue, )
-        for key in kwargs:
-            if key[:4] == 'Text':
-                post_data += "{}: {}\n".format(key, re.sub(r'\n', r'\n      ', 
kwargs[key]))
-            elif key[:3] == 'CF_':
-                post_data += "CF.{{{}}}: {}\n".format(key[3:], kwargs[key])
-            else:
-                post_data += "{}: {}\n".format(key, kwargs[key])
+        kwargs['id'] = 'ticket/new'
+        kwargs['Queue'] = Queue or self.default_queue
+        post_data = self.__ticket_post_data(kwargs)
         for file_info in files:
             post_data += "\nAttachment: {}".format(file_info[0], )
         msg = self.__request('ticket/new', post_data={'content': post_data}, 
files=files)
@@ -676,14 +734,7 @@
                       Ticket with given ID does not exist or unknown parameter
                       was set (in this case all other valid fields are changed)
         """
-        post_data = ''
-        for key, value in iteritems(kwargs):
-            if isinstance(value, (list, tuple)):
-                value = ", ".join(value)
-            if key[:3] != 'CF_':
-                post_data += "{}: {}\n".format(key, value)
-            else:
-                post_data += "CF.{{{}}}: {}\n".format(key[3:], value)
+        post_data = self.__ticket_post_data(kwargs)
         msg = self.__request('ticket/{}/edit'.format(str(ticket_id)), 
post_data={'content': post_data})
         state = msg.split('\n')[2]
         return self.RE_PATTERNS['update_pattern'].match(state) is not None
@@ -736,7 +787,7 @@
                                                Missing line starting with 
`Attachements:`.')
             for i in range(cont_id):
                 if ': ' in msg[i]:
-                    header, content = msg[i].split(': ', 1)
+                    header, content = self.split_header(msg[i])
                     pairs[header.strip()] = content.strip()
             content = msg[cont_id][9:]
             cont_id += 1
@@ -746,12 +797,12 @@
             pairs['Content'] = content
             for i in range(cont_id, atta_id):
                 if ': ' in msg[i]:
-                    header, content = msg[i].split(': ', 1)
+                    header, content = self.split_header(msg[i])
                     pairs[header.strip()] = content.strip()
             attachments = []
             for i in range(atta_id + 1, len(msg)):
                 if ': ' in msg[i]:
-                    header, content = msg[i].split(': ', 1)
+                    header, content = self.split_header(msg[i])
                     attachments.append((int(header),
                                         content.strip()))
             pairs['Attachments'] = attachments
@@ -976,8 +1027,7 @@
         msg = self.__request('ticket/{}/attachments/{}'.format(str(ticket_id), 
str(attachment_id)),
                              text_response=False)
         msg = msg.split(b'\n')
-        if (len(msg) > 2) and 
(self.RE_PATTERNS['invalid_attachment_pattern_bytes'].match(msg[2]) or 
self.RE_PATTERNS[
-            'does_not_exist_pattern_bytes'].match(msg[2])):
+        if (len(msg) > 2) and 
(self.RE_PATTERNS['invalid_attachment_pattern_bytes'].match(msg[2]) or 
self.RE_PATTERNS['does_not_exist_pattern_bytes'].match(msg[2])):
             return None
         msg = msg[2:]
         head_matching = [i for i, m in enumerate(msg) if 
self.RE_PATTERNS['headers_pattern_bytes'].match(m)]
@@ -1031,8 +1081,7 @@
                              (str(ticket_id), str(attachment_id)),
                              text_response=False)
         lines = msg.split(b'\n', 3)
-        if (len(lines) == 4) and 
(self.RE_PATTERNS['invalid_attachment_pattern_bytes'].match(lines[2]) or 
self.RE_PATTERNS[
-            'does_not_exist_pattern_bytes'].match(lines[2])):
+        if (len(lines) == 4) and 
(self.RE_PATTERNS['invalid_attachment_pattern_bytes'].match(lines[2]) or 
self.RE_PATTERNS['does_not_exist_pattern_bytes'].match(lines[2])):
             return None
         return msg[msg.find(b'\n') + 2:-3]
 
@@ -1272,7 +1321,7 @@
             i = 2
             while i < len(msg):
                 if ': ' in msg[i]:
-                    key, link = msg[i].split(': ', 1)
+                    key, link = self.split_header(msg[i])
                     links = [link.strip()]
                     j = i + 1
                     pad = len(key) + 2
@@ -1405,3 +1454,19 @@
         post_data = {'content': "Ticket: {}\nAction: 
untake".format(str(ticket_id))}
         msg = self.__request('ticket/{}/take'.format(str(ticket_id)), 
post_data=post_data)
         return self.__get_status_code(msg) == 200
+
+    @staticmethod
+    def split_header(line):
+        """ Split a header line into field name and field value.
+
+        Note that custom fields may contain colons inside the curly braces,
+        so we need a special test for them.
+
+        :param line: A message line to be split.
+
+        :returns: (Field name, field value) tuple.
+        """
+        match = re.match(r'^(CF\.\{.*?}): (.*)$', line)
+        if match:
+            return (match.group(1), match.group(2))
+        return line.split(': ', 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rt-1.0.11/setup.cfg new/rt-1.0.12/setup.cfg
--- old/rt-1.0.11/setup.cfg     2018-07-16 14:51:02.000000000 +0200
+++ new/rt-1.0.12/setup.cfg     2019-10-25 15:06:55.000000000 +0200
@@ -1,6 +1,10 @@
 [bdist_wheel]
 universal = 1
 
+[pycodestyle]
+filename = rt.py
+ignore = E501
+
 [egg_info]
 tag_build = 
 tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rt-1.0.11/setup.py new/rt-1.0.12/setup.py
--- old/rt-1.0.11/setup.py      2018-07-16 14:48:00.000000000 +0200
+++ new/rt-1.0.12/setup.py      2019-10-25 15:01:01.000000000 +0200
@@ -9,7 +9,7 @@
 README = open(os.path.join(here, 'README.rst')).read()
 
 setup(name='rt',
-      version='1.0.11',
+      version='1.0.12',
       description='Python interface to Request Tracker API',
       long_description=README,
       license='GNU General Public License (GPL)',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rt-1.0.11/test_rt.py new/rt-1.0.12/test_rt.py
--- old/rt-1.0.11/test_rt.py    2018-07-16 14:48:00.000000000 +0200
+++ new/rt-1.0.12/test_rt.py    2019-10-25 14:58:58.000000000 +0200
@@ -31,17 +31,14 @@
 
 
 class RtTestCase(unittest.TestCase):
+    rt.DEBUG_MODE = True
     RT_VALID_CREDENTIALS = {
         'RT4.4 stable': {
-            'url': 'http://demo.request-tracker.fr/REST/1.0',
-            'admin': {
-                'default_login': 'administrateur',
-                'default_password': 'administrateur',
-            },
+            'url': "http://localhost:8080/REST/1.0/";,
             'support': {
-                'default_login': 'support',
-                'default_password': 'support',
-            }
+                'default_login': 'root',
+                'default_password': 'password',
+            },
         },
         # HTTP timeout
         # 'RT4.6 dev': {
@@ -59,7 +56,7 @@
 
     RT_INVALID_CREDENTIALS = {
         'RT4.4 stable (bad credentials)': {
-            'url': 'http://demo.request-tracker.fr/REST/1.0',
+            'url': "http://localhost:8080/REST/1.0/";,
             'default_login': 'idontexist',
             'default_password': 'idonthavepassword',
         },
@@ -67,7 +64,7 @@
 
     RT_MISSING_CREDENTIALS = {
         'RT4.4 stable (missing credentials)': {
-            'url': 'http://demo.request-tracker.fr/REST/1.0',
+            'url': "http://localhost:8080/REST/1.0/";,
         },
     }
 
@@ -79,6 +76,14 @@
         },
     }
 
+    def _have_creds(*creds_seq):
+        return all(creds[name].get('url') for creds in creds_seq for name in 
creds)
+
+    @unittest.skipUnless(_have_creds(RT_VALID_CREDENTIALS,
+                                     RT_INVALID_CREDENTIALS,
+                                     RT_MISSING_CREDENTIALS,
+                                     RT_BAD_URL),
+                         "missing credentials required to run test")
     def test_login_and_logout(self):
         for name in self.RT_VALID_CREDENTIALS:
             tracker = rt.Rt(self.RT_VALID_CREDENTIALS[name]['url'], 
**self.RT_VALID_CREDENTIALS[name]['support'])
@@ -95,20 +100,12 @@
             tracker = rt.Rt(**params)
             self.assertRaises(rt.UnexpectedResponse, lambda: tracker.login())
 
-    def check_or_create_queue(self, name):
-        tracker = rt.Rt(self.RT_VALID_CREDENTIALS[name]['url'], 
**self.RT_VALID_CREDENTIALS[name]['admin'])
-        tracker.login()
-        queue = tracker.get_queue('General')
-        if 'Name' not in queue:
-            queue_id = tracker.create_queue('General')
-        tracker.logout()
-
+    @unittest.skipUnless(_have_creds(RT_VALID_CREDENTIALS),
+                         "missing credentials required to run test")
     def test_ticket_operations(self):
         ticket_subject = 'Testing issue ' + 
"".join([random.choice(string.ascii_letters) for i in range(15)])
         ticket_text = 'Lorem ipsum dolor sit amet, consectetur adipisicing 
elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
         for name in ('RT4.4 stable',):
-            self.check_or_create_queue(name)
-
             url = self.RT_VALID_CREDENTIALS[name]['url']
             default_login = 
self.RT_VALID_CREDENTIALS[name]['support']['default_login']
             default_password = 
self.RT_VALID_CREDENTIALS[name]['support']['default_password']
@@ -153,7 +150,7 @@
             # get_short_history
             short_hist = tracker.get_short_history(ticket_id)
             self.assertTrue(len(short_hist) > 0, 'Empty ticket short history.')
-            self.assertEqual(short_hist[0][1], 'Ticket created by support')
+            self.assertEqual(short_hist[0][1], 'Ticket created by %s' % 
default_login)
             # create 2nd ticket
             ticket2_subject = 'Testing issue ' + 
"".join([random.choice(string.ascii_letters) for i in range(15)])
             ticket2_id = tracker.create_ticket(Subject=ticket2_subject)
@@ -175,21 +172,22 @@
             # should provide a content type as RT 4.0 type guessing is broken 
(missing use statement for guess_media_type in REST.pm)
             self.assertTrue(tracker.reply(ticket_id, text=reply_text, 
files=[(attachment_name, attachment_content, 'text/plain')]),
                             'Reply to ticket returned False indicating error.')
-            at_ids = tracker.get_attachments_ids(ticket_id)
-            self.assertTrue(at_ids, 'Emply list with attachment ids, something 
went wrong.')
-            at_content = tracker.get_attachment_content(ticket_id, at_ids[-1])
-            self.assertEqual(at_content, attachment_content, 'Recorded 
attachment is not equal to the original file.')
             # attachments list
             at_list = tracker.get_attachments(ticket_id)
+            self.assertTrue(at_list, 'Empty list with attachment ids, 
something went wrong.')
             at_names = [at[1] for at in at_list]
             self.assertTrue(attachment_name in at_names, 'Attachment name is 
not in the list of attachments.')
+            # get the attachment and compare it's content
+            at_id = at_list[at_names.index(attachment_name)][0]
+            at_content = tracker.get_attachment_content(ticket_id,
+                                                        at_id)
+            self.assertEqual(at_content, attachment_content, 'Recorded 
attachment is not equal to the original file.')
             # merge tickets
             self.assertTrue(tracker.merge_ticket(ticket2_id, ticket_id), 
'Merging tickets failed.')
             # delete ticket
             self.assertTrue(tracker.edit_ticket(ticket_id, Status='deleted'), 
'Ticket delete failed.')
             # get user
-            self.assertEqual(tracker.get_user(default_login)['EmailAddress'], 
default_login + '@no.mail',
-                             'Bad user email received.')
+            self.assertIn('@', tracker.get_user(default_login)['EmailAddress'])
 
 
 if __name__ == '__main__':


Reply via email to