feat: add tests for qml only and qml with qt backends modules

This commit is contained in:
Khushboo Mehta
2026-04-10 19:05:23 +02:00
parent 539f555c64
commit 77776b9ae3
10 changed files with 279 additions and 0 deletions
+120
View File
@@ -12,6 +12,7 @@
outputs = { self, logos-nix, logos-module-builder, logos-liblogos, logos-logoscore-cli, nixpkgs }:
let
mkModule = logos-module-builder.lib.mkLogosModule;
mkQmlModule = logos-module-builder.lib.mkLogosQmlModule;
basic = mkModule {
src = ./test-basic-module;
@@ -63,6 +64,19 @@
'';
};
qmlOnly = mkQmlModule {
src = ./test-qml-only-module;
configFile = ./test-qml-only-module/metadata.json;
};
qmlBackend = mkQmlModule {
src = ./test-qml-backend-module;
configFile = ./test-qml-backend-module/metadata.json;
flakeInputs = {
test_basic_module = basic;
};
};
systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
forAllSystems = fn: nixpkgs.lib.genAttrs systems fn;
in {
@@ -75,6 +89,8 @@
test_ipc_module = ipc.packages.${system}.default;
test_ipc_new_api_module = ipc-new-api.packages.${system}.default;
test_dummy_module = dummy.packages.${system}.default;
test_qml_only = qmlOnly.packages.${system}.default;
test_qml_backend = qmlBackend.packages.${system}.default;
# Convenience alias: `nix build .#tests` runs the integration test suite
tests = self.checks.${system}.tests;
@@ -146,6 +162,110 @@
echo "Tests completed successfully."
'';
# QML module build + packaging verification
# Uses the install outputs from mkLogosQmlModule (lgpm is run internally
# by nix-bundle-logos-module-install, no direct lgpm dependency needed).
qml-modules = pkgs.runCommand "logos-test-qml-modules" {
nativeBuildInputs = [ pkgs.jq ];
} ''
set -euo pipefail
echo "=== QML Module Tests ==="
# --- QML-only module ---
echo "Testing QML-only module build..."
defaultPkg="${qmlOnly.packages.${system}.default}"
test -f "$defaultPkg/Main.qml"
echo "PASS: QML-only default has Main.qml"
test -f "$defaultPkg/metadata.json"
echo "PASS: QML-only default has metadata.json"
type=$(jq -r '.type' "$defaultPkg/metadata.json")
test "$type" = "ui_qml"
echo "PASS: QML-only type is ui_qml"
view=$(jq -r '.view' "$defaultPkg/metadata.json")
test "$view" = "Main.qml"
echo "PASS: QML-only view is Main.qml"
# Verify LGX package exists
qmlOnlyLgx="${qmlOnly.packages.${system}.lgx}"
test -f "$qmlOnlyLgx"/*.lgx
echo "PASS: QML-only LGX package exists"
# Verify install output (produced by nix-bundle-logos-module-install)
qmlOnlyInstall="${qmlOnly.packages.${system}.install}"
manifest=$(find "$qmlOnlyInstall" -name "manifest.json" | head -1)
test -n "$manifest"
echo "PASS: QML-only install has manifest.json"
mtype=$(jq -r '.type' "$manifest")
test "$mtype" = "ui_qml"
echo "PASS: installed manifest type is ui_qml"
mview=$(jq -r '.view' "$manifest")
test "$mview" = "Main.qml"
echo "PASS: installed manifest has view field"
# --- QML + backend module ---
echo ""
echo "Testing QML + backend module build..."
backendDefault="${qmlBackend.packages.${system}.default}"
test -d "$backendDefault/lib"
echo "PASS: backend default has lib/ directory"
test -f "$backendDefault/lib/metadata.json"
echo "PASS: backend lib/ has metadata.json"
# Check for plugin .so/.dylib
pluginCount=$(find "$backendDefault/lib" -name "test_qml_backend_plugin.*" | wc -l)
test "$pluginCount" -gt 0
echo "PASS: backend plugin library exists"
# Check for replica factory
factoryCount=$(find "$backendDefault/lib" -name "test_qml_backend_replica_factory.*" | wc -l)
test "$factoryCount" -gt 0
echo "PASS: replica factory plugin exists"
# Check QML view is bundled
test -f "$backendDefault/lib/qml/Main.qml"
echo "PASS: QML view bundled in lib/qml/"
# Verify LGX package exists
backendLgx="${qmlBackend.packages.${system}.lgx}"
test -f "$backendLgx"/*.lgx
echo "PASS: backend LGX package exists"
# Verify install output
backendInstall="${qmlBackend.packages.${system}.install}"
bmanifest=$(find "$backendInstall" -name "manifest.json" | head -1)
test -n "$bmanifest"
echo "PASS: backend install has manifest.json"
btype=$(jq -r '.type' "$bmanifest")
test "$btype" = "ui_qml"
echo "PASS: backend manifest type is ui_qml"
bview=$(jq -r '.view' "$bmanifest")
test "$bview" = "qml/Main.qml"
echo "PASS: backend manifest has view field"
bmain=$(jq '.main | length' "$bmanifest")
test "$bmain" -gt 0
echo "PASS: backend manifest has main entries"
echo ""
echo "All QML module tests passed."
mkdir -p $out
echo "passed" > $out/results.txt
'';
# NOTE: QML backend → core module IPC tests require logos-standalone-app
# (ui-host process) which is not available in the headless test environment.
# The backend plugin is tested structurally (build, LGX, manifest) by
# qml-modules above. Runtime IPC is verified manually via:
# ws run logos-standalone-app --local ... -l test_qml_backend
# Async-only tests (validates invokeRemoteMethodAsync + generated wrappers)
async-tests = pkgs.runCommand "logos-test-modules-async-tests" {
nativeBuildInputs = [
+17
View File
@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.14)
project(TestQmlBackendPlugin LANGUAGES CXX)
if(DEFINED ENV{LOGOS_MODULE_BUILDER_ROOT})
include($ENV{LOGOS_MODULE_BUILDER_ROOT}/cmake/LogosModule.cmake)
else()
message(FATAL_ERROR "LogosModule.cmake not found. Set LOGOS_MODULE_BUILDER_ROOT.")
endif()
logos_module(
NAME test_qml_backend
REP_FILE src/test_qml_backend.rep
SOURCES
src/test_qml_backend_interface.h
src/test_qml_backend_plugin.h
src/test_qml_backend_plugin.cpp
)
+16
View File
@@ -0,0 +1,16 @@
{
"name": "test_qml_backend",
"version": "1.0.0",
"type": "ui_qml",
"category": "testing",
"description": "Test module — ui_qml with C++ backend and .rep interface",
"main": "test_qml_backend_plugin",
"view": "qml/Main.qml",
"dependencies": ["test_basic_module"],
"nix": {
"packages": { "build": [], "runtime": [] },
"external_libraries": [],
"cmake": { "find_packages": [], "extra_sources": [] }
}
}
+12
View File
@@ -0,0 +1,12 @@
import QtQuick
Item {
id: root
readonly property var backend: logos.module("test_qml_backend")
Text {
anchors.centerIn: parent
text: backend ? "Backend status: " + backend.status : "Connecting..."
color: "#ffffff"
}
}
@@ -0,0 +1,6 @@
class TestQmlBackend
{
PROP(QString status READWRITE)
SLOT(int add(int a, int b))
SLOT(QString echo(QString msg))
}
@@ -0,0 +1,12 @@
#pragma once
#include <QObject>
#include <QString>
#include "interface.h"
class TestQmlBackendInterface : public PluginInterface {
public:
virtual ~TestQmlBackendInterface() = default;
};
#define TestQmlBackendInterface_iid "logos.test.qml_backend/1.0"
Q_DECLARE_INTERFACE(TestQmlBackendInterface, TestQmlBackendInterface_iid)
@@ -0,0 +1,33 @@
#include "test_qml_backend_plugin.h"
#include "logos_api.h"
#include "logos_sdk.h"
#include <QDebug>
TestQmlBackendPlugin::TestQmlBackendPlugin(QObject* parent)
: TestQmlBackendSimpleSource(parent) {}
TestQmlBackendPlugin::~TestQmlBackendPlugin() { delete m_logos; }
void TestQmlBackendPlugin::initLogos(LogosAPI* api)
{
if (m_logos) return;
m_logosAPI = api;
m_logos = new LogosModules(api);
setBackend(this);
setStatus("Ready");
qDebug() << "TestQmlBackendPlugin: initialized";
}
int TestQmlBackendPlugin::add(int a, int b)
{
// Call test_basic_module.add() via the typed SDK — proves backend → core IPC
int result = m_logos->test_basic_module.add(a, b);
setStatus(QStringLiteral("%1 + %2 = %3 (via test_basic_module)").arg(a).arg(b).arg(result));
return result;
}
QString TestQmlBackendPlugin::echo(QString msg)
{
setStatus(QStringLiteral("echo: %1").arg(msg));
return msg;
}
@@ -0,0 +1,38 @@
#pragma once
#include <QString>
#include <QVariantList>
#include "test_qml_backend_interface.h"
#include "LogosViewPluginBase.h"
#include "rep_test_qml_backend_source.h"
class LogosAPI;
class LogosModules;
class TestQmlBackendPlugin : public TestQmlBackendSimpleSource,
public TestQmlBackendInterface,
public TestQmlBackendViewPluginBase
{
Q_OBJECT
Q_PLUGIN_METADATA(IID TestQmlBackendInterface_iid FILE "metadata.json")
Q_INTERFACES(TestQmlBackendInterface)
public:
explicit TestQmlBackendPlugin(QObject* parent = nullptr);
~TestQmlBackendPlugin() override;
QString name() const override { return "test_qml_backend"; }
QString version() const override { return "1.0.0"; }
Q_INVOKABLE void initLogos(LogosAPI* api);
// Slots from .rep — call test_basic_module via LogosModules SDK
int add(int a, int b) override;
QString echo(QString msg) override;
signals:
void eventResponse(const QString& eventName, const QVariantList& args);
private:
LogosAPI* m_logosAPI = nullptr;
LogosModules* m_logos = nullptr;
};
+10
View File
@@ -0,0 +1,10 @@
import QtQuick
Item {
id: root
Text {
anchors.centerIn: parent
text: "QML-only test module"
color: "#ffffff"
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"name": "test_qml_only",
"version": "1.0.0",
"type": "ui_qml",
"category": "testing",
"description": "Test module — QML-only ui_qml (no backend)",
"view": "Main.qml",
"dependencies": [],
"nix": {
"packages": { "build": [], "runtime": [] },
"external_libraries": [],
"cmake": { "find_packages": [], "extra_sources": [] }
}
}