Session State Handling.

plainbox.impl.session.state – session state handling

class plainbox.impl.session.state.SessionDeviceContext(state=None)[source]

Bases: object

Session context specific to a given device.

This class exposes access to a “world view” unique to a specific device. The view is composed of the following attributes:

Attr _provider_list:
 A list of providers known by this device. All of those providers are compatible with the device.
Attr _unit_list:
 A list of all the units known by this device. Initially it is identical to the union of all the units from _provider_list but it is in fact mutable and can be grown (or shrunk in some cases) when jobs are created at runtime.
Attr _test_plan_list:
 A list of test plans that this device will be executing. This is stored so that all job changes can automatically apply field overrides to job state.
Attr _device:Always None, this is a future extension point
Attr _state:A SessionState object that holds all of the job results and also exposes some legacy API for computing the run list and the desired job list
add_provider(provider, add_units=True)[source]

Add a provider to the context.

Parameters:
  • provider – The Provider1 to add
  • add_units – An optional flag that controls if all of the units from that provider should be added. Defaults to True.
Raises:

ValueError – If the provider is already in the context

This method can be used to add a provider to the context. It also adds all of the units of that provider automatically.

Note

This method fires the on_provider_added() signal but it does so before any of the units from that provider are added.

add_unit(unit, recompute=True)[source]

Add a unit to the context.

Parameters:unit – The Unit to add.
Raises:ValueError – If the unit is already in the context

This method can be used to register both the initially-known units as well as units generated at runtime.

This method fires the on_unit_added() signal

compute_shared(cache_key, func, *args, **kwargs)[source]

Compute a shared helper.

Parameters:
  • cache_key – Key to use to lookup the helper value
  • func – Function that computes the helper value. The function is called with the context as the only argument
Returns:

Return value of func(self, *args, **kwargs) (possibly computed earlier).

Compute something that can be shared by all users of the device context This allows certain expensive computations to be performed only once.

Note

The caller is responsible for ensuring that args and kwargs match the cache_key each time this function is called.

device

The device associated with this context.

Warning

Currently this method will always return None. In the future it will return an object that describes the device.

execution_controller_list

A list of execution controllers applicable in this context.

Returns:A list of IExecutionController objects

Note

The return value is different whenever a provider is added to the context. If you have obtained this value in the past it may be no longer accurate.

get_ctrl_for_job(job)[source]

Get the execution controller most applicable to run this job.

Parameters:job – A job definition to run
Returns:An execution controller instance
Raises:LookupError – if no execution controller capable of running the specified job can be found

The best controller is the controller that has the highest score (as computed by :meth:`IExecutionController.get_score()) for the job in question.

get_unit(unit_id, kind_name=None)[source]

Get an unit with a specific identifier.

Parameters:
  • unit_id – The identifier of the unit to find
  • kind_name – (optional) Name of the type of unit. By default units of any type can be found. Unit kind is the value of the unit.Meta.name attribute. Using this argument allows the caller to quickly find only units of a particular type without having to do the filtering on their side.
Raises:

KeyError – If the matching unit does not exists.

invalidate_shared(cache_key)[source]

Invalidate a cached shared value.

on_job_added

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_provider_added

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_unit_added

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_unit_removed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
override_map

A list of execution controllers applicable in this context.

Returns:A list of IExecutionController objects

Note

The return value is different whenever a provider is added to the context. If you have obtained this value in the past it may be no longer accurate.

provider_list

The list of providers currently available in this context.

Note

You must not modify the return value.

This is not enforced but please use the add_provider() method if you want to add a provider. Currently you cannot remove providers or reorder the list of providers.

remove_unit(unit)[source]

Remove an unit from the context.

Parameters:unit – The Unit to remove.

This method fires the on_unit_removed() signal

set_test_plan_list()[source]

Compute all of the effective job state values.

Parameters:test_plan_list – The list of test plans to consider

This method is intended to be called exactly once per session, after the application determines the set of test plans it intends to execute.

The method will collect all of the override values exposed by all of the test plans and apply them in sequence. Note that correct applications must also perform micro-updates whenever a new test job is added to the system.

state

The session state object associated with this context.

Note

You can use both the session state and the session device context to query and monitor the changes to all the participating units

unit_list

The list of units currently available in this context.

Note

You must not modify the return value.

This is not enforced but please use the add_unit() or remove_unit() if you want to manipulate the list. Currently you cannot reorder the list of units.

class plainbox.impl.session.state.SessionMetaData(title=None, flags=None, running_job_name=None, app_blob=None, app_id=None)[source]

Bases: object

Class representing non-critical state of the session.

The data held here allows applications to reason about sessions in general but is not relevant to the runner or the core in general

FLAG_BOOTSTRAPPING = 'bootstrapping'
FLAG_INCOMPLETE = 'incomplete'
FLAG_SUBMITTED = 'submitted'
FLAG_TESTPLANLESS = 'testplanless'
app_blob

Custom, application specific binary blob.

The type and value of this property is irrelevant as it is not inspected by plainbox at all. Reasonable applications will not make use of this property for storing large amounts of data. If you are tempted to do that, please redesign your application or propose changes to plainbox.

app_id

Application identifier.

A string identifying the application that stored app_blob. It is recommended to use reverse domain names or UUIDs.

flags

a set of flags that are associated with this session.

This set is persisted by persistent_save() and can be used to keep track of how the application wants to interpret this session state.

Intended usage is to keep track of “testing finished” and “results submitted” flags. Some flags are added as constants to this class.

running_job_name

id of the running job.

Note

This property has a confusing name. It actually refers to job ID, not name.

This property should be updated to keep track of the name of the job that is being executed. When either plainbox or the machine it was running on crashes during the execution of a job this value should be preserved and can help the GUI to resume and provide an error message.

The property MUST be set before starting the job itself.

title

the session title.

Title is just an arbitrary string that can be used to distinguish between multiple sessions.

The value can be changed at any time.

class plainbox.impl.session.state.SessionState(unit_list)[source]

Bases: object

Class representing all state needed during a single program session.

This is the central glue/entry-point for applications. It connects user intents to the rest of the system / plumbing and keeps all of the state in one place.

The set of utility methods and properties allow applications to easily handle the lower levels of dependencies, resources and ready states.

SessionState has the following instance variables, all of which are currently exposed as properties.

Variables:
  • job_list (list) –

    A list of all known jobs

    Not all the jobs from this list are going to be executed (or selected for execution) by the user.

    It may change at runtime because of local jobs. Note that in upcoming changes this will start out empty and will be changeable dynamically. It can still change due to local jobs but there is no API yes.

    This list cannot have any duplicates, if that is the case a DependencyDuplicateError is raised. This has to be handled externally and is a sign that the job database is corrupted or has wrong data. As an exception if duplicates are perfectly identical this error is silently corrected.

  • unit_list (list) –

    A list of all known units

    This list contains all the known units, including all the know job definitions (and in the future, all test plans).

    It may change at runtime because of local jobs and template instantiations.

  • job_state_map (dict) –

    mapping that tracks the state of each job

    Mapping from job id to JobState. This basically has the test result and the inhibitor of each job. It also serves as a plainbox.impl.job.JobDefinition.id-> job lookup helper.

    Directly exposed with the intent to fuel part of the UI. This is a way to get at the readiness state, result and readiness inhibitors, if any.

    XXX: this can loose data job_list has jobs with the same id. It would be better to use job id as the keys here. A separate map could be used for the id->job lookup. This will be fixed when session controller branch lands in trunk as then jobs are dynamically added to the system one at a time and proper error conditions can be detected and reported.

  • desired_job_list (list) –

    subset of jobs selected for execution

    This is used to compute run_list. It can only be changed by calling update_desired_job_list() which returns meaningful values so this is not a settable property.

  • run_list (list) –

    sorted list of jobs to execute

    This is basically a superset of desired_job_list and a subset of job_list that is topologically sorted to allowing all desired jobs to run. This property is updated whenever desired_job_list is changed.

  • resource_map (dict) –

    all known resources

    A mapping from resource id to a list of plainbox.impl.resource.Resource objects. This encapsulates all “knowledge” about the system plainbox is running on.

    It is needed to compute job readiness (as it stores resource data needed by resource programs). It is also available to exporters.

    This is computed internally from the output of checkbox resource jobs, it can only be changed by calling update_job_result()

  • metadata (dict) – instance of SessionMetaData
add_job(new_job, recompute=True)[source]

Add a new job to the session.

Parameters:
  • new_job – The job being added
  • recompute – If True, recompute readiness inhibitors for all jobs. You should only set this to False if you’re adding a number of jobs and will otherwise ensure that _recompute_job_readiness() gets called before session state users can see the state again.
Returns:

The job that was actually added or an existing, identical job if a perfect clash was silently ignored.

Raises:

DependencyDuplicateError – if a duplicate, clashing job definition is detected

The new_job gets added to all the state tracking objects of the session. The job is initially not selected to run (it is not in the desired_job_list and has the undesired inhibitor).

The new_job may clash with an existing job with the same id. Unless both jobs are identical this will cause DependencyDuplicateError to be raised. Identical jobs are silently discarded.

Note

This method recomputes job readiness for all jobs

Deprecated since version 0.9: use the add_unit() method instead

add_unit(new_unit, recompute=True)[source]

Add a new unit to the session.

Parameters:
  • new_unit – The unit being added
  • recompute – If True, recompute readiness inhibitors for all jobs. You should only set this to False if you’re adding a number of jobs and will otherwise ensure that _recompute_job_readiness() gets called before session state users can see the state again.
Returns:

The unit that was actually added or an existing, identical unit if a perfect clash was silently ignored.

Raises:

DependencyDuplicateError – if a duplicate, clashing job definition is detected

Note

The following applies only to newly added job units:

The new_unit gets added to all the state tracking objects of the session. The job unit is initially not selected to run (it is not in the desired_job_list and has the undesired inhibitor).

The new_unit job may clash with an existing job with the same id. Unless both jobs are identical this will cause DependencyDuplicateError to be raised. Identical jobs are silently discarded.

Note

This method recomputes job readiness for all jobs unless the recompute=False argument is used. Recomputing takes a while so if you want to add a lot of units consider setting that to False and only recompute at the last call.

desired_job_list

List of jobs that are on the “desired to run” list.

This is a list, not a set, because the dependency solver algorithm retains as much of the original ordering as possible. Having said that, the actual order can differ widely (for instance, be reversed)

get_certification_status_map(outcome_filter=('fail', ), certification_status_filter=('blocker', ))[source]

Get a map of jobs that have a specific certification blocker status.

Filter the Job state map to only return items with given outcomes and certification statuses.

Parameters:
  • outcome_filter – Only consider job results with those outcome values
  • certification_status_filter – Only consider jobs with those certification status values
Returns:

a Job state map only containing job with a given outcome and certification status value.

get_estimated_duration(manual_overhead=30.0)[source]

Estimate the total duration of the session.

Provide the estimated duration of the jobs that have been selected to run in this session (maintained by calling update_desired_job_list).

Manual jobs have an arbitrary figure added to their runtime to allow for execution of the test steps and verification of the result.

Returns:(estimate_automated, estimate_manual)

where estimate_automated is the value for automated jobs only and estimate_manual is the value for manual jobs only. These can be easily combined. Either value can be None if the value could not be calculated due to any job lacking the required estimated_duration field.

get_outcome_stats()[source]

Process the JobState map to get stats about the job outcomes.

Returns:a mapping of “outcome”: “total” key/value pairs

Note

Only the outcomes seen during this session are reported, not all possible values (such as crash, not implemented, ...).

job_list

List of all known jobs.

Not necessarily all jobs from this list can be, or are desired to run. For API simplicity this variable is read-only, if you wish to alter the list of all jobs re-instantiate this class please.

job_state_map

Map from job id to JobState associated with each job.

mandatory_job_list

List of all mandatory jobs that must run.

Testplan units can specify a list of jobs that have to be run and are not supposed to be deselected by the application user.

metadata

meta-data object associated with this session state.

on_job_added

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_job_removed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_job_result_changed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_job_state_map_changed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_unit_added

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
on_unit_removed

Basic signal that supports arbitrary listeners.

While this class can be used directly it is best used with the helper decorator Signal.define on a function or method. See the documentation for the plainbox.vendor.morris module for details.

Attr _name:Name of the signal, typically accessed via name().
Attr _listeners:
 List of signal listeners. Each item is a tuple (listener, pass_signal) that encodes how to call the listener.
remove_unit(unit, *, recompute=True)[source]

Remove an existing unit from the session.

Parameters:
  • unit – The unit to remove
  • recompute – If True, recompute readiness inhibitors for all jobs. You should only set this to False if you’re adding a number of jobs and will otherwise ensure that _recompute_job_readiness() gets called before session state users can see the state again.

Note

This method recomputes job readiness for all jobs unless the recompute=False argument is used. Recomputing takes a while so if you want to add a lot of units consider setting that to False and only recompute at the last call.

resource_map

Map from resource id to a list of resource records.

run_list

List of jobs that were intended to run, in the proper order.

The order is a result of topological sorting of the desired_job_list. This value is recomputed when change_desired_run_list() is called. It may be shorter than desired_run_list due to dependency errors.

set_resource_list(resource_id, resource_list)[source]

Add or change a resource with the given id.

Resources silently overwrite any old resources with the same id.

trim_job_list(qualifier)[source]

Discard jobs that are selected by the given qualifier.

Parameters:qualifier – A qualifier that selects jobs to be removed
Ptype qualifier:
 IJobQualifier
Raises:ValueError – If any of the jobs selected by the qualifier is on the desired job list (or the run list)

This function correctly and safely discards certain jobs from the job list. It also removes the associated job state (and referenced job result) and results (for jobs that were resource jobs)

unit_list

List of all known units.

update_desired_job_list(desired_job_list, include_mandatory=True)[source]

Update the set of desired jobs (that ought to run).

This method can be used by the UI to recompute the dependency graph. The argument ‘desired_job_list’ is a list of jobs that should run. Those jobs must be a sub-collection of the job_list argument that was passed to the constructor.

It never fails although it may reduce the actual permitted desired_job_list to an empty list. It returns a list of problems (all instances of DependencyError class), one for each job that had to be removed.

update_job_result(job, result)[source]

Notice the specified test result and update readiness state.

This function updates the internal result collection with the data from the specified test result. Results can safely override older results. Results also change the ready map (jobs that can run) because of dependency relations.

Some results have deeper meaning, those are results for local and resource jobs. They are discussed in detail below:

Resource jobs produce resource records which are used as data to run requirement expressions against. Each time a result for a resource job is presented to the session it will be parsed as a collection of RFC822 records. A new entry is created in the resource map (entirely replacing any old entries), with a list of the resources that were parsed from the IO log.

Local jobs produce more jobs. Like with resource jobs, their IO log is parsed and interpreted as additional jobs. Unlike in resource jobs local jobs don’t replace anything. They cannot replace an existing job with the same id.

update_mandatory_job_list(mandatory_job_list)[source]

Update the set of mandatory jobs (that must run).

This method simply stores the list of mandatory jobs inside the session state. The next time the set of desired jobs is altered via a call update_desired_job_list() the effective selection will also include mandatory jobs.

comments powered by Disqus