def test_positive_delete_filter_from_role(self): """@Test: Delete the filter to remove permissions from a role. @Feature: Role and Permissions @Assert: Filter should be deleted """ role_name = orm.StringField(str_type=('alphanumeric',)).get_value() try: role_attrs = entities.Role(name=role_name).create() except factory.FactoryError as err: self.fail(err) # fail instead of error path = entities.Role(id=role_attrs['id']).path() # GET the role and verify it's name. response = client.get( path, auth=get_server_credentials(), verify=False, ).json() self.assertEqual(response['name'], role_name) # Get permissions that have a resource_type of ConfigTemplate. permissions = client.get( entities.Permission().path(), auth=get_server_credentials(), verify=False, data={'resource_type': 'Ptable'}, ).json()['results'] # Create a filter under a selected role with all permissions # of a selected resource_type. filter_attrs = entities.Filter( role=role_attrs['id'], permission=[permission['id'] for permission in permissions] ).create() filter_path = entities.Filter(id=filter_attrs['id']).path() client.get( filter_path, auth=get_server_credentials(), verify=False, ).json() # Delete the Filter, GET it, and assert that an HTTP 404 is returned. entities.Filter(id=filter_attrs['id']).delete() response = client.get( filter_path, auth=get_server_credentials(), verify=False, ) status_code = httplib.NOT_FOUND self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), )
def test_positive_create_role_with_permissions(self): """@Test: Create a filter to add permissions to a selected role @Feature: Role and Permissions @Assert: Filter should be created with all permissions of a selected resource_type """ role_name = orm.StringField(str_type=('alphanumeric',)).get_value() try: role_attrs = entities.Role(name=role_name).create() except factory.FactoryError as err: self.fail(err) # fail instead of error path = entities.Role(id=role_attrs['id']).path() # GET the role and verify it's name. response = client.get( path, auth=get_server_credentials(), verify=False, ).json() self.assertEqual(response['name'], role_name) # Get permissions that have a resource_type of ConfigTemplate. permissions = client.get( entities.Permission().path(), auth=get_server_credentials(), verify=False, data={'resource_type': 'ConfigTemplate'}, ).json()['results'] # Create a filter under a selected role with all permissions # of a selected resource_type. filter_attrs = entities.Filter( role=role_attrs['id'], permission=[permission['id'] for permission in permissions] ).create() # Get all permissions from created filter permission_names = client.get( entities.Filter(id=filter_attrs['id']).path(), auth=get_server_credentials(), verify=False, ).json()['permissions'] get_permissions = [permission_name['name'] for permission_name in permission_names] real_permissions = [permission['name'] for permission in permissions] self.assertListEqual(get_permissions, real_permissions)
def test_post_and_get(self, entity): """@Test Issue a POST request and GET the created entity. @Assert: The created entity has the correct attributes. """ if entity in BZ_1122267_ENTITIES and bz_bug_is_open(1122267): self.skipTest("Bugzilla bug 1122267 is open.""") # Generate some attributes and use them to create an entity. gen_attrs = entity().build() response = client.post( entity().path(), gen_attrs, auth=get_server_credentials(), verify=False, ) path = entity(id=response.json()['id']).path() self.assertIn( response.status_code, (httplib.OK, httplib.CREATED), path ) # Get the just-created entity and examine its attributes. real_attrs = client.get( path, auth=get_server_credentials(), verify=False, ).json() for key, value in gen_attrs.items(): self.assertIn(key, real_attrs.keys(), path) self.assertEqual( value, real_attrs[key], '{0} {1}'.format(key, path) )
def test_put_and_get(self, entity): """@Test: Issue a PUT request and GET the updated entity. @Assert: The updated entity has the correct attributes. """ path = entity(id=entity().create()['id']).path() # Generate some attributes and use them to update an entity. gen_attrs = entity().attributes() response = client.put( path, gen_attrs, auth=get_server_credentials(), verify=False, ) self.assertEqual(response.status_code, httplib.OK, path) # Get the just-updated entity and examine its attributes. real_attrs = client.get( path, auth=get_server_credentials(), verify=False, ).json() for key, value in gen_attrs.items(): self.assertIn(key, real_attrs.keys(), path) self.assertEqual( value, real_attrs[key], '{0} {1}'.format(key, path) )
def test_delete(self, entity): """@Test Create an entity, fetch it, DELETE it, and fetch it again. @Assert DELETE succeeds. HTTP 200, 202 or 204 is returned before deleting entity, and 404 is returned after deleting entity. """ attrs = entity().create() path = entity(id=attrs['id']).path() response = client.delete( path, auth=get_server_credentials(), verify=False, ) status_code = (httplib.NO_CONTENT, httplib.OK, httplib.ACCEPTED) self.assertIn( response.status_code, status_code, status_code_error(path, status_code, response), ) response = client.get( path, auth=get_server_credentials(), verify=False, ) status_code = httplib.NOT_FOUND self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), )
def read_json(self, auth=None): """Get information about the current entity. Send an HTTP GET request to ``self.path(which='this')``. Return the decoded JSON response. :param tuple auth: A ``(username, password)`` tuple used when accessing the API. If ``None``, the credentials provided by :func:`robottelo.common.helpers.get_server_credentials` are used. :return: The server's response, with all JSON decoded. :rtype: dict :raises: ``requests.exceptions.HTTPError`` if the response has an HTTP 4XX or 5XX status code. :raises: ``ValueError`` If the response JSON can not be decoded. """ if auth is None: auth = helpers.get_server_credentials() response = client.get( self.path(which='this'), auth=auth, verify=False, ) response.raise_for_status() return response.json()
def test_subscribe_system_to_cv(self): """@Test: Subscribe a system to a content view. @Feature: ContentView @Assert: It is possible to create a system and set its 'content_view_id' attribute. """ # Create an organization, lifecycle environment and content view. organization = entities.Organization().create() lifecycle_environment = entities.LifecycleEnvironment( organization=organization['id'] ).create() content_view = entities.ContentView( organization=organization['id'] ).create() # Publish the newly created content view. response = entities.ContentView(id=content_view['id']).publish() self.assertEqual( u'success', entities.ForemanTask(id=response['id']).poll()['result'] ) # Fetch and promote the newly published content view version. content_view_version = client.get( entities.ContentViewVersion().path(), auth=get_server_credentials(), data={u'content_view_id': content_view['id']}, verify=False, ).json()['results'][0] response = entities.ContentViewVersion( id=content_view_version['id'] ).promote(environment_id=lifecycle_environment['id']) self.assertEqual( u'success', entities.ForemanTask(id=response['id']).poll()['result'] ) # Create a system that is subscribed to the published and promoted # content view. Associating this system with the organization and # environment created above is not particularly important, but doing so # means a shorter test where fewer entities are created, as # System.organization and System.environment are required attributes. system = entities.System( content_view=content_view['id'], environment=lifecycle_environment['id'], organization=organization['id'], ).create() # See bugzilla bug #1122267. self.assertEqual( system['content_view_id'], # This is good. content_view['id'] ) self.assertEqual( system['environment']['id'], # This is bad. lifecycle_environment['id'] )
def test_positive_create_1(self, login): """ @Test Create a user providing the initial login name. @Assert: User is created and contains provided login name. @Feature: User """ path = entities.User().path() attrs = entities.User(login=login).build() response = client.post( path, attrs, auth=get_server_credentials(), verify=False, ) status_code = (httplib.OK, httplib.CREATED) self.assertIn( response.status_code, status_code, status_code_error(path, status_code, response), ) # Fetch the user real_attrs = client.get( entities.User(id=response.json()['id']).path(), auth=get_server_credentials(), verify=False, ).json() # Remove the ``password`` field from ``attrs`` since it isn't # returned by GET. attrs.pop('password') # Assert that keys and values match for key, value in attrs.items(): self.assertIn(key, real_attrs.keys()) self.assertEqual(value, real_attrs[key])
def get_packages(repository_id): """Return all packages belonging to repository ``repository_id``. :param int repository_id: A repository ID. :return: That repository's packages. :rtype: list :raises robottelo.api.utils.RepositoryPackagesException: If an error occurs while fetching the requested repository's packages. """ path = urljoin( helpers.get_server_url(), 'katello/api/v2/repositories/{0}/packages'.format(repository_id) ) response = client.get( path, auth=helpers.get_server_credentials(), verify=False, ).json() if 'errors' in response.keys(): raise RepositoryPackagesException( 'Error received after issuing GET to {0}. Error received: {1}' ''.format(path, response['errors']) ) return response['results']
def read(self, auth=None): """Return information about a foreman task. :return: Information about this foreman task. :rtype: dict :raises ReadException: If information about this foreman task could not be fetched. This could happen if, for example, the task does not exist or bad credentials are used. """ # FIXME: Need better error handling. If there's an authentication # error, the server will respond with JSON: # # {u'error': {u'text': u'Unable to authenticate user.'}} # # But what if the JSON response contains 'errors', or what if the # response cannot be converted to JSON at all? A utility function can # probably be created for this need. Perhaps # robottelo.api.utils.status_code_error() could be of use. After all, # most of that method is devoted to fetching an error message, and only # the last bit composes an error message. if auth is None: auth = get_server_credentials() response = client.get(self.path(), auth=auth, verify=False) if response.status_code is not 200: raise ReadException(response.text) if response.json() == {}: # FIXME: See bugzilla bug #1131702 raise ReadException( 'ForemanTask {0} does not exist.'.format(self.id) ) return response.json()
def test_update_max_content_hosts(self): """@Test: Create an activation key with ``max_content_hosts == 1``, then update that field with a string value. @Feature: ActivationKey @Assert: The update fails with an HTTP 422 return code. """ attrs = entities.ActivationKey(max_content_hosts=1).create() path = entities.ActivationKey(id=attrs['id']).path() new_attrs = attrs.copy() new_attrs['max_content_hosts'] = 'foo' response = client.put( path, new_attrs, auth=get_server_credentials(), verify=False, ) self.assertEqual( response.status_code, httplib.UNPROCESSABLE_ENTITY, status_code_error(path, httplib.UNPROCESSABLE_ENTITY, response), ) # Status code is OK. Was `max_content_hosts` changed, or is it still 1? response = client.get( path, auth=get_server_credentials(), verify=False, ).json() self.assertEqual(response['max_content_hosts'], 1)
def test_delete_and_get(self, entity): """@Test: Issue an HTTP DELETE request and GET the deleted entity. @Assert: An HTTP 404 is returned when fetching the missing entity. """ if entity is entities.ConfigTemplate and bz_bug_is_open(1096333): self.skipTest('Cannot delete config templates.') # Create an entity, then delete it. try: entity_n = entity(id=entity().create()['id']) except factory.FactoryError as err: self.fail(err) logger.info('test_delete_and_get path: {0}'.format(entity_n.path())) entity_n.delete() # Get the now non-existent entity. response = client.get( entity_n.path(), auth=get_server_credentials(), verify=False, ) status_code = httplib.NOT_FOUND self.assertEqual( status_code, response.status_code, status_code_error(entity_n.path(), status_code, response), )
def _search(self, entity, query, auth=None): """ Performs a GET ``api/v2/<entity>`` and specify the ``search`` parameter. :param robottelo.orm.Entity entity: A logical representation of a Foreman entity. :param string query: A ``search`` parameter. :param tuple auth: A ``tuple`` containing the credentials to be used for authentication when accessing the API. If ``None``, credentials are automatically read from :func:`robottelo.common.helpers.get_server_credentials`. :return: A ``dict`` representing a Foreman entity. :rtype: dict """ # Use the server credentials if None are provided if auth is None: auth = get_server_credentials() path = entity().path() response = client.get( path, auth=auth, data={u'search': query}, verify=False, ) response.raise_for_status() self.assertEqual( response.json()['search'], query, u"Could not find {0}.".format(query) ) return response.json()
def test_delete_and_get(self): """@Test: Issue an HTTP DELETE request and GET the deleted system. @Assert: An HTTP 404 is returned when fetching the missing system. """ try: attrs = System().create() except factory.FactoryError as err: self.fail(err) System(uuid=attrs['uuid']).delete() # Get the now non-existent system path = System(uuid=attrs['uuid']).path() response = client.get( path, auth=get_server_credentials(), verify=False, ) status_code = httplib.NOT_FOUND self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), )
def test_get_releases_status_code(self): """@Test: Get an activation key's releases. Check response format. @Assert: HTTP 200 is returned with an ``application/json`` content-type @Feature: ActivationKey """ try: attrs = entities.ActivationKey().create() except HTTPError as err: self.fail(err) path = entities.ActivationKey(id=attrs['id']).path(which='releases') response = client.get( path, auth=get_server_credentials(), verify=False, ) status_code = httplib.OK self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), ) self.assertIn('application/json', response.headers['content-type'])
def test_positive_create_3(self, name): """@Test: Create an activation key providing the initial name. @Assert: Activation key is created and contains provided name. @Feature: ActivationKey """ try: attrs = entities.ActivationKey(name=name).create() except FactoryError as err: self.fail(err) # Fetch the activation key real_attrs = client.get( entities.ActivationKey(id=attrs['id']).path(), auth=get_server_credentials(), verify=False, ).json() # Assert that initial values match self.assertEqual( real_attrs['name'], name, u"Initial attribute values mismatch: {0} != {1}".format( real_attrs['name'], name) )
def test_get_status_code(self, entity): """@Test: Create an entity and GET it. @Assert: HTTP 200 is returned with an ``application/json`` content-type """ if entity is entities.ActivationKey and bz_bug_is_open(1127335): self.skipTest("Bugzilla bug 1127335 is open.""") try: attrs = entity().create() except factory.FactoryError as err: self.fail(err) path = entity(id=attrs['id']).path() response = client.get( path, auth=get_server_credentials(), verify=False, ) status_code = httplib.OK self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), ) self.assertIn('application/json', response.headers['content-type'])
def test_post_and_get(self): """@Test Issue a POST request and GET the created system. @Assert: The created system has the correct attributes. """ # Generate some attributes and use them to create a system. gen_attrs = System().build() response = client.post( System().path(), gen_attrs, auth=get_server_credentials(), verify=False, ) path = System(uuid=response.json()['uuid']).path() self.assertIn( response.status_code, (httplib.OK, httplib.CREATED), path ) # Get the just-created system and examine its attributes. real_attrs = client.get( path, auth=get_server_credentials(), verify=False, ).json() for key, value in gen_attrs.items(): self.assertIn(key, real_attrs.keys(), path) self.assertEqual( value, real_attrs[key], '{0} {1}'.format(key, path) )
def test_subscribe_system_to_cv(self): """@Test: Subscribe a system to a content view. @Feature: ContentView @Assert: It is possible to create a system and set its 'content_view_id' attribute. """ # organization # ├── lifecycle environment # └── content view org = entities.Organization() org.id = org.create()['id'] lifecycle_env = entities.LifecycleEnvironment(organization=org.id) lifecycle_env.id = lifecycle_env.create()['id'] content_view = entities.ContentView(organization=org.id) content_view.id = content_view.create()['id'] # Publish the content view. self.assertEqual('success', content_view.publish()['result']) # Get the content view version's ID. response = client.get( entities.ContentViewVersion().path(), auth=get_server_credentials(), data={u'content_view_id': content_view.id}, verify=False, ) response.raise_for_status() results = response.json()['results'] self.assertEqual(len(results), 1) cv_version = entities.ContentViewVersion(id=results[0]['id']) # Promote the content view version. self.assertEqual( 'success', cv_version.promote(environment_id=lifecycle_env.id)['result'] ) # Create a system that is subscribed to the published and promoted # content view. Associating this system with the organization and # environment created above is not particularly important, but doing so # means a shorter test where fewer entities are created, as # System.organization and System.environment are required attributes. system_attrs = entities.System( content_view=content_view.id, environment=lifecycle_env.id, organization=org.id, ).create() # See BZ #1151240 self.assertEqual(system_attrs['content_view_id'], content_view.id) self.assertEqual(system_attrs['environment']['id'], lifecycle_env.id) self.assertEqual(system_attrs['organization_id'], org.id)
def test_positive_delete_1(self, name): """@Test: Create a role and delete it @Feature: Role @Assert: Role deletion should succeed """ try: role_attrs = entities.Role(name=name).create() except factory.FactoryError as err: self.fail(err) # fail instead of error path = entities.Role(id=role_attrs['id']).path() # GET the role and verify it's name. response = client.get( path, auth=get_server_credentials(), verify=False, ).json() self.assertEqual(response['name'], name) # Delete the role, GET it, and assert that an HTTP 404 is returned. response = client.delete( path, auth=get_server_credentials(), verify=False, ) # 404 should be returned for deleted role response = client.get( path, auth=get_server_credentials(), verify=False, ) status_code = httplib.NOT_FOUND self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), )
def test_get_with_no_args(self): """@Test: Issue an HTTP GET to the base content view filters path. @Feature: ContentViewFilter @Assert: An HTTP 400 or 422 response is received if a GET request is issued with no arguments specified. This test targets bugzilla bug #1102120. """ response = client.get(entities.ContentViewFilter().path(), auth=get_server_credentials(), verify=False) self.assertIn(response.status_code, (httplib.BAD_REQUEST, httplib.UNPROCESSABLE_ENTITY))
def _poll_task(task_id, poll_rate=None, timeout=None, auth=None): """Implement :meth:`robottelo.entities.ForemanTask.poll`. See :meth:`robottelo.entities.ForemanTask.poll` for a full description of how this method acts. Other methods may also call this method, such as :meth:`robottelo.orm.EntityDeleteMixin.delete`. This function has been placed in this module to keep the import tree sane. This function could also be placed in :mod:`robottelo.api.utils`. However, doing so precludes :mod:`robottelo.api.utils` from importing :mod:`robottelo.entities`, which may be desirable in the future. This function is private because only entity mixins should use this. :class:`robottelo.entities.ForemanTask` is, for obvious reasons, an exception. """ if poll_rate is None: poll_rate = TASK_POLL_RATE if timeout is None: timeout = TASK_TIMEOUT if auth is None: auth = helpers.get_server_credentials() # Implement the timeout. def raise_task_timeout(): """Raise a KeyboardInterrupt exception in the main thread.""" thread.interrupt_main() timer = threading.Timer(timeout, raise_task_timeout) # Poll until the task finishes. The timeout prevents an infinite loop. try: timer.start() path = '{0}/foreman_tasks/api/tasks/{1}'.format( helpers.get_server_url(), task_id ) while True: response = client.get(path, auth=auth, verify=False) response.raise_for_status() task_info = response.json() if task_info['state'] != 'running': return task_info time.sleep(poll_rate) except KeyboardInterrupt: # raise_task_timeout will raise a KeyboardInterrupt when the timeout # expires. Catch the exception and raise TaskTimeout raise TaskTimeout("Timed out polling task {0}".format(task_id)) finally: timer.cancel()
def test_get_unauthorized(self, entity): """@Test: GET an entity-dependent path without credentials. @Assert: HTTP 401 is returned """ path = entity().path() response = client.get(path, verify=False) status_code = httplib.UNAUTHORIZED self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), )
def _test_role_name(self, name): """Create a role with name ``name``.""" try: role_attrs = entities.Role(name=name).create() except factory.FactoryError as err: self.fail(err) # fail instead of error # Creation apparently succeeded. GET the role and verify it's name. response = client.get( entities.Role(id=role_attrs['id']).path(), auth=get_server_credentials(), verify=False, ).json() self.assertEqual(response['name'], name)
def test_get_status_code(self): """@Test: Create a system and GET it. @Assert: HTTP 200 is returned with an ``application/json`` content-type """ system = System(uuid=System().create_json()['uuid']) logger.debug('system uuid: {0}'.format(system.uuid)) response = client.get( system.path(), auth=get_server_credentials(), verify=False, ) self.assertEqual(httplib.OK, response.status_code) self.assertIn('application/json', response.headers['content-type'])
def test_get_status_code(self): """@Test: GET ``api/v2`` and examine the response. @Feature: API @Assert: HTTP 200 is returned with an ``application/json`` content-type """ response = client.get( self.path, auth=helpers.get_server_credentials(), verify=False, ) self.assertEqual(response.status_code, httplib.OK) self.assertIn('application/json', response.headers['content-type'])
def read_raw(self, auth=None): """Get information about the current entity. Send an HTTP GET request to :meth:`Entity.path`. Return the response. Do not check the response for any errors, such as an HTTP 4XX or 5XX status code. :param tuple auth: A ``(username, password)`` tuple used when accessing the API. If ``None``, the credentials provided by :func:`robottelo.common.helpers.get_server_credentials` are used. :return: A ``requests.response`` object. """ if auth is None: auth = helpers.get_server_credentials() return client.get(self.path(), auth=auth, verify=False)
def test_get_per_page(self): """@Test: GET ``api/v2/hosts`` and specify the ``per_page`` parameter. @Feature: Host @Assert: HTTP 200 is returned, along with per ``per_page`` value. """ per_page = FauxFactory.generate_integer(1, 1000) response = client.get( entities.Host().path(), auth=get_server_credentials(), params={'per_page': per_page}, verify=False, ) self.assertEqual(response.status_code, httplib.OK) self.assertEqual(response.json()['per_page'], per_page)
def test_get_search(self): """@Test: GET ``api/v2/hosts`` and specify the ``search`` parameter. @Feature: Host @Assert: HTTP 200 is returned, along with ``search`` term. """ query = gen_string('utf8', gen_integer(1, 100)) response = client.get( entities.Host().path(), auth=get_server_credentials(), data={u'search': query}, verify=False, ) self.assertEqual(response.status_code, httplib.OK) self.assertEqual(response.json()['search'], query)
def test_get_all(self): """@Test: Get ``katello/api/v2/gpg_keys`` and specify just an organization ID. @Feature: GPGKey @Assert: HTTP 200 is returned with an ``application/json`` content-type """ org_attrs = entities.Organization().create() response = client.get( entities.GPGKey().path(), auth=get_server_credentials(), data={u'organization_id': org_attrs['id']}, verify=False, ) self.assertEqual(response.status_code, httplib.OK) self.assertIn('application/json', response.headers['content-type'])