Skip to content
Snippets Groups Projects
Unverified Commit cdb42f0d authored by Kali Kaneko's avatar Kali Kaneko
Browse files

[test] minimal qml tests

just a minimal boilerplate. the idea is to import the qml files and
assert that the states/widgets change accordingly if we mock the backend
status.

- Closes: #300
parent 4de5748e
No related branches found
No related tags found
No related merge requests found
......@@ -14,8 +14,8 @@ VERSION ?= $(shell git describe)
# go paths
GOPATH = $(shell go env GOPATH)
SYSTRAY = 0xacab.org/leap/bitmask-vpn
GOSYSTRAY = ${GOPATH}/src/${SYSTRAY}
TARGET_GOLIB=lib/libgoshim.a
SOURCE_GOLIB=gui/backend.go
# detect OS, we use it for dependencies
UNAME = $(shell uname -s)
......@@ -81,6 +81,15 @@ build_%:
test:
@go test -tags "integration $(TAGS)" ./...
golib:
CGO_ENABLED=1 go build -buildmode=c-archive -o ${TARGET_GOLIB} ${SOURCE_GOLIB}
test_ui: golib
@qmake -o tests/Makefile test.pro
@make -C tests clean
@make -C tests
@./tests/build/test_ui
build_win:
powershell -Command '$$version=git describe --tags; go build -ldflags "-H windowsgui -X main.version=$$version" ./cmd/*'
......
......@@ -41,6 +41,14 @@ Linux
./build.sh
Running tests
-------------
sudo apt install qml-module-qttest
make test
make test_ui
i18n
----
......
......@@ -33,7 +33,6 @@ MOC_DIR = release/.moc
RCC_DIR = release/.rcc
UI_DIR = release/.ui
Release:DESTDIR = release
Release:DESTDIR = release
Release:OBJECTS_DIR = release/.obj
Release:MOC_DIR = release/.moc
......
......@@ -44,7 +44,16 @@ func SubscribeToEvent(event string, f unsafe.Pointer) {
//export InitializeBitmaskContext
func InitializeBitmaskContext() {
backend.InitializeBitmaskContext()
opts := &backend.InitOpts{}
backend.InitializeBitmaskContext(opts)
}
//export InitializeTestBitmaskContext
func InitializeTestBitmaskContext() {
opts := &backend.InitOpts{}
opts.SkipLaunch = true
backend.InitializeBitmaskContext(opts)
backend.EnableMockBackend()
}
//export RefreshContext
......
......@@ -9,7 +9,7 @@ ApplicationWindow {
id: app
visible: false
property var ctx
property var ctx
Connections {
target: jsonModel
......
......@@ -45,10 +45,18 @@ func SubscribeToEvent(event string, f unsafe.Pointer) {
subscribe(event, f)
}
func InitializeBitmaskContext() {
type InitOpts struct {
Provider string
AppName string
SkipLaunch bool
}
func InitializeBitmaskContext(opts *InitOpts) {
p := bitmask.GetConfiguredProvider()
opts.Provider = p.Provider
opts.AppName = p.AppName
initOnce.Do(func() { initializeContext(p.Provider, p.AppName) })
initOnce.Do(func() { initializeContext(opts) })
runDonationReminder()
go ctx.updateStatus()
}
......@@ -62,7 +70,7 @@ func InstallHelpers() {
pickle.InstallHelpers()
}
func MockUIInteraction() {
log.Println("mocking ui interaction on port 8080. \nTry 'curl localhost:8080/{on|off|failed}' to toggle status.")
go mockUI()
func EnableMockBackend() {
log.Println("[+] Mocking ui interaction on port 8080. \nTry 'curl localhost:8080/{on|off|failed}' to toggle status.")
go enableMockBackend()
}
......@@ -12,11 +12,11 @@ import (
// initializeContext initializes an empty connStatus and assigns it to the
// global ctx holder. This is expected to be called only once, so the public
// api uses the sync.Once primitive to call this.
func initializeContext(provider, appName string) {
func initializeContext(opts *InitOpts) {
var st status = off
ctx = &connectionCtx{
AppName: appName,
Provider: provider,
AppName: opts.AppName,
Provider: opts.Provider,
TosURL: config.TosURL,
HelpURL: config.HelpURL,
DonateURL: config.DonateURL,
......@@ -28,7 +28,7 @@ func initializeContext(provider, appName string) {
errCh := make(chan string)
go trigger(OnStatusChanged)
go checkErrors(errCh)
initializeBitmask(errCh)
initializeBitmask(errCh, opts)
}
func checkErrors(errCh chan string) {
......@@ -39,14 +39,14 @@ func checkErrors(errCh chan string) {
}
}
func initializeBitmask(errCh chan string) {
func initializeBitmask(errCh chan string, opts *InitOpts) {
if ctx == nil {
log.Println("bug: cannot initialize bitmask, ctx is nil!")
os.Exit(1)
}
bitmask.InitializeLogger()
b, err := bitmask.InitializeBitmask()
b, err := bitmask.InitializeBitmask(opts.SkipLaunch)
if err != nil {
log.Println("error: cannot initialize bitmask")
errCh <- err.Error()
......
......@@ -9,6 +9,14 @@ import (
* should also show a good way of writing functionality tests just for the Qml
* layer */
func enableMockBackend() {
log.Println("[+] You should not use this in production!")
http.HandleFunc("/on", mockUIOn)
http.HandleFunc("/off", mockUIOff)
http.HandleFunc("/failed", mockUIFailed)
http.ListenAndServe(":8080", nil)
}
func mockUIOn(w http.ResponseWriter, r *http.Request) {
log.Println("changing status: on")
setStatus(on)
......@@ -23,10 +31,3 @@ func mockUIFailed(w http.ResponseWriter, r *http.Request) {
log.Println("changing status: failed")
setStatus(failed)
}
func mockUI() {
http.HandleFunc("/on", mockUIOn)
http.HandleFunc("/off", mockUIOff)
http.HandleFunc("/failed", mockUIFailed)
http.ListenAndServe(":8080", nil)
}
......@@ -56,14 +56,18 @@ func initBitmask(printer *message.Printer) (Bitmask, error) {
return b, err
}
func InitializeBitmask() (Bitmask, error) {
func InitializeBitmask(skipLaunch bool) (Bitmask, error) {
if skipLaunch {
log.Println("Initializing bitmask, but not launching it...")
}
if _, err := os.Stat(config.Path); os.IsNotExist(err) {
os.MkdirAll(config.Path, os.ModePerm)
}
err := pid.AcquirePID()
if err != nil {
log.Fatal(err)
log.Println("Error acquiring PID:", err)
return nil, err
}
defer pid.ReleasePID()
......@@ -75,13 +79,21 @@ func InitializeBitmask() (Bitmask, error) {
return nil, err
}
err = checkAndStartBitmask(b, conf)
err = setTransport(b, conf)
if err != nil {
return nil, err
}
if !skipLaunch {
err := maybeStartVPN(b, conf)
if err != nil {
log.Println("Error starting VPN: ", err)
return nil, err
}
}
var as Autostart
if conf.DisableAustostart {
if skipLaunch || conf.DisableAustostart {
as = &dummyAutostart{}
} else {
as = newAutostart(config.ApplicationName, "")
......@@ -103,7 +115,7 @@ func initPrinter() *message.Printer {
return message.NewPrinter(message.MatchLanguage(locale, "en"))
}
func checkAndStartBitmask(b Bitmask, conf *config.Config) error {
func setTransport(b Bitmask, conf *config.Config) error {
if conf.Obfs4 {
err := b.UseTransport("obfs4")
if err != nil {
......@@ -111,12 +123,6 @@ func checkAndStartBitmask(b Bitmask, conf *config.Config) error {
return err
}
}
err := maybeStartVPN(b, conf)
if err != nil {
log.Println("Error starting VPN: ", err)
return err
}
return nil
}
......
test.pro 0 → 100644
TEMPLATE = app
TARGET = test_ui
CONFIG += warn_on qmltestcase
SOURCES += \
tests/test_ui.cpp \
gui/qjsonmodel.cpp \
gui/handlers.cpp
HEADERS += \
lib/libgoshim.h \
gui/qjsonmodel.h \
gui/handlers.h
LIBS += -L../lib -lgoshim -lpthread
DESTDIR = build
OBJECTS_DIR = build/.obj
RCC_DIR = build/.rcc
UI_DIR = build/.ui
Release:DESTDIR = build
Release:OBJECTS_DIR = build/.obj
Release:RCC_DIR = build/.rcc
Release:UI_DIR = build/.ui
build/*
*.h
*.sh
*.moc
*.o
*.stash
Makefile
test_ui
moc_handlers.cpp
moc_qjsonmodel.cpp
// test_ui.cpp
#include <QtQuickTest>
#include <QQmlEngine>
#include <QQmlContext>
#include "../gui/qjsonmodel.h"
#include "../lib/libgoshim.h"
class Helper : public QObject
{
Q_OBJECT
public:
explicit Helper(QObject *parent = 0);
public slots:
Q_INVOKABLE QString refreshContext();
};
Helper::Helper(QObject *parent) : QObject(parent)
{
}
Q_INVOKABLE QString Helper::refreshContext()
{
return QString(RefreshContext());
}
class Setup : public QObject
{
Q_OBJECT
public:
Setup() {}
public slots:
void qmlEngineAvailable(QQmlEngine *engine)
{
QQmlContext *ctx = engine->rootContext();
QJsonModel *model = new QJsonModel;
Helper *helper = new Helper(this);
InitializeTestBitmaskContext();
ctx->setContextProperty("jsonModel", model);
ctx->setContextProperty("helper", helper);
}
};
QUICK_TEST_MAIN_WITH_SETUP(ui, Setup)
#include "test_ui.moc"
import QtQuick 2.3
import QtTest 1.0
TestCase {
name: "SmokeTests"
property var ctx
function refresh() {
ctx = JSON.parse(helper.refreshContext())
}
function test_helper() {
compare(Boolean(helper), true, "does helper exist?")
}
function test_model() {
compare(Boolean(jsonModel), true, "does model exist?")
}
function test_loadCtx() {
refresh()
compare(ctx.appName, "RiseupVPN", "can read appName?")
compare(ctx.tosURL, "https://riseup.net/tos", "can read tosURL?")
compare(ctx.status, "off", "is initial status off?")
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment