From 41574554cbd874da2aecde27afa1d0a98e78d064 Mon Sep 17 00:00:00 2001 From: Philip Blyth Date: Thu, 19 Mar 2015 12:19:48 -0400 Subject: [PATCH] For #28441: FIXED version checks, better API flag tests --- shotgun_api3/shotgun.py | 45 ++++----- tests/base.py | 24 ++++- tests/test_flags.py | 199 +++++++++++++++++++++++++++++++--------- 3 files changed, 199 insertions(+), 69 deletions(-) diff --git a/shotgun_api3/shotgun.py b/shotgun_api3/shotgun.py index a21eb907..2fdcbcc5 100755 --- a/shotgun_api3/shotgun.py +++ b/shotgun_api3/shotgun.py @@ -137,7 +137,7 @@ def __init__(self, host, meta): self.ensure_json_supported() - def _ensure_support(self, feature): + def _ensure_support(self, feature, raise_hell=True): """Checks the server version supports a given feature, raises an exception if it does not. @@ -147,10 +147,11 @@ def _ensure_support(self, feature): """ if not self.version or self.version < feature['version']: - raise ShotgunError( - "%s requires server version %s or higher, "\ - "server is %s" % (feature['label'], _version_str(feature['version']), _version_str(self.version)) - ) + if raise_hell: + raise ShotgunError( + "%s requires server version %s or higher, "\ + "server is %s" % (feature['label'], _version_str(feature['version']), _version_str(self.version)) + ) return False else: return True @@ -163,19 +164,23 @@ def ensure_json_supported(self): 'label': 'JSON API' }) - def ensure_include_archived_projects(self): + def ensure_include_archived_projects(self, value=True): """Wrapper for ensure_support""" + # This defaults to True on the server + # So we only need to raise a version error if it's False return self._ensure_support({ 'version': (5, 3, 14), 'label': 'include_archived_projects parameter' - }) + }, (value == False)) - def ensure_include_template_projects(self): + def ensure_include_template_projects(self, value=False): """Wrapper for ensure_support""" + # This defaults to False on the server + # So we only need to raise a version error if it's True return self._ensure_support({ 'version': (6, 0, 0), 'label': 'include_template_projects parameter' - }) + }, (value == True)) def __str__(self): @@ -665,19 +670,11 @@ def _construct_flag_parameters(self, include_archived_projects, include_template_projects): - if not include_archived_projects: - # This defaults to True on the server (no argument is sent) - # So we only need to check the server version if it's False - self.server_caps.ensure_include_archived_projects() - # Only pass it if it's False - params["include_archived_projects"] = False + if self.server_caps.ensure_include_archived_projects(include_archived_projects): + params["include_archived_projects"] = include_archived_projects - if include_template_projects: - # This defaults to False on the server (no argument is sent) - # So we only need to check the server version if it's True - self.server_caps.ensure_include_template_projects() - # Only pass it if it's True - params["include_template_projects"] = True + if self.server_caps.ensure_include_template_projects(include_template_projects): + params["include_template_projects"] = include_template_projects return params @@ -1644,6 +1641,7 @@ def _call_rpc(self, method, params, include_auth_params=True, first=False): """ + log_time = datetime.datetime.now() LOG.debug("Starting rpc call to %s with params %s" % ( method, params)) @@ -1658,7 +1656,10 @@ def _call_rpc(self, method, params, include_auth_params=True, first=False): } http_status, resp_headers, body = self._make_call("POST", self.config.api_path, encoded_payload, req_headers) - LOG.debug("Completed rpc call to %s" % (method)) + + log_time = datetime.datetime.now() - log_time + LOG.debug("Completed rpc call to %s in %s" % (method, str(log_time))) + try: self._parse_http_status(http_status) except ProtocolError, e: diff --git a/tests/base.py b/tests/base.py index 201844b4..39e0ebc7 100644 --- a/tests/base.py +++ b/tests/base.py @@ -3,13 +3,14 @@ import unittest from ConfigParser import ConfigParser - import mock import shotgun_api3 as api from shotgun_api3.shotgun import json from shotgun_api3.shotgun import ServerCapabilities +import logging + CONFIG_PATH = 'tests/config' class TestBase(unittest.TestCase): @@ -35,6 +36,10 @@ def __init__(self, *args, **kws): def setUp(self, auth_mode='ApiUser'): + + self.LOG = logging.getLogger("shotgun_api3") + self.LOG.setLevel(logging.WARN) + self.config = SgTestConfig() self.config.read_config(CONFIG_PATH) self.human_login = self.config.human_login @@ -185,10 +190,14 @@ def _setup_mock_data(self): class LiveTestBase(TestBase): '''Test base for tests relying on connection to server.''' + def setUp(self, auth_mode='ApiUser'): super(LiveTestBase, self).setUp(auth_mode) + self.sg_version = self.sg.info()['version'][:3] + self._setup_db(self.config) + if self.sg.server_caps.version and \ self.sg.server_caps.version >= (3, 3, 0) and \ (self.sg.server_caps.host.startswith('0.0.0.0') or \ @@ -197,17 +206,22 @@ def setUp(self, auth_mode='ApiUser'): else: self.server_address = self.sg.server_caps.host + def _setup_db(self, config): data = {'name':self.config.project_name} self.project = _find_or_create_entity(self.sg, 'Project', data) + self.template_project = _find_or_create_entity(self.sg, 'Project', { + 'name': 'Template Project', + 'is_template': True + }) + data = {'name':self.config.human_name, 'login':self.config.human_login, 'password_proxy':self.config.human_password} if self.sg_version >= (3, 0, 0): data['locked_until'] = None - self.human_user = _find_or_create_entity(self.sg, 'HumanUser', data) data = {'code':self.config.asset_code, @@ -256,6 +270,12 @@ def _setup_db(self, config): keys = ['title','project', 'sg_priority'] self.ticket = _find_or_create_entity(self.sg, 'Ticket', data, keys) + data = {'project': self.template_project, + 'title': self.config.ticket_title, + 'sg_priority': '1'} + keys = ['title', 'project', 'sg_priority'] + self.template_ticket = _find_or_create_entity(self.sg, 'Ticket', data, keys) + keys = ['code'] data = {'code':'api wrapper test storage', 'mac_path':'nowhere', diff --git a/tests/test_flags.py b/tests/test_flags.py index 403a05e1..38f320be 100644 --- a/tests/test_flags.py +++ b/tests/test_flags.py @@ -1,21 +1,23 @@ """Test using the Shotgun API flags.""" import shotgun_api3 +from shotgun_api3 import * from shotgun_api3.lib.httplib2 import Http import base +import logging + class TestFlags(base.LiveTestBase): + def setUp(self): super(TestFlags, self).setUp() + # We will need the created_at field for the shot fields = self.shot.keys()[:] fields.append('created_at') self.shot = self.sg.find_one('Shot', [['id', 'is', self.shot['id']]], fields) - # We will need the uuid field for our LocalStorage - fields = self.local_storage.keys()[:] - fields.append('uuid') - self.local_storage = self.sg.find_one('LocalStorage', [['id', 'is', self.local_storage['id']]], fields) + def test_summary_include_archived_projects(self): """Test summary with 'include_archived_projects'""" @@ -23,105 +25,212 @@ def test_summary_include_archived_projects(self): if self.sg.server_caps.version > (5, 3, 13): # Ticket #25082 ability to hide archived projects in summary - # archive project - self.sg.update('Project', self.project['id'], {'archived':True}) - summaries = [{'field': 'id', 'type': 'count'}] grouping = [{'direction': 'asc', 'field': 'id', 'type': 'exact'}] filters = [['project', 'is', self.project]] - # setting defaults to False, so we should get result + # archive project + self.sg.update('Project', self.project['id'], {'archived':True}) + + # should get no result result = self.sg.summarize('Shot', filters=filters, summary_fields=summaries, - grouping=grouping) - self.assertEqual(result['summaries']['id'], 1) + grouping=grouping, + include_archived_projects=False) + self.assertEquals(result['summaries']['id'], 0) - # should get no result + # should get result result = self.sg.summarize('Shot', filters=filters, summary_fields=summaries, grouping=grouping, - include_archived_projects=False) - self.assertEqual(result['summaries']['id'], 0) + include_archived_projects=True) + self.assertEquals(result['summaries']['id'], 1) + + # setting defaults to True, should get result + result = self.sg.summarize('Shot', + filters=filters, + summary_fields=summaries, + grouping=grouping) + self.assertEquals(result['summaries']['id'], 1) # reset project self.sg.update('Project', self.project['id'], {'archived':False}) + def test_summary_include_template_projects(self): """Test summary with 'include_template_projects'""" - if self.sg.server_caps.version > (6, 0, 0): - # Ticket #28441 + # Ticket #28441 - # set as template project - self.sg.update('Project', self.project['id'], {'template':True}) + self.LOG.setLevel(logging.DEBUG) - summaries = [{'field': 'id', 'type': 'count'}] - grouping = [{'direction': 'asc', 'field': 'id', 'type': 'exact'}] - filters = [['project', 'is', self.project]] + summaries = [{'field': 'id', 'type': 'count'}] + grouping = [{'direction': 'asc', 'field': 'id', 'type': 'exact'}] + filters = [['project', 'is', self.project]] - # setting defaults to False, so we should get no result + # control + result = self.sg.summarize('Shot', + filters=filters, + summary_fields=summaries, + grouping=grouping) + self.assertEquals(result['summaries']['id'], 1) + + # backwards-compatibility + if self.sg.server_caps.version < (6, 0, 0): + + # flag should not be passed, should get result + self.assertRaises(ShotgunError, self.sg.summarize, 'Shot', + filters=filters, + summary_fields=summaries, + grouping=grouping, + include_template_projects=True) + + # test new features + if self.sg.server_caps.version >= (6, 0, 0): + # set as template project + self.sg.update('Project', self.project['id'], {'is_template':True}) + + # should get result result = self.sg.summarize('Shot', filters=filters, summary_fields=summaries, - grouping=grouping) - self.assertEqual(result['summaries']['id'], 0) + grouping=grouping, + include_template_projects=True) + self.assertEquals(result['summaries']['id'], 1) - # should get result + # should get no result result = self.sg.summarize('Shot', filters=filters, summary_fields=summaries, grouping=grouping, include_template_projects=False) - self.assertEqual(result['summaries']['id'], 1) + self.assertEquals(result['summaries']['id'], 0) + + # setting defaults to False, should get no result + result = self.sg.summarize('Shot', + filters=filters, + summary_fields=summaries, + grouping=grouping) + self.assertEquals(result['summaries']['id'], 0) # reset project - self.sg.update('Project', self.project['id'], {'template':False}) + self.sg.update('Project', self.project['id'], {'is_template':False}) + + self.LOG.setLevel(logging.WARN) + def test_include_archived_projects(self): """Test find with 'include_archived_projects'""" + # Ticket #25082 + + filters = [['id', 'is', self.shot['id']]] + if self.sg.server_caps.version > (5, 3, 13): - # Ticket #25082 - result = self.sg.find_one('Shot', [['id','is',self.shot['id']]]) - self.assertEquals(self.shot['id'], result['id']) + # control + result = self.sg.find_one('Shot', + filters=filters) + self.assertEquals(result['id'], self.shot['id']) # archive project self.sg.update('Project', self.project['id'], {'archived':True}) - # setting defaults to True, so we should get result - result = self.sg.find_one('Shot', [['id','is',self.shot['id']]]) - self.assertEquals(self.shot['id'], result['id']) - # should get no result - result = self.sg.find_one('Shot', [['id','is',self.shot['id']]], include_archived_projects=False) - self.assertEquals(None, result) + result = self.sg.find_one('Shot', + filters=filters, + include_archived_projects=False) + self.assertEquals(result, None) + + # should get result + result = self.sg.find_one('Shot', + filters=filters, + include_archived_projects=True) + self.assertEquals(result['id'], self.shot['id']) + + # setting defaults to True, should get result + result = self.sg.find_one('Shot', + filters=filters) + self.assertEquals(result['id'], self.shot['id']) # reset project self.sg.update('Project', self.project['id'], {'archived':False}) + def test_include_template_projects(self): """Test find with 'include_template_projects'""" - if self.sg.server_caps.version > (6, 0, 0): - # Ticket #28441 + # Ticket #28441 + + self.LOG.setLevel(logging.DEBUG) + + filters = [['id', 'is', self.shot['id']]] + + # control + result = self.sg.find_one('Shot', + filters=filters) + self.assertEquals(result['id'], self.shot['id']) + + # backwards-compatibility + if self.sg.server_caps.version < (6, 0, 0): - result = self.sg.find_one('Shot', [['id','is',self.shot['id']]]) - self.assertEquals(self.shot['id'], result['id']) + self.assertRaises(ShotgunError, self.sg.find_one, 'Shot', + filters=filters, + include_template_projects=True) + + # test new features + if self.sg.server_caps.version >= (6, 0, 0): # set as template project self.sg.update('Project', self.project['id'], {'is_template':True}) - # setting defaults to False, so we should not get result - result = self.sg.find_one('Shot', [['id','is',self.shot['id']]]) - self.assertEquals(None, result) - # should get result - result = self.sg.find_one('Shot', [['id','is',self.shot['id']]], include_template_projects=True) - self.assertEquals(self.shot['id'], result['id']) + result = self.sg.find_one('Shot', + filters=filters, + include_template_projects=True) + self.assertEquals(result['id'], self.shot['id']) + + # should get no result + result = self.sg.find_one('Shot', + filters=filters, + include_template_projects=False) + self.assertEquals(result, None) + + # setting defaults to False, should get no result + result = self.sg.find_one('Shot', + filters=filters) + self.assertEquals(result, None) # reset project self.sg.update('Project', self.project['id'], {'is_template':False}) + self.LOG.setLevel(logging.WARN) + + + def test_find_template_project(self): + """Test find the 'Template Project'""" + + # Ticket #28441 + + if self.sg.server_caps.version >= (6, 0, 0): + + # find by name + result = self.sg.find_one('Project', [['name', 'is', self.template_project['name']]]) + self.assertEquals(result['id'], self.template_project['id']) + + # find by ID + result = self.sg.find_one('Project', [['id', 'is', self.template_project['id']]]) + self.assertEquals(result['id'], self.template_project['id']) + + # find attached entity + result = self.sg.find_one( + 'Ticket', + [ + ['id', 'is', self.template_ticket['id']], + ['project.Project.name', 'is', 'Template Project'], + ['project.Project.layout_project', 'is', None] + ] + ) + self.assertEquals(result['id'], self.template_ticket['id'])