Skip to content

Embedding the server

veriCue works by embedding a small TCP server into the application under test. This page covers wiring it into your build, configuring authentication and licensing, and - importantly - keeping it out of your production binaries.

Just evaluating?

To try veriCue against an existing Qt binary without touching your build at all, use vericue-inject - it starts the server inside an unmodified app via LD_PRELOAD (Linux, evaluation only). Embedding, below, is the production path.

With the veriCue SDK installed (see Installation), add to your CMakeLists.txt:

cmake
find_package(vericue REQUIRED)

target_link_libraries(my-app PRIVATE vericue::vericue-server)

If CMake can't find the package, point it at the install prefix:

bash
cmake -B build -DCMAKE_PREFIX_PATH="/usr/local;/path/to/Qt/6.7/gcc_64"

2. Start the server

Create a VeriCueServer after your main window exists and start it:

cpp
#include <vericue/server.h>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QMainWindow window;
    window.setObjectName("MainWindow");
    // ... build your UI ...

    vericue::VeriCueServer server(&window);   // parented - cleaned up with the window
    if (!server.start(4242)) {
        qWarning("veriCue server failed to start");
    }

    window.show();
    return app.exec();
}

Notes:

  • start(0) lets the OS pick a free port; read it back with server.serverPort(). Useful for parallel CI jobs - print it to stdout so the test harness can discover it (the bundled test app prints VERICUE_PORT=<port>).
  • The constructor takes an optional QObject* parent. Parenting to your main window ties the server's lifetime to the UI.
  • started() / stopped() / errorOccurred(QString) signals are available if you want to log or react to lifecycle events.
  • Works for QWidget and QML applications alike. For QML, use a build of the server library with Qt Quick support (auto-detected at build time).

3. Name your objects

Clients address objects by path, e.g. MainWindow/centralWidget/okButton. Path segments use QObject::objectName(), falling back to ClassName#N for unnamed objects. Unnamed-object paths break when the UI changes, so:

cpp
okButton->setObjectName("okButton");

Give stable objectNames to every widget you intend to automate. In QML, set the objectName property.

4. Authentication

cpp
server.setAuthToken(qEnvironmentVariable("MYAPP_VERICUE_TOKEN"));

When a token is set, clients must present it during the handshake; connections with a missing or wrong token are rejected. Read the token from the environment or a config file - don't hardcode secrets.

5. Licensing

Without any license configuration the server runs in 30-day trial mode. For licensed use, pick one:

cpp
// Organization license: RSA-signed JSON key file (from your license email / portal)
server.setLicenseFile("/etc/myapp/vericue-license.json");

// Floating: lease a session from your self-hosted LAN license server
server.setLicenseServer("licenses.internal.example.com", 5252);

Licensing is fully offline - the server never phones home. Session accounting differs by mode: with an organization key file (or trial), each connected client occupies one concurrent automation session while connected; with a floating license, the application process checks out one lease from the pool at start() and holds it (with heartbeats) until it exits. When a license expires (trial or paid), the server keeps answering handshake, ping and version but refuses everything else. See Trial & paid tiers.

6. Compile it out of release builds

The veriCue server is a test-time tool. Don't ship it in production binaries: it opens a TCP port into your application's internals. The recommended pattern is a dedicated build option:

cmake
option(ENABLE_VERICUE "Embed the veriCue automation server" OFF)

if(ENABLE_VERICUE)
    find_package(vericue REQUIRED)
    target_link_libraries(my-app PRIVATE vericue::vericue-server)
    target_compile_definitions(my-app PRIVATE MYAPP_WITH_VERICUE)
endif()
cpp
#ifdef MYAPP_WITH_VERICUE
#include <vericue/server.h>
#endif

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QMainWindow window;
    // ...

#ifdef MYAPP_WITH_VERICUE
    vericue::VeriCueServer server(&window);
    server.setAuthToken(qEnvironmentVariable("MYAPP_VERICUE_TOKEN"));
    server.start(4242);
#endif

    window.show();
    return app.exec();
}

Your QA/CI builds configure with -DENABLE_VERICUE=ON; release builds don't reference veriCue at all - no linked library, no open port, nothing to audit in the shipped artifact.

Security model

Be deliberate about where the automation port is reachable:

  • The server listens on all network interfaces - there is currently no bind-address option. On a developer machine or CI runner that's usually fine; on a shared network it means anyone who can reach the port can drive your application.
  • Transport is plaintext TCP (length-prefixed JSON). There is no TLS. Treat the port like a local debug interface, not a network service.
  • A connected client can read widget contents, click anything, invoke methods and take screenshots - full control of the UI.

Recommendations, in order of importance:

  1. Only embed in test builds (compile-out pattern above). The strongest control is the port not existing.
  2. Always set an auth token outside single-developer machines.
  3. Firewall the port to localhost or the CI subnet.
  4. For remote debugging across machines, tunnel instead of exposing: ssh -L 4242:localhost:4242 testrig and connect to localhost.
  5. Never expose the port on an untrusted or public network.

Released under a commercial licence. Privacy · Terms