def test_get_endpoints_and_messages_combines_endpoints_and_messages_from_all_addons( self): endpoint1 = EndpointId('extension1', '') endpoint2 = EndpointId('extension2', '') msg1 = MessageId('msg1', '') msg2 = MessageId('msg2', '') msg3 = MessageId('msg3', '') @FrameworkExtension('extension1', endpoints_and_messages={endpoint1: [msg1, msg2]}) class Extension1(): pass @FrameworkExtension('extension2', endpoints_and_messages={endpoint2: [msg3]}) class Extension2(): pass self.em.add_extension(Extension1) self.em.add_extension(Extension2) self.em.enable_all_extensions() actual_endpoints_and_messages = self.em.get_endpoints_and_messages() self.assertEqual(actual_endpoints_and_messages[endpoint1], [msg1, msg2]) self.assertEqual(actual_endpoints_and_messages[endpoint2], [msg3])
argument=True) PLUGIN_DIRS = ConfigOptionId( 'plugin.dirs', 'Directories with Asciidoctor plugins. Can be provided multiple times.', multiple=True, option_type=Path(exists=True)) ASCIIDOCTOR_ENDPOINT = EndpointId('ASCIIDOCTOR_ENDPOINT', 'Endpoint for Asciidoctor Extension') ASCIIDOCTOR_PLUGINS_ENDPOINT = EndpointId( 'ASCIIDOCTOR_PLUGINS_ENDPOINT', 'Endpoint that handles Asciidoctor Plugins') GENERATE_DOC = MessageId( 'GENERATE_DOC', """ Request to generate documentation data: AsciidoctorCommand object """) GET_ASCIIDOCTOR_OPTIONS = MessageId( 'GET_ASCIIDOCTOR_OPTIONS', """ Get command line options for the Asciidoctor command data: String with preformated options """) class AsciidoctorCommand(object): def __init__(self, output_path): self._output_path = output_path
from zaf.messages.message import EndpointId, MessageId MONITOR_ENDPOINT = EndpointId('monitor', """\ The K2 monitor addon endpoint. """) PERFORM_MEASUREMENT = MessageId( 'PERFORM_MEASUREMENT', """ Request that a monitor performs its measurements. data: None """)
'tests.exclude', 'Exclude test cases where the start of the qualified name matches this value. ' 'Syntax is "package[.module[[.class].testcase]]."', multiple=True, ) TESTS_EXCLUDE_REGEX = ConfigOptionId( 'tests.exclude.regex', 'Exclude test cases where the qualified name matches this regex.', multiple=True, ) SCHEDULE_NEXT_TEST = MessageId( 'SCHEDULE_NEXT_TEST', """\ Request that the scheduler schedules the next test case to be run. data: None returns: TestCaseDefinition """) ADD_TEST_CASES = MessageId( 'ADD_TEST_CASES', """\ Message that can be sent to the test scheduler to add test cases to the run queue. Test cases will not be added if ABORT or CRITICAL_ABORT messages have been received by the scheduler. data: List of TestCaseDefinition """) REMOVE_TEST_CASES = MessageId( 'REMOVE_TEST_CASES', """\ Message that can be sent to the test scheduler to remove test cases from the run queue.
from collections import namedtuple from zaf.messages.message import MessageId, EndpointId DocTemplate = namedtuple('DocTemplate', ['package', 'template_dir', 'filename']) DOCGEN_COMMAND_ENDPOINT = EndpointId('DOCGEN_COMMAND_ENDPOINT', """Endpoint for the docgen command.""") GET_CUSTOM_LOGGING_DOCS = MessageId( 'GET_CUSTOM_LOGGING_DOCS', """ Get path to template file with custom logging documentation that should be injected into the generated documentation. return: list of DocTemplate """) GET_CUSTOM_DOCS = MessageId( 'GET_CUSTOM_DOCS', """ Get list of paths to templates that should be rendered and included in the generated documentation. return: list of DocTemplate """) GET_CUSTOM_DOC_FILES = MessageId( 'GET_CUSTOM_DOC_FILES', """ Get list of files that need to be put in the same directory as the documentation. return: list of DocTemplate
from zaf.config.options import ConfigOptionId from zaf.messages.message import EndpointId, MessageId from k2.sut import SUT CONNECTIONCHECK_ENDPOINT = EndpointId( 'connectioncheck', 'Endpoint for the connection check messages') CONNECTIONCHECK_RUN_CHECK = MessageId( 'CONNECTIONCHECK_RUN_CHECK', """\ Tells subscribers to the message to run their checks and return the result as a ConnectionCheckResult. """) CONNECTIONCHECK_RUN_CHECKS = MessageId( 'CONNECTIONCHECK_RUN_CHECKS', """\ Send to connectioncheck to trigger all connection checks. Raises exception if any of the required checks fail. """) CONNECTIONCHECK_ENABLED = ConfigOptionId('connectioncheck.enabled', 'Enable the connection check', option_type=bool, default=True, at=SUT) CONNECTIONCHECK_SHOULD_RECOVER = ConfigOptionId( 'connectioncheck.should.recover', 'Attempt to recover the SUT on failed connection check', option_type=bool, default=True,
logger.addHandler(logging.NullHandler()) EXIT_CODE_FROM_VERDICT = ConfigOptionId( 'exitcode.from.verdict', 'Give the verdict of the test run as exit code', option_type=bool, default=False) RUN_COMMAND_ENDPOINT = EndpointId('runcommand', """ The K2 run command """) PRE_INITIALIZE_SUT = MessageId( 'PRE_INITIALIZE_SUT', """ Triggered before the initialize the SUT. This message is sent once for each sut entity. data: None """) INITIALIZE_SUT = MessageId( 'INITIALIZE_SUT', """ Triggered when the run command is ready to initialize the SUT. Initializing the SUT should done be as a callback. This message is sent once for each sut entity. data: None """) POST_INITIALIZE_SUT = MessageId( 'POST_INITIALIZE_SUT', """
from zaf.config.options import ConfigOptionId from zaf.messages.message import EndpointId, MessageId EXTENSION_NAME = 'testrunner' RUNNER_ENDPOINT = EndpointId('runner', """\ The K2 default test runner """) TEST_RUN_STARTED = MessageId( 'TEST_RUN_STARTED', """\ Message that is triggered when the test runner has started. data: k2.runner.messages.TestRunStarted """) TEST_RUN_FINISHED = MessageId( 'TEST_RUN_FINISHED', """\ Message that is triggered when the test runner has finished. data: k2.runner.messages.TestRunFinished """) TEST_CASE_STARTED = MessageId( 'TEST_CASE_STARTED', """\ Message that is triggered when the test case is started. data: k2.runner.messages.TestCaseStarted """) TEST_CASE_FINISHED = MessageId(
from zaf.config.options import ConfigOptionId from zaf.messages.message import EndpointId, MessageId MULTI_RUNNER_ENDPOINT = EndpointId('customrunner', 'Endpoint for the custom runner') MULTI_RUNNER_ENABLED = ConfigOptionId('multi.runner.enabled', ( 'Enable the custom runner. ' 'The normal test runner needs to be disabled for this to work as expected.' ), option_type=bool, default=False) TEST_SUBRUN = MessageId( 'TEST_SUBRUN', """\ Triggered when the test sub-run is started. data: None """)
from zaf.config.options import ConfigOptionId from zaf.messages.message import MessageId SUT_RECOVERY_PERFORM = MessageId( 'SUT_RECOVERY_PERFORM', """\ Perform a sut recovery. Send with endpoint_id=None and entity=sut_id. Raise exception if recovery is unsuccessful """) SUT_RECOVERY_STARTED = MessageId( 'SUT_RECOVERY_STARTED', """\ Event indicating the recovery has been started. """) SUT_RECOVERY_COMPLETED = MessageId( 'SUT_RECOVERY_COMPLETED', """\ Event indicating the recovery has been completed. """) SUT_RESET_EXPECTED = MessageId( 'SUT_RESET_EXPECTED', """\ Event indicating that one or multiple expected reset(s) will be initiated. The event should be triggered by any module/extension that intentionally resets the system under test. This to allow extensions that trigger SUT_RESET_STARTED and SUT_RESET_DONE to take that into account. """) SUT_RESET_NOT_EXPECTED = MessageId( 'SUT_RESET_NOT_EXPECTED', """\ Event indicating no more reset(s) are expected and should be treated as failures. The event should be triggered by any module/extension that intentionally resets the system under test. This to allow extensions that trigger SUT_RESET_STARTED and SUT_RESET_DONE to take that into account.
import threading import unittest from zaf.application import AFTER_COMMAND, APPLICATION_ENDPOINT from zaf.builtin.unittest.harness import ExtensionTestHarness from zaf.config.manager import ConfigManager from zaf.messages.dispatchers import LocalMessageQueue from zaf.messages.message import EndpointId, MessageId from .. import BLOCKER_ENABLED, BLOCKER_ENDPOINT, BLOCKING_COMPLETED, BLOCKING_STARTED, \ BLOCKING_TIMED_OUT, START_BLOCKING_ON_MESSAGE, STOP_BLOCKING_ON_MESSAGE, StartBlockingInfo from ..blocker import Blocker TEST_BLOCKER_ENDPOINT = EndpointId('TEST_BLOCKER_ENDPOINT', '') TEST_BLOCKER_BLOCK = MessageId('TEST_BLOCKER_BLOCK', '') class BlockerTest(unittest.TestCase): def test_enabling_using_config(self): config = ConfigManager() config.set(BLOCKER_ENABLED, True) with ExtensionTestHarness( Blocker, endpoints_and_messages={APPLICATION_ENDPOINT: [AFTER_COMMAND]}, config=config) as harness: self.assertTrue(harness.extension._enabled) with ExtensionTestHarness(Blocker, endpoints_and_messages={ TEST_BLOCKER_ENDPOINT:
from zaf.config.options import ConfigOptionId from zaf.messages.message import EndpointId, MessageId from k2.sut import SUT SUTEVENTSLOG_ENDPOINT = EndpointId('suteventslog', 'Endpoint for the log based SUT events') SUTEVENTSTIME_ENDPOINT = EndpointId('suteventstime', 'Endpoint for the time based SUT events') SUTEVENTSCOMPONENT_ENDPOINT = EndpointId( 'sutevents', 'Endpoint for the SUT events component extension') LOG_LINE_RECEIVED = MessageId( 'LOG_LINE_RECEIVED', """\ An event that is sent for each line on the serial port """) IS_SUT_RESET_EXPECTED = MessageId( 'IS_SUT_RESET_EXPECTED', """\ Request to check if sut reset is expected. """) SUT_RESET_STARTED_PATTERN = ConfigOptionId( 'resetstarted.pattern', 'Pattern that matches logline that indicates that the SUT has started reset', at=SUT) SUT_RESET_DONE_PATTERN = ConfigOptionId( 'resetdone.pattern', 'Pattern that matches logline that indicates that the SUT reset is complete', at=SUT)
from .version import __version__ except Exception: __version__ = None __version__ = '0.0.0' if not __version__ else __version__ try: from time import perf_counter, process_time from zaf.messages.message import EndpointId, MessageId PERF_COUNTER_K2_START = perf_counter() PROCESS_TIME_K2_START = process_time() ABORT = MessageId( 'ABORT', """ Triggered when K2 core receives a SIGINT. Informs all extensions to shut down. data: None """) CRITICAL_ABORT = MessageId( 'CRITICAL_ABORT', """ Triggered when K2 receives a second SIGINT or a SIGABRT. Informs all extensions to shut down right now. data: None """) CRITICAL_EXTENSION_ERROR = MessageId( 'CRITICAL_EXTENSION_ERROR', """ Triggered by extensions to indicate that a critical error has occurred.
args, kwargs = mock.wait_for_call(timeout=1) self.assertEqual(args[1].data, 'message') def create_harness(extension, endpoints_and_messages, config={}): config_manager = ConfigManager() for id, value in config.items(): config_manager.set(id, value) return ExtensionTestHarness(extension, endpoints_and_messages=endpoints_and_messages, config=config_manager) other_endpoint = EndpointId('otherendpoint', '') other_message = MessageId('othermessage', '') my_endpoint = EndpointId('myendpoint', '') my_message = MessageId('mymessage', '') required_option = ConfigOptionId('opt', '') @CommandExtension( 'name', config_options=[ConfigOption(required_option, required=True)], extends=[], endpoints_and_messages={my_endpoint: [my_message]}, ) class MyManualExtension(AbstractExtension): def __init__(self, config, instances):
from zaf.messages.message import EndpointId, MessageId HEALTH_CHECK_ENDPOINT = EndpointId( 'healthcheck', """\ The K2 health check addon endpoint. """) PERFORM_HEALTH_CHECK = MessageId( 'PERFORM_HEALTH_CHECK', """ Tells subscribers to this message to run their health check data: None """) PERFORM_HEALTH_CHECKS = MessageId( 'PERFORM_HEALTH_CHECK', """ Send to the healthcheck endpoint to trigger running all health checks data: None """) class HealthCheckError(Exception): """Raise from a dispatcher for the PERFORM_HEALTH_CHECK request to indicate check failure.""" pass
from k2.cmd.run import INITIALIZE_SUT, POST_INITIALIZE_SUT from k2.sut import SUT from orchestration.ansible import SUT_ANSIBLE_TEST_NODE from . import ANSIBLE_PARALLEL_RUNS logger = logging.getLogger(get_logger_name('k2', 'initansible')) logger.addHandler(logging.NullHandler()) INITIALIZE_ANSIBLE_SUTS_ENDPOINT = EndpointId( 'INITIALIZE_ANSIBLE_SUTS_ENDPOINT', 'Endpoint for initializing Ansible Suts') INITIALIZE_ANSIBLE_NODE = MessageId( 'INITIALIZE_ANSIBLE_NODE', dedent("""\ Trigger initiation of the Ansible node specified by the message entity. """)) @CommandExtension(name='ansible', extends=['sut'], config_options=[ ConfigOption(SUT, required=False), ConfigOption(ANSIBLE_PARALLEL_RUNS, required=False), ConfigOption(SUT_ANSIBLE_TEST_NODE, required=False), ], endpoints_and_messages={ INITIALIZE_ANSIBLE_SUTS_ENDPOINT: [INITIALIZE_ANSIBLE_NODE] },
'blocker.init.timeout', 'Timeout for init blocking.', option_type=float, default=5.0, hidden=True, application_contexts=ApplicationContext.EXTENDABLE) BLOCKER_ENDPOINT = EndpointId('blocker', 'Endpoint for blocker extension') StartBlockingInfo = namedtuple( 'StartBlockingInfo', ['message_id', 'endpoint_id', 'entity', 'timeout']) START_BLOCKING_ON_MESSAGE = MessageId( 'START_BLOCKING_ON_MESSAGE', """ Starts blocking on message described by the message data. Send as request to receive an ID that should be used as entity when sending the STOP_BLOCKING_ON_MESSAGE data: StartBlockingInfo """) STOP_BLOCKING_ON_MESSAGE = MessageId( 'STOP_BLOCKING_ON_MESSAGE', """ Stop blocking on message. This message should be sent with the ID that was received from START_BLOCKING_ON_MESSAGE as the entity. data: None """) BLOCKING_STARTED = MessageId( 'BLOCKING_STARTED', """ Event that is triggered when message that should be blocked on has been received.
at=entity) all_contexts = ConfigOptionId( 'all.contexts', 'Included in all application contexts', hidden=True, ) extendable_context = ConfigOptionId( 'extendable.context', 'Included in extendable application context', application_contexts=ApplicationContext.EXTENDABLE) internal_context = ConfigOptionId( 'internal.context', 'Included in internal application context', application_contexts=ApplicationContext.INTERNAL) m1 = MessageId('m1', 'm1 description\n\nm1 extended description\n') m2 = MessageId('m2', 'm2 description\n\nm2 extended description') m3 = MessageId('m3', 'm3 description\ncontinues') e1 = EndpointId('e1', 'e1 description') e2 = EndpointId('e2', 'e1 description\ncontinues\n\ne1 extended description\n') c1 = CommandId('c1', 'c1 description\n\nc1 extended description\n', lambda a: None, [ ConfigOption(bools, required=True), ConfigOption(extendable_context, required=True) ]) c2 = CommandId( 'c2', 'c2 description\nc2 description continue\n\nc2 extended description\n', lambda a: None,
import os from zaf.application.context import ApplicationContext from zaf.builtin.changelog import ChangeLogType from zaf.config.options import ConfigOptionId from zaf.config.types import Choice from zaf.messages.message import EndpointId, MessageId BEFORE_COMMAND = MessageId( 'BEFORE_COMMAND', """ Event triggered before the command has been started data: command name """) AFTER_COMMAND = MessageId( 'AFTER_COMMAND', """ Event triggered after the command has been finished data: command name """) APPLICATION_ENDPOINT = EndpointId( 'application', """ The Zaf application endpoint """) MESSAGEBUS_TIMEOUT = ConfigOptionId( 'application.messagebus.timeout', 'Specifies how long application should wait for the messagebus to finish on shutdown, in seconds', option_type=float,
'Generate a Z2 report', option_type=bool, default=False) Z2_REPORTS_FILE = ConfigOptionId( 'reports.z2.file', 'Write the report to this path. If no path is given the report will be stored in output_dir', default='${output.dir}/reports/z2/z2-results.json', option_type=Path()) Z2_REPORTS_URL = ConfigOptionId('reports.z2.url', 'Upload the report to this Z2 instance.') Z2_REPORTS_JOB_NAME = ConfigOptionId( 'reports.z2.job.name', 'Name of the job that initiated this K2 run.') Z2_REPORTS_BUILD_NUMBER = ConfigOptionId( 'reports.z2.build.number', 'Build number of the job that initiated this K2 run.', option_type=int) Z2_REPORTS_ENDPOINT = EndpointId('Z2_REPORTER_ENDPOINT', 'The Z2 reporter endpoint') Z2_INTERNAL_PUBLISH_REPORT_REQUEST = MessageId( 'Z2_INTERNAL_PUBLISH_REPORT_REQUEST', """\ Request sent internally to indicate when a report should be published. data: The Z2 report to publish. """)
'powerswitchcc.enabled', 'Should powerswitch connection check be enabled', at=SUT, option_type=bool, default=True) POWER_SWITCH_CONNECTION_CHECK_REQUIRED = ConfigOptionId( 'powerswitchcc.required', 'Require powerswitch connection to be working', at=SUT, option_type=bool, default=True) POWER_SWITCH_POWERON = MessageId( 'POWER_SWITCH_POWERON', """\ Makes sure that the power is on. exception if something failed """) POWER_SWITCH_POWEROFF = MessageId( 'POWER_SWITCH_POWEROFF', """\ Makes sure that the power is off. exception if something failed """) POWER_SWITCH_POWER_STATE = MessageId( 'POWER_SWITCH_POWER_STATE', """\ Check if the power is on response: True/False
from zaf.messages.message import EndpointId, MessageId RESULTS_ENDPOINT = EndpointId( 'results', """\ Collects test results and triggers TEST_RESULTS_COLLECTED when test run is completed """) TEST_RESULTS_COLLECTED = MessageId( 'TEST_RESULTS_COLLECTED', """\ Message that is triggered when the test run is completed with a complete collection of the test results data: k2.results.results.TestResult """)
from zaf.config.options import ConfigOptionId from zaf.messages.message import EndpointId, MessageId INSTANCES = ConfigOptionId('ids', 'description instance', multiple=True, namespace='instances', entity=True) MY_EXTENSION_ENDPOINT = EndpointId( 'MY_EXTENSION_ENDPOINT', """\ This is my extensions endpoint """) MY_EXTENSION_MESSAGE = MessageId( 'MY_EXTENSION_MESSAGE', """ This is my extensions message data: None """)
multiple=True, hidden=True) LOG_FILE_TYPE = ConfigOptionId( 'type', 'What type of log file to write. Choose from text or json', option_type=LOG_TYPE_CHOICE, default='text', at=LOG_FILES, hidden=True) LOG_END_POINT = EndpointId('logging', 'The Logging endpoint') ENTER_LOG_SCOPE = MessageId( 'ENTER_LOG_SCOPE', """ Entering log scope data: LogScopeMessageData """) EXIT_LOG_SCOPE = MessageId( 'EXIT_LOG_SCOPE', """ Exiting log scope data: LogScopeMessageData """) InternalLogScopeMessageData = namedtuple('InternalLogScopeMessageData', ['id', 'name', 'result']) class LogScopeMessageData(InternalLogScopeMessageData):
from zaf.builtin.blocker import BLOCKER_ENDPOINT, BLOCKING_COMPLETED, BLOCKING_STARTED, \ START_BLOCKING_ON_MESSAGE, STOP_BLOCKING_ON_MESSAGE, StartBlockingInfo from zaf.commands.command import CommandId from zaf.component.decorator import requires from zaf.extensions.extension import AbstractExtension, FrameworkExtension from zaf.messages.decorator import concurrent_dispatcher from zaf.messages.dispatchers import LocalMessageQueue from zaf.messages.message import EndpointId, MessageId BLOCK_MESSAGE = MessageId('BLOCK_MESSAGE', '') START = MessageId('START', '') CONTINUE = MessageId('CONTINUE', '') ENDPOINT = EndpointId('ENDPOINT', '') def remote_and_blocker_command(core): core.messagebus.send_request(START, receiver_endpoint_id=ENDPOINT) core.component_factory.call(_remote_and_blocker_command, core.session_scope) @requires(client='RemoteClient') def _remote_and_blocker_command(client): # Request that waits for CONTINUE to have been received by the test case # which indicates that test case message and endpoint have been defined client.send_request(CONTINUE, ENDPOINT).wait(timeout=1)[0].result(timeout=1) # Register the blocking and receive the blocking ID so that it can be used in the # local message queue registration blocking_id = client.send_request(
import pickle from zaf.messages.message import EndpointId, MessageId MESSAGE = MessageId('message', '') PICKLED_MESSAGE = pickle.dumps(MESSAGE) PICKLED_MESSAGES = pickle.dumps([MESSAGE]) ENDPOINT = EndpointId('endpoint', '') PICKLED_ENDPOINT = pickle.dumps(ENDPOINT) PICKLED_ENDPOINTS = pickle.dumps([ENDPOINT]) DATA = {'a': 'b', 3: 4, MESSAGE: ENDPOINT} PICKLED_DATA = pickle.dumps(DATA) ENTITY = 'entity' PICKLED_ENTITY = pickle.dumps(ENTITY) PICKLED_ENTITIES = pickle.dumps([ENTITY])
from zaf.config.options import ConfigOptionId from zaf.messages.message import EndpointId, MessageId TEST_SOURCES = ConfigOptionId( 'test.sources', 'One or more test sources. Can be files, modules, classes etc', multiple=True, argument=True) FINDER_ENDPOINT = EndpointId('testfinder', """\ The test finder """) FIND_TEST_CASES = MessageId( 'FIND_TEST_CASES', """\ Request to find test cases. returns: List of TestCase """)
from zaf.config.options import ConfigOptionId from zaf.messages.message import EndpointId, MessageId METRICS_ENDPOINT = EndpointId('metrics', """\ The K2 metrics addon endpoint. """) CREATE_METRIC = MessageId( 'CREATE_METRIC', """ Store a metric. data: A metrics.messages.RegisterMetric instance. """) COLLECT_METRICS_REQUEST = MessageId( 'COLLECT_METRICS_REQUEST', """ Retreive metrics collected so far. data: A metrics.messages.CollectMetrics instance. """) GENERATE_METRICS_AGGREGATE = MessageId( 'GENERATE_METRICS_AGGREGATE', """ Request that metrics aggregates are generated. data: None """) GENERATE_METRICS_REPORT = MessageId( 'GENERATE_METRICS_REPORT', """ Request that metrics reports are generated.
POWER_METER = ConfigOptionId('powermeter', 'The type of the power meter', at=SUT, option_type=ConfigChoice(AVAILABLE_POWER_METERS)) POWER_METER_CONNECTION_CHECK_ENDPOINT = EndpointId( 'powermetercc', 'Endpoint for power meter connection check') POWER_METER_CONNECTION_CHECK_ENABLED = ConfigOptionId( 'powermetercc.enabled', 'Should powermeter connection check be enabled', at=SUT, option_type=bool, default=True) POWER_METER_CONNECTION_CHECK_REQUIRED = ConfigOptionId( 'powermetercc.required', 'Require powermeter connection to be working', at=SUT, option_type=bool, default=True) POWER_METER_POWER = MessageId( 'POWER_METER_POWER', """\ Check current power consumption response: True/False exception if something failed """)
forward_signals=False) MAKE_ARGUMENTS = ConfigOptionId( 'arguments', 'The arguments to make.', multiple=True, namespace='make', argument=True, ) MAKE_COMMAND = CommandId( 'make', make.__doc__, make, config_options=[ ConfigOption(MAKE_ARGUMENTS, required=True), ], allow_unknown_options=True, ) MAKE_ENDPOINT = EndpointId('MAKE_ENDPOINT', 'Endpoint for the make command') PRE_MAKE = MessageId('PRE_MAKE', 'Event triggered before make is executed.') @FrameworkExtension('makecommand', commands=[MAKE_COMMAND], endpoints_and_messages={MAKE_ENDPOINT: [PRE_MAKE]}) class MakeExtension(AbstractExtension): pass