Usage¶
This section explains Satellite Populate data populate.
Contents
Commands¶
Using $ satellite-populate
you can run the populate
and validate
commands.
That commands are used to read data description from YAML file and
populate the system or validate populated entities.
Having test_data.yaml
with the following content.
vars:
org_label_suffix = inc
actions:
- model: Organization
log: The first organization...
register: org_1
data:
name: MyOrg
label: MyOrg{{org_label_suffix}}
To populate the system
(satellite_env)[you@host]$ satellite-populate test_data.yaml -v -o validation_data.yaml
2017-01-04 04:31:17 - satellite_populate.base - INFO - CREATE: The first organization...
2017-01-04 04:31:19 - satellite_populate.base - INFO - search: Organization {'query': {'search': 'name=MyOrg,label=MyOrg'}} found unique item
2017-01-04 04:31:19 - satellite_populate.base - INFO - create: Entity already exists: Organization 36
2017-01-04 04:31:19 - satellite_populate.base - INFO - registry: org_1 registered
To validate the system use the file generated by population validation_data.yaml
(satellite_env)[you@host]$ satellite-populate validation_data.yaml
(satellite_env)[you@host]$ echo $?
0 # system validated else 1
Use $ satellite-populate --help
for more info
Hostname and Credentials¶
Pass -h –hostname, -p –password, -u –username to the command, or this arguments to decorator:
@populate_with(data, username='x', password='y', hostname='server.com')
Decorator¶
Other way to use populate is via decorator, it is useful to decorate a test_case forcing a populate or validate operation to be performed.
Having a data_file like:
actions: - model: Organization register: organization_1 data: name: My OrgThen you can use in decorators:
@populate_with('file.yaml') def test_case_(self): 'My Org exists in system test anything here'And getting the populated entities inside the test_case:
@populate_with('file.yaml', context_name='my_context') def test_case_(self, my_context=None): assert my_context.organization_1.name == 'My Org' You can also set a customized context wrapper to the context_wrapper argument:: def my_custom_context_wrapper(result): # create an object using result my_context = MyResultContext(result) return my_context @populate_with('file.yaml', context_name='my_context', content_wrapper=my_custom_context_wrapper) def test_case_(self, my_context=None): # assert with some expression using my_context object returned # my_custom_context_wrapper assert some_expression
And if you don’t want to have YAML file you can provide a dict:
data_in_dict = {
'actions': [
{
'model': 'Organization',
'register': 'organization_1',
'data': {
'name': 'My Organization 1',
'label': 'my_organization_1'
}
},
]
}
@populate_with(data_in_dict, context_name='my_context', verbose=1)
def test_org_1(my_context=None):
"""a test with populated data"""
assert my_context.organization_1.name == "MyOrganization1"
And finally it also accepts bare YAML string for testing purposes:
data_in_string = """
actions:
- model: Organization
registry: organization_3
data:
name: My Organization 3
label: my_organization_3
"""
@populate_with(data_in_string, context_name='context', verbose=1)
def test_org_3(context=None):
"""a test with populated data"""
assert context.organization_3.name == "My Organization 3"
assert context.organization_3.label == "my_organization_3"
NOTE:
That is important that ``context_name`` argument always be declared
using either a default value ``my_context=None`` or handle in
``**kwargs`` Otherwise ``py.test`` may try to use this as a fixture
placeholder.
if context_wrapper is set to None, my_context will be the pure unmodified
result of populate function.
Decorating UnitTest setUp and test_cases:
class MyTestCase(TestCase):
"""
This test populates data in setUp and also in individual tests
"""
@populate_with(data_in_string, context_name='context')
def setUp(self, context=None):
self.context = context
def test_with_setup_data(self):
self.assertEqual(
self.context.organization_3.name, "My Organization 3"
)
@populate_with(data_in_dict, context_name='test_context')
def test_with_isolated_data(self, test_context=None):
self.assertEqual(
test_context.organization_1.name, "My Organization 1"
)
The YAML data file¶
In the YAML data file it is possible to specify 3 sections, config
, vars
and actions
.
config¶
The config may be used to define special behavior of populator and its keys are:
populator
The name of the populator defined in
populators
populators
The specification of populator modules to be loaded
verbose
The verbosity of logging 0, 1 or 2, it can be overwritten with -vvv in commands.
example:
config:
verbose: 3
populator: api
populators:
api:
module: satellite_populate.api.APIPopulator
cli:
module: satellite_populate.cli.CLIPopulator
vars¶
Variables to be available in the rendering context of the YAML data
every var defined here is available to be referenced using Jinja
syntax in
any action.
vars:
admin_username: admin
admin_password: changeme
org_name_list:
- company7
- company8
prefix: aaaa
suffix: bbbb
my_name: me
actions¶
The actions is the most important section of the YAML, it is a list of actions being each action a dictionary containing special keys depending on the action type.
The action type is defined in action
key and available actions are:
Actions are executed in the defined order and order is very important because
each action can register
its result to the internal registry to be referenced
later in any other action.
CRUD ACTIONS
Crud actions takes a model
argument, any from nailgun.entities
is valid.
create (the default)
Creates a new entity if not exists, else gets existing.
update
Updates entity with provided
data
byid
or unique searchdelete
deleted entity with
id
or unique search
SPECIAL ACTIONS
echo
Logs and print output to the console
register
Register a variable in the internal registry
unregister
removes a variable from register
assertion
perform assertion operations, if any fails returns exit code 1
Dynamic Data¶
There are some ways to fetch dynamic data in action definitions, it depends on the action type.
For any key you can use Jinja
to provide a dynamic value as in:
value: "{{ get_something }}"
value: "{{ fauxfactory.gen_string('alpha') }}"
value: user_{{ item }}
For some actions you can provide a data
key, that data is used to create
new entities and also to perform searches or build the action function.
Every data
key accepts 4 special reference directives in its sub-keys.
from_registry
Gets anything from registry:
data: organization: from_registry: default_org name: from_registry: my_name
from_object
Gets any Python object available in the environment:
data: url: from_object: name: robottelo.constants.FAKE_0_YUM_REPO
from_search
Perform a search and return its result:
data: organization: from_search: model: Organization data: name: Default Organization
from_read
Perform a read operation, which is useful when we have unique data or id:
data: organization: from_read: model: Organization data: id: 1
The internal registry¶
Every action which returns a result can write its result to the registry, so it is available to be accessed by other actions.
Provide a register
unique name in action
definition.
The actions that support register
are:
- create
- update
- register
- assertion
All dynamic directives from_*
supports the use of register
Example:
- action: create
model: Organization
register: my_org
data:
name: my_org
- model: User
log: Creating user under {{ register.my_org.name }}
data:
organization:
from_registry: my_org