Skip to content

Plugins

Vladislav Alekseev edited this page Dec 30, 2019 · 13 revisions

Emcee supports plugins for both workers and queue processes. Plugins do not alter any logic of Emcee, but they can listen to the events and react to them accordingly.

Possible use cases for plugins:

  • Integrate your tests with your test management system - for example, update test statuses in your TMS when test finishes.

  • Record videos of tests: e.g. you may develop a logic to purge video if test succeeds, and upload video to your internal storage if test fails, for further investigation. Use SimulatorVideoRecorder module for that.

Implementing plugin

It is convenient to develop Emcee plugins as Swift packages.

Plugin module

This is a base module for implementing Emcee plugin. In your Package.swift, import the library that has all required APIs to implement a plugin:

dependencies: [
    .package(url: "https://github.com/avito-tech/Emcee", .branch("master"))
]

In your plugin target add EmceePlugin dependency:

targets: [
    .target(
        name: "TestPlugin",
        dependencies: [
            "EmceePlugin"
        ]
    )
]

Creating your listener

Plugin will listen to Emcee event bus via EventStream instance. Emcee provides DefaultBusListener open class for your convenience (available is EventBus module). Subclass it and override its methods to receive corresponding events.

Example implementation of capturing commonly used events related to test execution flow.

import EventBus
import Models
import Plugin

class MyPluginListener: DefaultBusListener {
    override func runnerEvent(_ event: RunnerEvent) {
        switch event {
        case .willRun(let testEntries, let testContext):
            // will be called when Emcee is preparing to run a set of tests (bucket)
            break
        case .didRun(let testEntryResults, let testContext):
            // will be called when Emcee finish running a set of tests and already has test results
            break
        case .testStarted(let testEntry, let testContext):
            // will be called when test has started
            break
        case .testFinished(let testEntry, let succeeded, let testContext):
            // will be called when test has finished
            break
        }
    }
}

Plugin can take advantage from TestContext object passed into most events - it describes the test environment.

Wiring up the plugin

Since any plugin is an regular executable, you will need to provide main.swift file - your executable entry point. It may contain the following code:

import EventBus
import LoggingSetup
import Plugin

// Make use of Emcee logging - logs will be written to a hosting machine, at ~/Library/Logs/ru.avito.emcee.logs/Plugin/
try LoggingSetup.setupLogging(stderrVerbosity: Verbosity.debug)

// Create an event bus that will get the events from the Emcee
let eventBus = EventBus()

// Subscribe to the event bus by providing your instance of EventStream: 
eventBus.add(stream: MyPluginListener())

// Plugin class will stream all events into event bus:
let plugin = Plugin(eventBus: eventBus)
plugin.streamPluginEvents()

// Wait for plugin to finish:
plugin.join()

Preparing plugin bundle

First, build your plugin using swift build command.

Emcee expects all plugins to have the following bundle structure:

YourPlugin.emceeplugin/
                       Plugin   <-- your plugin executable

You can use some basic Bash skills to prepare bundle and ZIP it:

#!/bin/bash

set -e

pluginName="YourPlugin.emceeplugin"
pluginPath=".build/debug/$pluginName/"
rm -rf "$pluginPath"
mkdir -p "$pluginPath"
cp .build/debug/Plugin "$pluginPath"

cd "$pluginPath/../"
rm -rf "$pluginName".zip
zip -r "$pluginName".zip "$pluginName"

Using your plugin

You should upload your YourPlugin.zip to your web server. Then you can declare URL to this file as plugins value of queue server configuration.

Clone this wiki locally