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 create_raw(self, auth=None, create_missing=True): """Create an entity. Generate values for required, unset fields by calling :meth:`create_missing`. Only do this if ``create_missing`` is true. Then make an HTTP POST call to ``self.path('base')``. Return the response received from the server. :param tuple auth: A ``(username, password)`` pair to use when communicating with the API. If ``None``, the credentials returned by :func:`robottelo.common.helpers.get_server_credentials` are used. :param bool create_missing: Should :meth:`create_missing` be called? In other words, should values be generated for required, empty fields? :return: A ``requests.response`` object. """ if auth is None: auth = helpers.get_server_credentials() if create_missing: self.create_missing(auth) return client.post( self.path('base'), self.create_payload(), auth=auth, verify=False, )
def test_post_hash(self): """@Test: Do not wrap API calls in an extra hash. @Assert: It is possible to associate an activation key with an organization. @Feature: Architecture """ name = gen_utf8() os_id = entities.OperatingSystem().create()['id'] response = client.post( entities.Architecture().path(), {u'name': name, u'operatingsystem_ids': [os_id]}, auth=get_server_credentials(), verify=False, ) response.raise_for_status() attrs = response.json() # The server will accept some POSTed attributes (name) and silently # ignore others (operatingsystem_ids). self.assertIn('name', attrs) self.assertEqual(name, attrs['name']) self.assertIn('operatingsystems', attrs) self.assertEqual([os_id], attrs['operatingsystems'])
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 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.""") if entity is entities.AuthSourceLDAP and bz_bug_is_open(1140313): self.skipTest("Bugzilla bug 1140313 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, ) response.raise_for_status() # Get the just-created entity and examine its attributes. entity_n = entity(id=response.json()['id']) logger.info('test_post_and_get path: {0}'.format(entity_n.path())) real_attrs = entity_n.read_json() for key, value in gen_attrs.items(): self.assertIn(key, real_attrs.keys()) self.assertEqual(value, real_attrs[key], key)
def test_post_status_code(self, entity): """@Test: Issue a POST request and check the returned status code. @Assert: HTTP 201 is returned with an ``application/json`` content-type """ # Some arguments are "normal" classes and others are objects produced # by functools.partial. Also, `partial(SomeClass).func == SomeClass`. if ((entity.func if isinstance(entity, partial) else entity) in BZ_1118015_ENTITIES and bz_bug_is_open(1118015)): self.skipTest('Bugzilla bug 1118015 is open.') path = entity().path() response = client.post( path, entity().build(), auth=get_server_credentials(), verify=False, ) status_code = httplib.CREATED 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, 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_update_contents(self): """@Test: Create a repository and upload RPM contents. @Assert: The repository's contents include one RPM. @Feature: Repository """ # Create a repository and upload RPM content. repo_id = entities.Repository(product=self.prod_id).create()['id'] client.post( entities.Repository(id=repo_id).path(which='upload_content'), {}, auth=get_server_credentials(), files={u'content': open(get_data_file(RPM_TO_UPLOAD), 'rb')}, verify=False, ).raise_for_status() # Verify the repository's contents. attrs = entities.Repository(id=repo_id).read_json() self.assertEqual(attrs[u'content_counts'][u'rpm'], 1)
def test_post_unauthorized(self, entity): """@Test: POST to an entity-dependent path without credentials. @Assert: HTTP 401 is returned """ path = entity().path() response = client.post(path, verify=False) status_code = httplib.UNAUTHORIZED self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), )
def test_create_text_plain(self): """@Test Create an organization using a 'text/plain' content-type. @Assert: HTTP 415 is returned. @Feature: Organization """ organization = entities.Organization() organization.create_missing() response = client.post( organization.path(), organization.create_payload(), auth=get_server_credentials(), headers={'content-type': 'text/plain'}, verify=False, ) self.assertEqual(httplib.UNSUPPORTED_MEDIA_TYPE, response.status_code)
def setup_to_create_cv(self, session, cv_name, repo_name=None, repo_url=None, repo_type=None): """Create product/repo and sync it and create CV""" cv_name = cv_name or generate_string("alpha", 8) repo_name = repo_name or generate_string("alpha", 8) repo_url = repo_url or FAKE_1_YUM_REPO repo_type = repo_type or REPO_TYPE['yum'] # Creates new product and repository via API's product_attrs = entities.Product( organization=self.org_id ).create() repo_attrs = entities.Repository( name=repo_name, url=repo_url, content_type=repo_type, product=product_attrs['id'], ).create() # Sync repository response = client.post( entities.Repository(id=repo_attrs['id']).path('sync'), { u'ids': [repo_attrs['id']], u'organization_id': self.org_id }, auth=get_server_credentials(), verify=False, ).json() self.assertGreater( len(response['id']), 1, u"Was not able to fetch a task ID.") task_status = entities.ForemanTask(id=response['id']).poll() self.assertEqual( task_status['result'], u'success', u"Sync for repository {0} failed.".format(repo_attrs['name'])) make_contentview(session, org=self.org_name, name=cv_name) self.assertIsNotNone(self.content_views.search(cv_name))
def test_positive_update_5(self): """@Test: Create a repository and upload rpm contents @Feature: Repositories @Assert: Repository is updated with contents """ # Create a repository and upload an RPM file. attrs = entities.Repository(url=FAKE_1_YUM_REPO).create() response = client.post( entities.Repository(id=attrs['id']).path(which='upload_content'), {}, auth=get_server_credentials(), files={u'content': open(get_data_file(RPM_TO_UPLOAD), 'rb')}, verify=False, ) response.raise_for_status() # Fetch info about the updated repo and verify the file was uploaded. attrs = entities.Repository(id=attrs['id']).read_json() self.assertEqual(attrs[u'content_counts'][u'rpm'], 1)
def test_post_status_code(self, entity): """@Test: Issue a POST request and check the returned status code. @Assert: HTTP 201 is returned with an ``application/json`` content-type """ if entity in BZ_1118015_ENTITIES and bz_bug_is_open(1118015): self.skipTest("Bugzilla bug 1118015 is open.""") path = entity().path() response = client.post( path, entity().build(), auth=get_server_credentials(), verify=False, ) status_code = httplib.CREATED self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), ) self.assertIn('application/json', response.headers['content-type'])
def create(self, auth=None): """Create a new entity, plus all of its dependent entities. Create an entity at the path returned by :meth:`Factory._factory_path`. If necessary, recursively create dependent entities. When done, return a dict of information about the newly created entity. :param tuple auth: A ``(username, password)`` pair to use when communicating with the API. If ``None``, the credentials returned by :func:`robottelo.common.helpers.get_server_credentials` are used. :return: Information about the newly created entity. :rtype: dict :raises robottelo.factory.FactoryError: If the server returns an error when attempting to create an entity. """ if auth is None: auth = get_server_credentials() # Create dependent entities and generate values for non-FK fields. values = self.build(auth) # Create the current entity. path = urljoin(get_server_url(), self._factory_path()) response = client.post(path, values, auth=auth, verify=False).json() if 'error' in response.keys() or 'errors' in response.keys(): if 'error' in response.keys(): message = response['error'] else: message = response['errors'] raise FactoryError( 'Error encountered while POSTing to {0}. Error received: {1}' ''.format(path, message) ) # Tell caller about created entity. return response
def test_create_text_plain(self): """@Test Create an organization using a 'text/plain' content-type. @Assert: HTTP 415 is returned. @Feature: Organization """ path = entities.Organization().path() attrs = entities.Organization().build() response = client.post( path, attrs, auth=get_server_credentials(), headers={'content-type': 'text/plain'}, verify=False, ) status_code = httplib.UNSUPPORTED_MEDIA_TYPE self.assertEqual( status_code, response.status_code, status_code_error(path, status_code, response), )
def test_smoke(self): """ @Test: Check that basic content can be created 1. Create a new user with admin permissions 2. Using the new user from above: 1. Create a new organization 2. Create two new lifecycle environments 3. Create a custom product 4. Create a custom YUM repository 5. Create a custom PUPPET repository 6. Synchronize both custom repositories 7. Create a new content view 8. Associate both repositories to new content view 9. Publish content view 10. Promote content view to both lifecycles 11. Create a new libvirt compute resource 12. Create a new subnet 13. Create a new domain 14. Create a new hostgroup and associate previous entities to it @Feature: Smoke Test @Assert: All entities are created and associated. """ # prep work # # FIXME: Use a larger charset when authenticating users. # # It is possible to create a user with a wide range of characters. (see # the "User" entity). However, Foreman supports only HTTP Basic # authentication, and the requests lib enforces the latin1 charset in # this auth mode. We then further restrict ourselves to the # alphanumeric charset, because Foreman complains about incomplete # multi-byte chars when latin1 chars are used. # login = orm.StringField(str_type=('alphanumeric',)).get_value() password = orm.StringField(str_type=('alphanumeric',)).get_value() # step 1: Create a new user with admin permissions entities.User(admin=True, login=login, password=password).create() # step 2.1: Create a new organization org = entities.Organization().create(auth=(login, password)) # step 2.2: Create 2 new lifecycle environments le1 = entities.LifecycleEnvironment(organization=org['id']).create() le2 = entities.LifecycleEnvironment( organization=org['id'], prior=le1['id']).create() # step 2.3: Create a custom product prod = entities.Product(organization=org['id']).create() # step 2.4: Create custom YUM repository repo1 = entities.Repository( product=prod['id'], content_type=u'yum', url=GOOGLE_CHROME_REPO ).create() # step 2.5: Create custom PUPPET repository repo2 = entities.Repository( product=prod['id'], content_type=u'puppet', url=FAKE_PUPPET_REPO ).create() # step 2.6: Synchronize both repositories for repo in [repo1, repo2]: response = client.post( entities.Repository(id=repo['id']).path('sync'), { u'ids': [repo['id']], u'organization_id': org['id'] }, auth=get_server_credentials(), verify=False, ).json() self.assertGreater( len(response['id']), 1, u"Was not able to fetch a task ID.") task_status = entities.ForemanTask(id=response['id']).poll() self.assertEqual( task_status['result'], u'success', u"Sync for repository {0} failed.".format(repo['name'])) # step 2.7: Create content view content_view = entities.ContentView(organization=org['id']).create() # step 2.8: Associate YUM repository to new content view response = client.put( entities.ContentView(id=content_view['id']).path(), auth=get_server_credentials(), verify=False, data={u'repository_ids': [repo1['id']]}) # Fetch all available puppet modules puppet_mods = client.get( entities.ContentView(id=content_view['id']).path( 'available_puppet_module_names'), auth=get_server_credentials(), verify=False).json() self.assertGreater( puppet_mods['results'], 0, u"No puppet modules were found") # Select a random puppet module from the results puppet_mod = random.choice(puppet_mods['results']) # ... and associate it to the content view path = entities.ContentView(id=content_view['id']).path( 'content_view_puppet_modules') response = client.post( path, auth=get_server_credentials(), verify=False, data={u'name': puppet_mod['module_name']}) self.assertEqual( response.status_code, httplib.OK, status_code_error(path, httplib.OK, response) ) self.assertEqual( response.json()['name'], puppet_mod['module_name'], ) # step 2.9: Publish content view task = entities.ContentView(id=content_view['id']).publish() task_status = entities.ForemanTask(id=task['id']).poll() self.assertEqual( task_status['result'], u'success', u"Publishing {0} failed.".format(content_view['name'])) # step 2.10: Promote content view to both lifecycles content_view = entities.ContentView(id=content_view['id']).read_json() self.assertEqual( len(content_view['versions']), 1, u'There should only be 1 version published.') self.assertEqual( len(content_view['versions'][0]['environment_ids']), 1, u"Content view should be present on 1 lifecycle only") task = entities.ContentViewVersion( id=content_view['versions'][0]['id']).promote(le1['id']) task_status = entities.ForemanTask(id=task['id']).poll() self.assertEqual( task_status['result'], u'success', u"Promoting {0} to {1} failed.".format( content_view['name'], le1['name'])) # Check that content view exists in 2 lifecycles content_view = entities.ContentView(id=content_view['id']).read_json() self.assertEqual( len(content_view['versions']), 1, u'There should only be 1 version published.') self.assertEqual( len(content_view['versions'][0]['environment_ids']), 2, u"Content view should be present on 2 lifecycles only") task = entities.ContentViewVersion( id=content_view['versions'][0]['id']).promote(le2['id']) task_status = entities.ForemanTask(id=task['id']).poll() self.assertEqual( task_status['result'], u'success', u"Promoting {0} to {1} failed.".format( content_view['name'], le2['name'])) # Check that content view exists in 2 lifecycles content_view = entities.ContentView(id=content_view['id']).read_json() self.assertEqual( len(content_view['versions']), 1, u'There should only be 1 version published.') self.assertEqual( len(content_view['versions'][0]['environment_ids']), 3, u"Content view should be present on 3 lifecycle only") # BONUS: Create a content host and associate it with promoted # content view and last lifecycle where it exists content_host = entities.System( content_view=content_view['id'], environment=le2['id'] ).create() # Check that content view matches what we passed self.assertEqual( content_host['content_view_id'], content_view['id'], u"Content views do not match." ) # Check that lifecycle environment matches self.assertEqual( content_host['environment']['id'], le2['id'], u"Environments do not match." )
def test_smoke(self): """ @Test: Check that basic content can be created 1. Create a new user with admin permissions 2. Using the new user from above: 1. Create a new organization 2. Create two new lifecycle environments 3. Create a custom product 4. Create a custom YUM repository 5. Create a custom PUPPET repository 6. Synchronize both custom repositories 7. Create a new content view 8. Associate both repositories to new content view 9. Publish content view 10. Promote content view to both lifecycles 11. Create a new libvirt compute resource 12. Create a new subnet 13. Create a new domain 14. Create a new capsule 15. Create a new hostgroup and associate previous entities to it @Feature: Smoke Test @Assert: All entities are created and associated. """ # prep work # # FIXME: Use a larger charset when authenticating users. # # It is possible to create a user with a wide range of characters. (see # the "User" entity). However, Foreman supports only HTTP Basic # authentication, and the requests lib enforces the latin1 charset in # this auth mode. We then further restrict ourselves to the # alphanumeric charset, because Foreman complains about incomplete # multi-byte chars when latin1 chars are used. # login = orm.StringField(str_type=('alphanumeric',)).get_value() password = orm.StringField(str_type=('alphanumeric',)).get_value() # step 1: Create a new user with admin permissions entities.User(admin=True, login=login, password=password).create() # step 2.1: Create a new organization org = entities.Organization().create(auth=(login, password)) # step 2.2: Create 2 new lifecycle environments le1 = entities.LifecycleEnvironment(organization=org['id']).create() le2 = entities.LifecycleEnvironment( organization=org['id'], prior=le1['id']).create() # step 2.3: Create a custom product prod = entities.Product(organization=org['id']).create() # step 2.4: Create custom YUM repository repo1 = entities.Repository( product=prod['id'], content_type=u'yum', url=GOOGLE_CHROME_REPO ).create() # step 2.5: Create custom PUPPET repository repo2 = entities.Repository( product=prod['id'], content_type=u'puppet', url=FAKE_PUPPET_REPO ).create() # step 2.6: Synchronize both repositories response = client.post( entities.Repository(id=repo1['id']).path('sync'), {u'ids': [repo1['id']]}, auth=get_server_credentials(), verify=False, params={u'organization_id': org['id']}).json() # TODO: Fetch status of sync task from response task 'id' # step 2.7: Create content view content_view = entities.ContentView(organization=org['id']).create()