summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkali kaneko (leap communications) <kali@leap.se>2020-06-18 20:42:29 +0200
committerkali kaneko (leap communications) <kali@leap.se>2020-06-26 12:17:30 +0200
commitcdb42f0d6b47a60ceb647e3ac6a6ce66352dbae4 (patch)
tree40f76de30181eb1036d44516e5dd05488c8c31dc
parent4de5748e25678dce9c5a344afc5fd40508c0860f (diff)
[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
-rw-r--r--Makefile13
-rw-r--r--README.md8
-rw-r--r--bitmask.pro1
-rw-r--r--gui/backend.go11
-rw-r--r--gui/qml/main.qml2
-rw-r--r--pkg/backend/api.go18
-rw-r--r--pkg/backend/init.go12
-rw-r--r--pkg/backend/mocks.go15
-rw-r--r--pkg/bitmask/init.go28
-rw-r--r--test.pro26
-rw-r--r--tests/.gitignore10
-rw-r--r--tests/test_ui.cpp52
-rw-r--r--tests/tst_smoke.qml28
13 files changed, 190 insertions, 34 deletions
diff --git a/Makefile b/Makefile
index 28d009c..7d284b4 100644
--- a/Makefile
+++ b/Makefile
@@ -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/*'
diff --git a/README.md b/README.md
index 0759369..cb20665 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,14 @@ Linux
./build.sh
+Running tests
+-------------
+
+sudo apt install qml-module-qttest
+make test
+make test_ui
+
+
i18n
----
diff --git a/bitmask.pro b/bitmask.pro
index 115aec7..7a29483 100644
--- a/bitmask.pro
+++ b/bitmask.pro
@@ -34,7 +34,6 @@ RCC_DIR = release/.rcc
UI_DIR = release/.ui
Release:DESTDIR = release
-Release:DESTDIR = release
Release:OBJECTS_DIR = release/.obj
Release:MOC_DIR = release/.moc
Release:RCC_DIR = release/.rcc
diff --git a/gui/backend.go b/gui/backend.go
index f7816ee..4a73cc2 100644
--- a/gui/backend.go
+++ b/gui/backend.go
@@ -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
diff --git a/gui/qml/main.qml b/gui/qml/main.qml
index efe0111..4aab7f1 100644
--- a/gui/qml/main.qml
+++ b/gui/qml/main.qml
@@ -9,7 +9,7 @@ ApplicationWindow {
id: app
visible: false
- property var ctx
+ property var ctx
Connections {
target: jsonModel
diff --git a/pkg/backend/api.go b/pkg/backend/api.go
index a19fd40..fea38db 100644
--- a/pkg/backend/api.go
+++ b/pkg/backend/api.go
@@ -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()
}
diff --git a/pkg/backend/init.go b/pkg/backend/init.go
index 5abb05e..79efdc7 100644
--- a/pkg/backend/init.go
+++ b/pkg/backend/init.go
@@ -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()
diff --git a/pkg/backend/mocks.go b/pkg/backend/mocks.go
index a8ede73..226fa4e 100644
--- a/pkg/backend/mocks.go
+++ b/pkg/backend/mocks.go
@@ -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)
-}
diff --git a/pkg/bitmask/init.go b/pkg/bitmask/init.go
index 33a5911..a96ab87 100644
--- a/pkg/bitmask/init.go
+++ b/pkg/bitmask/init.go
@@ -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
}
diff --git a/test.pro b/test.pro
new file mode 100644
index 0000000..099e18f
--- /dev/null
+++ b/test.pro
@@ -0,0 +1,26 @@
+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
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..65af933
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,10 @@
+build/*
+*.h
+*.sh
+*.moc
+*.o
+*.stash
+Makefile
+test_ui
+moc_handlers.cpp
+moc_qjsonmodel.cpp
diff --git a/tests/test_ui.cpp b/tests/test_ui.cpp
new file mode 100644
index 0000000..f9f960a
--- /dev/null
+++ b/tests/test_ui.cpp
@@ -0,0 +1,52 @@
+// 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"
diff --git a/tests/tst_smoke.qml b/tests/tst_smoke.qml
new file mode 100644
index 0000000..19904a6
--- /dev/null
+++ b/tests/tst_smoke.qml
@@ -0,0 +1,28 @@
+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?")
+ }
+}