Run Fediverse system tests with your application in a UBOS container

https://feditest.org/quickstart/fediverse-developer/app-on-ubos/

Here is an outline of the steps you need to take so your own Fediverse App can be tested like Mastodon is in the system test setups described in Getting a taste of FediTest. Just like there, this allows you to run your own App against itself, but also against other apps like Mastodon or WordPress with the plugins.

Step 1: Package your app for UBOS

This involves creating an Arch Linux package for it with extra metadata, and template files or scripts that can parameterize the configuration so that UBOS Gears can successfully deploy your App at any hostname.

The ubos.net website has tutorials for how to do that.

The essence of the packaging is the creation of these two files, as in this example of a minimal web application that uses a MySQL database:

  • PKGBUILD: package build file for the package (bash, from Arch Linux)
  • ubos-manifest.json: declares the files, web server configuration, database and the like that the application needs.

If your App is already available in a Docker container, these files may be even simpler. (We’ll write documentation for how to do this once we have a real-world example for this configuration.)

As a side effect, your App can now also be installed, uninstalled, backed up, and restored with a single command each, which may be an attractive feature anyway independent of FediTest.

Step 2: Create a NodeDriver implementation class for your app

When you specify Nodes in test Constellations, you specify a Node Driver like this:

{
    "nodedriver" : "MastodonUbosNodeDriver"
}

This name refers to a Python class that implements the FediTest NodeDriver abstract class (in src/feditest/nodedrivers/__init__.py). This NodeDriver abstract class defines a handful of methods that need to implemented for your App so FediTest can get an instance of your App up and running, and also take it back down.

As we are using UBOS Gears, you can subclass UbosNodeDriver which provides a lot of the required code already. As an example, you can use the MastodonUbosNodeDriver (which is found in src/feditest/nodedrivers/mastodon/ubos.py). Implement something similar that works for your App.

Step 3: Create a Node implementation class for your app

The NodeDriver class wants to instantiate a subclass of Node in its _instantiate_ubos_node() method. You need to implement a subclass of Node for your App, too.

Class Node has many (abstract) subclasses, each of which provides methods that allow FediTest scripts to make the Node do something, or report back an observation. There is one such subclass per protocol. If, for example, you want your Node to be tested as a WebFinger server, you implement Node subclass WebFingerServer. If it is a full-fledged Fediverse Node, you implement subclass FediverseNode (that inherits from WebFingerServer), as class MastodonNode does.

This can be a little involved, because there are many things tests want to test. If your App implements the Mastodon API, you are in relative luck, because you can simply reuse the NodeWithMastodonAPI class, as we do in the support for WordPress (see class WordPressPlusPluginsUbosNode).

If you have some other API to your App, you can use that. If not, in the future we are thinking of creating a JSON-RPC (client-side) implementation of FediverseNode: that would make it possible for you to add a single new route to your web App, from which you can invoke the internals of your App. (Let us know what you think of that idea.)

However, you can implement as many or as few methods in FediverseNode as you like. If you don’t implement them all, this means that either you can’t run tests that require an implementation of that method, or you need to manually perform the action during the test run.

For example, if you were to not implement method like_object() in FediverseNode, a test cannot automatically make your App “like” a “Note”, and FediTest would skip those tests that try to do that: the current default implementation of like_object() raises a NotImplementedByNodeError, which causes the skip. Alternatively, you could implement this method simply by asking the user to perform the action manually with their web browser, and hit return when done. The FallbackFediverseNode implementation of FediverseNode does this for most methods.

In fact, you might want to start your implementation of Node by simply returning an instance of FallbackFediverseNode from your NodeDriver: that way, you can see whether the setup works and FediTest runs, even if you have to initially perform test actions and observations manually. Over time, you can then implement automated versions of the same methods.