Commit 01033c93 authored by Bernd Wachter's avatar Bernd Wachter

Merge pull request #10 from martyone/master

sandbox code/doc polishing, add ut_coreconfig, add ut_sandbox, fix debug mode, extend ut_urlresolver, add ut_deviceinfo, add ut_repomanager
parents 0edb1e49 28fc0fd5
......@@ -17,7 +17,6 @@
#include <QtCore/QSet>
#include "libssu/ssucoreconfig.h"
// TODO: rename to ssuconstants.h?
#include "constants.h"
class Sandbox::FileEngineHandler : public QAbstractFileEngineHandler {
......@@ -37,20 +36,35 @@ class Sandbox::FileEngineHandler : public QAbstractFileEngineHandler {
/**
* @class Sandbox
* @brief Simple sandboxing with Qt file system abstraction.
*
* Redirects all file operations on system configuration files to files under
* sandbox directory. When constructed without arguments, the directory is get
* from @c SSU_TESTS_SANDBOX environment variable.
* Redirects all file operations on selected files to files under sandbox
* directory. The term <em>world files</em> is used to reffer files outside
* sandbox.
*
* Its effect is controlled by activate() and deactivate() calls. Only one
* Sandbox instance can be active at any time. Active sandbox is automatically
* deactivated upon destruction.
*
* When constructed without arguments, path to sandbox directory is get from
* @c SSU_TESTS_SANDBOX environment variable.
*
* @attention When constructed without arguments, it is activated automatically
* and failure to do so is reported with @c qFatal(), i.e., application will be
* abort()ed.
*
* When constructed with @a usage UseAsSkeleton, it will first make temporary
* copy of @a sandboxPath to work on and files in the original directory will
* stay untouched.
* stay untouched. Also see addWorldFiles().
*
* The argument @scopes allows to control if the sandbox will be used by this
* process, its children processes (@c SSU_TESTS_SANDBOX environment variable
* will be exported), or both.
*
* Internally it is based on QAbstractFileEngineHandler.
*
* @attention QDir lists entries presented in the world directory. The behavior
* changed with Qt 4.8.0 (Qt commit b9b55234a777c3b206332bafbe227e1355ca9186)
*/
Sandbox *Sandbox::s_activeInstance = 0;
......@@ -71,15 +85,15 @@ Sandbox::Sandbox(const QString &sandboxPath, Usage usage, Scopes scopes)
}
Sandbox::~Sandbox(){
delete m_handler;
if (isActive()){
deactivate();
}
if (!m_tempDir.isEmpty() && QFileInfo(m_tempDir).exists()){
if (QProcess::execute("rm", QStringList() << "-rf" << m_tempDir) != 0){
qWarning("%s: Failed to remove temporary directory", Q_FUNC_INFO);
}
}
s_activeInstance = 0;
}
bool Sandbox::isActive() const{
......@@ -105,6 +119,20 @@ bool Sandbox::activate(){
return true;
}
void Sandbox::deactivate(){
Q_ASSERT(isActive());
if (m_scopes & ThisProcess){
delete m_handler;
}
if (m_scopes & ChildProcesses){
unsetenv("SSU_TESTS_SANDBOX");
}
s_activeInstance = 0;
}
/**
* Copies selected files into sandbox. Existing files in sandbox are not overwriten.
*
......@@ -119,7 +147,6 @@ bool Sandbox::addWorldFiles(const QString &directory, QDir::Filters filters,
Q_ASSERT(!directory.contains("/./") && !directory.endsWith("/.")
&& !directory.contains("/../") && !directory.endsWith("/..")
&& !directory.contains("//"));
Q_ASSERT_X(!(m_scopes & ChildProcesses), Q_FUNC_INFO, "Unimplemented case!");
if (!prepare()){
return false;
......@@ -191,6 +218,11 @@ bool Sandbox::addWorldFiles(const QString &directory, QDir::Filters filters,
return true;
}
bool Sandbox::addWorldFile(const QString &file){
return addWorldFiles(QFileInfo(file).path(), QDir::NoFilter,
QStringList() << QFileInfo(file).fileName());
}
bool Sandbox::prepare(){
Q_ASSERT(m_defaultConstructed || !m_sandboxPath.isEmpty());
......
......@@ -33,10 +33,12 @@ class Sandbox {
~Sandbox();
bool activate();
void deactivate();
bool isActive() const;
bool addWorldFiles(const QString &directory, QDir::Filters filters = QDir::NoFilter,
const QStringList &filterNames = QStringList());
bool addWorldFile(const QString &file);
private:
bool prepare();
......
......@@ -23,6 +23,8 @@ class QNetworkReply;
class Ssu: public QObject {
Q_OBJECT
friend class UrlResolverTest;
public:
Ssu();
/**
......
......@@ -89,7 +89,7 @@ QString SsuVariables::resolveVariable(QString variable, QHash<QString, QString>
// find the operator who's after your colon
QChar op;
if (variable.length() >= magic +1)
if (variable.length() > magic +1)
op = variable.at(magic + 1);
switch(op.toAscii()){
......
......@@ -3,6 +3,9 @@ include(tests_common.pri)
QT += testlib
test_data.path = $${TESTS_DATA_PATH}
INSTALLS += test_data
test_data_etc.path = $${TESTS_DATA_PATH}/configroot/etc/ssu
test_data_usr_share.path = $${TESTS_DATA_PATH}/configroot/usr/share/ssu
INSTALLS += test_data_etc test_data_usr_share
......@@ -3,7 +3,11 @@ CONFIG += ordered coverage debug
SUBDIRS = \
testutils \
testutils/sandboxhook.pro \
ut_coreconfig \
ut_deviceinfo \
ut_repomanager \
ut_rndssucli \
ut_sandbox \
ut_settings \
ut_ssuurlresolver \
ut_urlresolver \
......
......@@ -3,11 +3,31 @@
<!-- Test suite, name mandatory - the same as test package name -->
<suite name="sync-app-tests" domain="ssu">
<!-- At least one set per suite, name and description mandatory -->
<set name="coreconfig" description="Test to determine if code configuration file processing works properly" feature="coreconfig">
<case name="ut_coreconfig" type="Functional" description="Core config processing test" timeout="1000" subfeature="">
<step expected_result="0">/opt/tests/ssu/runtest.sh ut_coreconfig</step>
</case>
</set>
<set name="deviceinfo" description="Test to determine if device info can be retrieved properly" feature="deviceinfo">
<case name="ut_deviceinfo" type="Functional" description="Device info processing test" timeout="1000" subfeature="">
<step expected_result="0">/opt/tests/ssu/runtest.sh ut_deviceinfo</step>
</case>
</set>
<set name="repomanager" description="Test to determine if ssu repository management works properly" feature="repomanager">
<case name="ut_repomanager" type="Functional" description="SSU repo management test" timeout="1000" subfeature="">
<step expected_result="0">/opt/tests/ssu/runtest.sh ut_repomanager</step>
</case>
</set>
<set name="rndssucli" description="Test to determine if ssu command line tool works properly" feature="rndssucli">
<case name="ut_rndssucli" type="Functional" description="SSU command line utility test" timeout="1000" subfeature="">
<step expected_result="0">/opt/tests/ssu/runtest.sh ut_rndssucli</step>
</case>
</set>
<set name="sandbox" description="Test to determine if sandboxing works properly" feature="sandbox">
<case name="ut_sandbox" type="Functional" description="Sandboxing test" timeout="1000" subfeature="">
<step expected_result="0">/opt/tests/ssu/runtest.sh ut_sandbox</step>
</case>
</set>
<set name="settings" description="Test to determine if configuration files processing works properly" feature="settings">
<case name="ut_settings" type="Functional" description="Settings processing test" timeout="1000" subfeature="">
<step expected_result="0">/opt/tests/ssu/runtest.sh ut_settings</step>
......
......@@ -25,7 +25,7 @@ Process::Process() : m_expectFail(false), m_timedOut(false) {}
QString Process::execute(const QString &program, const QStringList &arguments,
bool expectedResult){
Q_ASSERT(processStatus() == NotRunning);
Q_ASSERT(m_process.state() == QProcess::NotRunning);
m_program = program;
m_arguments = arguments;
m_expectFail = expectedResult == ExpectFail;
......@@ -42,7 +42,9 @@ bool Process::hasError(){
}
QString Process::fmtErrorMessage(){
Q_ASSERT(hasError());
if (!hasError()){
return QString();
}
QStringList reasons;
if (m_timedOut){
......
/**
* @file coreconfigtest.cpp
* @copyright 2013 Jolla Ltd.
* @author Martin Kampas <martin.kampas@tieto.com>
* @date 2013
*/
#include "coreconfigtest.h"
#include <QtTest/QtTest>
#include "libssu/ssucoreconfig.h"
void CoreconfigTest::testCredentialsScope(){
QCOMPARE(SsuCoreConfig::instance()->credentialsScope("/*ignored*/", false), QString("example"));
}
void CoreconfigTest::testCredentials(){
QCOMPARE(SsuCoreConfig::instance()->credentials("example").first, QString("example_username"));
QCOMPARE(SsuCoreConfig::instance()->credentials("example").second, QString("example_password"));
}
void CoreconfigTest::testCredentialsUrl(){
QCOMPARE(SsuCoreConfig::instance()->credentialsUrl("example"), QString("http://creden.tia.ls/"));
}
void CoreconfigTest::testFlavour(){
QCOMPARE(SsuCoreConfig::instance()->flavour(), QString("testing"));
SsuCoreConfig::instance()->setFlavour("release");
QCOMPARE(SsuCoreConfig::instance()->flavour(), QString("release"));
}
void CoreconfigTest::testDeviceMode(){
SsuCoreConfig::instance()->remove("deviceMode");
QCOMPARE(SsuCoreConfig::instance()->deviceMode(), (int)Ssu::ReleaseMode);
SsuCoreConfig::instance()->setDeviceMode(Ssu::ReleaseMode, Ssu::Add);
QCOMPARE(SsuCoreConfig::instance()->deviceMode(), (int)Ssu::ReleaseMode);
SsuCoreConfig::instance()->setDeviceMode(Ssu::LenientMode, Ssu::Add);
QCOMPARE(SsuCoreConfig::instance()->deviceMode(), (int)Ssu::ReleaseMode | Ssu::LenientMode);
SsuCoreConfig::instance()->setDeviceMode(Ssu::ReleaseMode, Ssu::Remove);
QCOMPARE(SsuCoreConfig::instance()->deviceMode(), (int)Ssu::LenientMode);
SsuCoreConfig::instance()->setDeviceMode(Ssu::ReleaseMode, Ssu::Replace);
QCOMPARE(SsuCoreConfig::instance()->deviceMode(), (int)Ssu::ReleaseMode);
}
void CoreconfigTest::testDomain(){
QCOMPARE(SsuCoreConfig::instance()->domain(), QString(""));
SsuCoreConfig::instance()->setDomain("foo");
QCOMPARE(SsuCoreConfig::instance()->domain(), QString("foo"));
}
void CoreconfigTest::testRegistered(){
QCOMPARE(SsuCoreConfig::instance()->isRegistered(), false);
SsuCoreConfig::instance()->setValue("registered", true);
QCOMPARE(SsuCoreConfig::instance()->isRegistered(), false);
SsuCoreConfig::instance()->setValue("privateKey", "fooKey");
QCOMPARE(SsuCoreConfig::instance()->isRegistered(), false);
SsuCoreConfig::instance()->setValue("certificate", "fooCert");
QCOMPARE(SsuCoreConfig::instance()->isRegistered(), true);
}
void CoreconfigTest::testLastCredentialsUpdate(){
QCOMPARE(SsuCoreConfig::instance()->lastCredentialsUpdate(), QDateTime());
SsuCoreConfig::instance()->setValue("lastCredentialsUpdate",
QDateTime::fromString("2013-04-08", Qt::ISODate));
QCOMPARE(SsuCoreConfig::instance()->lastCredentialsUpdate(),
QDateTime::fromString("2013-04-08", Qt::ISODate));
}
void CoreconfigTest::testRelease(){
QCOMPARE(SsuCoreConfig::instance()->release(false), QString("latest"));
QCOMPARE(SsuCoreConfig::instance()->release(true), QString("next"));
SsuCoreConfig::instance()->setRelease("next", false);
QCOMPARE(SsuCoreConfig::instance()->release(false), QString("next"));
QCOMPARE(SsuCoreConfig::instance()->release(true), QString("next"));
SsuCoreConfig::instance()->setRelease("latest", true);
QCOMPARE(SsuCoreConfig::instance()->release(false), QString("next"));
QCOMPARE(SsuCoreConfig::instance()->release(true), QString("latest"));
}
void CoreconfigTest::testSslVerify(){
QCOMPARE(SsuCoreConfig::instance()->useSslVerify(), true);
SsuCoreConfig::instance()->setValue("ssl-verify", false);
QCOMPARE(SsuCoreConfig::instance()->useSslVerify(), false);
}
/**
* @file coreconfigtest.h
* @copyright 2013 Jolla Ltd.
* @author Martin Kampas <martin.kampas@tieto.com>
* @date 2013
*/
#ifndef _CORECONFIGTEST_H
#define _CORECONFIGTEST_H
#include <QObject>
class CoreconfigTest: public QObject {
Q_OBJECT
private slots:
void testCredentialsScope();
void testCredentials();
void testCredentialsUrl();
void testFlavour();
void testDeviceMode();
void testDomain();
void testRegistered();
void testLastCredentialsUpdate();
void testRelease();
void testSslVerify();
};
#endif
/**
* @file main.cpp
* @copyright 2012 Jolla Ltd.
* @author Martin Kampas <martin.kampas@tieto.com>
* @date 2012
*/
#include <QtTest/QtTest>
#include "libssu/sandbox_p.h"
#include "coreconfigtest.h"
int main(int argc, char **argv){
Sandbox sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH),
Sandbox::UseAsSkeleton, Sandbox::ThisProcess);
if (!sandbox.activate()){
qFatal("Failed to activate sandbox");
}
CoreconfigTest coreconfigTest;
if (QTest::qExec(&coreconfigTest, argc, argv))
return 1;
return 0;
}
[General]
initialized=true
flavour=testing
registered=false
rndRelease=next
release=latest
adaptation=
ca-certificate=
credentials-scope=example
credentials-url-example = http://creden.tia.ls/
[credentials-example]
username = example_username
password = example_password
[repository-urls]
[repository-url-variables]
TARGET = ut_coreconfig
include(../testapplication.pri)
include(ut_coreconfig_dependencies.pri)
HEADERS = \
coreconfigtest.h \
SOURCES = \
main.cpp \
coreconfigtest.cpp \
test_data_etc.files = \
testdata/ssu.ini \
test_data_usr_share.files = \
testdata/ssu-defaults.ini \
include(../../libssu/libssu.pri)
include(../testutils/testutils.pri)
/**
* @file deviceinfotest.cpp
* @copyright 2013 Jolla Ltd.
* @author Martin Kampas <martin.kampas@tieto.com>
* @date 2013
*/
#include "deviceinfotest.h"
#include <QtTest/QtTest>
#include "libssu/ssudeviceinfo.h"
void DeviceInfoTest::testAdaptationVariables(){
SsuDeviceInfo deviceInfo("N950");
QHash<QString, QString> variables;
QHash<QString, QString> variablesExpected;
variablesExpected["adaptation"] = "n950-n9";
variablesExpected["foo-n9"] = "foo-n9-val";
variablesExpected["foo-n950-n9"] = "foo-n950-n9-val";
QString repoName = deviceInfo.adaptationVariables("adaptation1", &variables);
QCOMPARE(variables, variablesExpected);
QCOMPARE(repoName, QString("adaptation"));
}
void DeviceInfoTest::testDeviceUid(){
QVERIFY2(!SsuDeviceInfo().deviceUid().isEmpty(), "No method to get device UID on this platform");
}
void DeviceInfoTest::testVariableSection(){
SsuDeviceInfo deviceInfo;
QHash<QString, QString> fooVars;
QHash<QString, QString> fooVarsExpected;
fooVarsExpected["foo1"] = "foo1Val";
fooVarsExpected["foo2"] = "foo2Val";
deviceInfo.variableSection("foo", &fooVars);
QCOMPARE(fooVars, fooVarsExpected);
QHash<QString, QString> barVars;
QHash<QString, QString> barVarsExpected;
barVarsExpected["bar1"] = "bar1Val";
barVarsExpected["bar2"] = "bar2Val";
deviceInfo.variableSection("bar", &barVars);
QCOMPARE(barVars, barVarsExpected);
QHash<QString, QString> bazVars;
QHash<QString, QString> bazVarsExpected;
bazVarsExpected["foo1"] = "foo1Val";
bazVarsExpected["foo2"] = "foo2Val";
bazVarsExpected["bar1"] = "bar1Val";
bazVarsExpected["bar2"] = "bar2Val";
deviceInfo.variableSection("baz", &bazVars);
QCOMPARE(bazVars, bazVarsExpected);
}
void DeviceInfoTest::testValue(){
SsuDeviceInfo deviceInfo("N950");
QCOMPARE(deviceInfo.value("family").toString(), QString("n950-n9"));
QCOMPARE(deviceInfo.value("adaptation-repos").toStringList(),
QString("n9xx-common,n950-n9").split(','));
QCOMPARE(deviceInfo.value("foo").toString(), QString("n950-foo"));
}
/**
* @file deviceinfotest.h
* @copyright 2013 Jolla Ltd.
* @author Martin Kampas <martin.kampas@tieto.com>
* @date 2013
*/
#ifndef _DEVICEINFOTEST_H
#define _DEVICEINFOTEST_H
#include <QObject>
class DeviceInfoTest: public QObject {
Q_OBJECT
private slots:
void testAdaptationVariables();
void testDeviceUid();
void testVariableSection();
void testValue();
};
#endif
/**
* @file main.cpp
* @copyright 2012 Jolla Ltd.
* @author Martin Kampas <martin.kampas@tieto.com>
* @date 2012
*/
#include <QtTest/QtTest>
#include "libssu/sandbox_p.h"
#include "deviceinfotest.h"
int main(int argc, char **argv){
Sandbox sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH),
Sandbox::UseAsSkeleton, Sandbox::ThisProcess);
if (!sandbox.activate()){
qFatal("Failed to activate sandbox");
}
DeviceInfoTest deviceinfoTest;
if (QTest::qExec(&deviceinfoTest, argc, argv))
return 1;
return 0;
}
[file.exists]
SDK=/mer-sdk-chroot
[systeminfo.equals]
[cpuinfo.contains]
N900=Nokia RX-51 board
N950=Nokia RM-680 board
N9=Nokia RM-696 board
[arch.equals]
generic-x86=i586
[variants]
N950=N9
[N9]
family=n950-n9
adaptation-repos=n9xx-common,n950-n9
variables = n9
[var-n9]
foo-n9 = foo-n9-val
[var-n950-n9]
foo-n950-n9 = foo-n950-n9-val
[N900]
family=n900
adaptation-repos=n9xx-common,n900
[N950]
foo = n950-foo
[SDK]
[generic-x86]
family=x86
adaptation-repos=x86
[UNKNOWN]
family=UNKNOWN
[var-foo]
foo1 = foo1Val
foo2 = foo2Val
[var-bar]
bar1 = bar1Val
bar2 = bar2Val
[var-baz]
variables = foo, bar
[all]
credentials=jolla
credentials-url=https://%(ssuRegDomain)/%(ssuRegPath)/%1/credentials.xml
register-url=https://%(ssuRegDomain)/%(ssuRegPath)/%1/register.xml
[release]
mer-core=https://%(packagesDomain)/%(release)/mer/%(arch)/%(debugSplit)/
[rnd]
mer-core=https://%(packagesDomain)/mer/%(release)/builds/%(arch)/%(debugSplit)/
[devel-flavour]
flavour-pattern=
[release-flavour]
flavour-pattern=:/release
[testing-flavour]
flavour-pattern=:/testing
[example-domain]
dumpDomain=dump.example.com
packagesDomain=packages.example.com
ssuRegDomain=ssu.example.com
ssuRegPath=ssu/device
# fallback if domain is not matched or not set
[default-domain]
dumpDomain=dump.testing.com
packagesDomain=packages.testing.com
ssuRegDomain=ssu.testing.com
ssuRegPath=ssu/device
[General]
initialized=true
flavour=testing
registered=false
rndRelease=next
release=latest
adaptation=
ca-certificate=
credentials-scope=example
credentials-url-example = http://creden.tia.ls/
[credentials-example]
username = example_username
password = example_password
[repository-urls]
[repository-url-variables]
TARGET = ut_deviceinfo
include(../testapplication.pri)
include(ut_deviceinfo_dependencies.pri)
HEADERS = \
deviceinfotest.h \
SOURCES = \
main.cpp \
deviceinfotest.cpp \
test_data_etc.files = \
testdata/ssu.ini \
test_data_usr_share.files = \
testdata/ssu-defaults.ini \
testdata/board-mappings.ini \
testdata/repos.ini \
/**
* @file main.cpp
* @copyright 2012 Jolla Ltd.
* @author Martin Kampas <martin.kampas@tieto.com>
* @date 2012
*/
#include <QtTest/QtTest>
#include "libssu/sandbox_p.h"
#include "repomanagertest.h"
int main(int argc, char **argv){
Sandbox sandbox(QString("%1/configroot").arg(TESTS_DATA_PATH),
Sandbox::UseAsSkeleton, Sandbox::ThisProcess);
if (!sandbox.activate()){
qFatal("Failed to activate sandbox");
}
RepoManagerTest repomanagerTest;
if (QTest::qExec(&repomanagerTest, argc, argv))
return 1;
return 0;
}
/**
* @file repomanagertest.cpp
* @copyright 2013 Jolla Ltd.
* @author Martin Kampas <martin.kampas@tieto.com>
* @date 2013
*/
#include "repomanagertest.h"
#include <QtTest/QtTest>
#include "libssu/ssucoreconfig.h"
#include "libssu/ssurepomanager.h"
void RepoManagerTest::testSettings(){
SsuCoreConfig *const coreConfig = SsuCoreConfig::instance();
SsuRepoManager repoManager;
repoManager.add("repo1", "http://repo1");
QCOMPARE(coreConfig->value("repository-urls/repo1").toString(), QString("http://repo1"));
QVERIFY(!coreConfig->value("enabled-repos").toStringList().contains("repo1"));
QVERIFY(!coreConfig->value("disabled-repos").toStringList().contains("repo1"));
repoManager.enable("repo1");
QCOMPARE(coreConfig->value("repository-urls/repo1").toString(), QString("http://repo1"));
QVERIFY(!coreConfig->value("enabled-repos").toStringList().contains("repo1"));
QVERIFY(!coreConfig->value("disabled-repos").toStringList().contains("repo1"));
repoManager.add("repo1");
QCOMPARE(coreConfig->value("repository-urls/repo1").toString(), QString("http://repo1"));
QVERIFY(coreConfig->value("enabled-repos").toStringList().contains("repo1"));
QVERIFY(!coreConfig->value("disabled-repos").toStringList().contains("repo1"));