Skip to content

Commit cd388e8

Browse files
Merge pull request #4218 from MerginMaps/feature/independent-test-runs
Feature/independent test runs
1 parent 9dab170 commit cd388e8

File tree

7 files changed

+243
-43
lines changed

7 files changed

+243
-43
lines changed

.github/workflows/linux.yml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,8 @@ jobs:
134134
ninja
135135
136136
- name: run tests
137-
env:
138-
TEST_MERGIN_URL: https://app.dev.merginmaps.com/
139-
TEST_API_USERNAME: test_mobileapp
140-
TEST_API_PASSWORD: ${{ secrets.TEST_API_PASSWORD }}
141-
QT_QPA_PLATFORM: "offscreen"
137+
env:
138+
QT_QPA_PLATFORM: "offscreen"
142139
run: |
143140
cd build-mm-db/
144141
xvfb-run --server-args="-screen 0 640x480x24" ctest --output-on-failure

.github/workflows/macos.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,6 @@ jobs:
131131
ninja
132132
133133
- name: run tests
134-
env:
135-
TEST_MERGIN_URL: https://app.dev.merginmaps.com/
136-
TEST_API_USERNAME: test_mobileapp2
137-
TEST_API_PASSWORD: ${{ secrets.TEST_API_PASSWORD }}
138134
run: |
139135
cd build-mm-db/
140136
ctest --output-on-failure

app/test/testmerginapi.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ void TestMerginApi::initTestCase()
100100
// Note: projects on the server are deleted in createRemoteProject function when needed
101101

102102
qRegisterMetaType<LocalProject>();
103+
// wait for the server to finish up the creation of the new user
104+
qDebug() << "Workspace initialized - waiting for server-side setup to complete...";
105+
QTest::qWait( 3000 ); // Give server 3 seconds to fully initialize the workspace
103106
}
104107

105108
void TestMerginApi::cleanupTestCase()
@@ -134,6 +137,7 @@ void TestMerginApi::testListProject()
134137

135138
// project is not available locally, so it has no entry
136139
QVERIFY( !mApi->localProjectsManager().projectFromMerginName( mWorkspaceName, projectName ).isValid() );
140+
137141
}
138142

139143
void TestMerginApi::testListProjectsByName()
@@ -2145,7 +2149,10 @@ void TestMerginApi::testSelectiveSyncChangeSyncFolder()
21452149
photoDirExtra.mkpath( photoPathClient2 );
21462150

21472151
// simulate some traffic, let both clients create few photos several times (so that project has longer history)
2148-
for ( int i : { 1, 2, 3, 4, 5 } )
2152+
for ( int i :
2153+
{
2154+
1, 2, 3, 4, 5
2155+
} )
21492156
{
21502157
QFile f1( photoPathClient1 + "/" + QString( "photoC1-%1.png" ).arg( i ) );
21512158
f1.open( QIODevice::WriteOnly );
@@ -2367,7 +2374,9 @@ void TestMerginApi::testAutosync()
23672374

23682375
InputUtils::cpDir( TestUtils::testDataDir() + "/planes", projectdir );
23692376

2370-
MapThemesModel mtm; AppSettings as; ActiveLayer al;
2377+
MapThemesModel mtm;
2378+
AppSettings as;
2379+
ActiveLayer al;
23712380
ActiveProject activeProject( as, al, mApi->localProjectsManager() );
23722381

23732382
mApi->localProjectsManager().addLocalProject( projectdir, projectname );
@@ -2426,8 +2435,17 @@ void TestMerginApi::testOfflineCache()
24262435
QVERIFY( mApi->userAuth()->hasValidToken() );
24272436

24282437
QSettings cacheCheck;
2429-
QCOMPARE( cacheCheck.value( "Input/login" ).toString(), ::getenv( "TEST_API_USERNAME" ) );
2430-
QCOMPARE( cacheCheck.value( "Input/username" ).toString(), ::getenv( "TEST_API_USERNAME" ) );
2438+
// If we used environment variables, we should check that they match
2439+
if ( getenv( "TEST_API_USERNAME" ) != nullptr && getenv( "TEST_API_USERNAME" ) != nullptr )
2440+
{
2441+
QCOMPARE( cacheCheck.value( "Input/login" ).toString(), getenv( "TEST_API_USERNAME" ) );
2442+
QCOMPARE( cacheCheck.value( "Input/username" ).toString(), getenv( "TEST_API_USERNAME" ) );
2443+
}
2444+
else
2445+
{
2446+
QCOMPARE( cacheCheck.value( "Input/login" ).toString(), mApi->userInfo()->username() );
2447+
QCOMPARE( cacheCheck.value( "Input/username" ).toString(), mApi->userInfo()->username() );
2448+
}
24312449
QVERIFY( !cacheCheck.value( "Input/email" ).toString().isEmpty() );
24322450

24332451
MerginApi *extraApi = new MerginApi( *mLocalProjectsExtra, this );

app/test/testutils.cpp

Lines changed: 107 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,34 @@ void TestUtils::merginGetAuthCredentials( MerginApi *api, QString &apiRoot, QStr
2929
Q_ASSERT( api );
3030

3131
// Test server url needs to be set
32-
Q_ASSERT( ::getenv( "TEST_MERGIN_URL" ) );
33-
34-
apiRoot = ::getenv( "TEST_MERGIN_URL" );
32+
if ( ::getenv( "TEST_MERGIN_URL" ) == nullptr )
33+
{
34+
// if there is none, just default to the dev one
35+
apiRoot = QStringLiteral( "https://app.dev.merginmaps.com/" );
36+
}
37+
else
38+
{
39+
apiRoot = ::getenv( "TEST_MERGIN_URL" );
40+
// let's make sure we do not mess with the public instance
41+
Q_ASSERT( apiRoot != MerginApi::sDefaultApiRoot );
42+
}
3543
api->setApiRoot( apiRoot );
3644
qDebug() << "MERGIN API ROOT:" << apiRoot;
3745

38-
// let's make sure we do not mess with the public instance
39-
Q_ASSERT( apiRoot != MerginApi::sDefaultApiRoot );
40-
41-
// Test user needs to be set
42-
Q_ASSERT( ::getenv( "TEST_API_USERNAME" ) );
43-
44-
// Test password needs to be set
45-
Q_ASSERT( ::getenv( "TEST_API_PASSWORD" ) );
46-
47-
username = ::getenv( "TEST_API_USERNAME" );
48-
password = ::getenv( "TEST_API_PASSWORD" );
46+
// test user needs to be set
47+
// check if there are environmental variables for the username and the password
48+
if ( ::getenv( "TEST_API_USERNAME" ) == nullptr && ::getenv( "TEST_API_PASSWORD" ) == nullptr )
49+
{
50+
// generate a random email and pasword
51+
// create the user on the server
52+
// create a workspace for the user
53+
generateRandomUser( api, username, password );
54+
}
55+
else
56+
{
57+
username = ::getenv( "TEST_API_USERNAME" );
58+
password = ::getenv( "TEST_API_PASSWORD" );
59+
}
4960
}
5061

5162
void TestUtils::authorizeUser( MerginApi *api, const QString &username, const QString &password )
@@ -112,14 +123,14 @@ QString TestUtils::generateUsername()
112123
{
113124
QDateTime time = QDateTime::currentDateTime();
114125
QString uniqename = time.toString( QStringLiteral( "ddMMyy-hhmmss-z" ) );
115-
return QStringLiteral( "input-%1" ).arg( uniqename );
126+
return QStringLiteral( "mobile-%1" ).arg( uniqename );
116127
}
117128

118129
QString TestUtils::generateEmail()
119130
{
120131
QDateTime time = QDateTime::currentDateTime();
121132
QString uniqename = time.toString( QStringLiteral( "ddMMyy-hhmmss-z" ) );
122-
return QStringLiteral( "mergin+autotest+%1@lutraconsulting.co.uk" ).arg( uniqename );
133+
return QStringLiteral( "mobile-autotest+%1@lutraconsulting.co.uk" ).arg( uniqename );
123134
}
124135

125136
QString TestUtils::generatePassword()
@@ -128,6 +139,86 @@ QString TestUtils::generatePassword()
128139
return QStringLiteral( "_Pass12%1" ).arg( pass );
129140
}
130141

142+
QString TestUtils::generateWorkspaceName( const QString &username )
143+
{
144+
static const QRegularExpression regex( R"(mobile-autotest(\d{6})-(\d{4})\d{2}-\d{3})" );
145+
const QRegularExpressionMatch match = regex.match( username );
146+
147+
if ( match.hasMatch() )
148+
{
149+
const QString date = match.captured( 1 ); // Day Month Year
150+
const QString time = match.captured( 2 ); // Hour Second
151+
return QString( "mmat-%1-%2" ).arg( date, time );
152+
}
153+
return {};
154+
}
155+
156+
void TestUtils::generateRandomUser( MerginApi *api, QString &username, QString &password )
157+
{
158+
// generate the test run-specific user details
159+
QString email = generateEmail();
160+
password = generatePassword();
161+
username = email.split( '@' ).first();
162+
username.remove( "+" );
163+
164+
// create the account for the test run user
165+
api->clearAuth();
166+
QSignalSpy spy( api, &MerginApi::registrationSucceeded );
167+
QSignalSpy spy2( api, &MerginApi::registrationFailed );
168+
api->registerUser( email, password, true );
169+
// check that the account has been created.
170+
bool success = spy.wait( TestUtils::LONG_REPLY );
171+
if ( !success )
172+
{
173+
qDebug() << "Failed registration" << spy2.takeFirst();
174+
QVERIFY( false );
175+
}
176+
177+
// check that the user can be authorized
178+
QSignalSpy spyAuth( api->userAuth(), &MerginUserAuth::authChanged );
179+
api->authorize( email, password );
180+
QVERIFY( spyAuth.wait( TestUtils::LONG_REPLY * 5 ) );
181+
182+
// create workspace
183+
QSignalSpy wsSpy( api, &MerginApi::workspaceCreated );
184+
// create the workspace name
185+
QString workspace = generateWorkspaceName( username );
186+
api->createWorkspace( workspace );
187+
bool workspaceSuccess = wsSpy.wait( TestUtils::LONG_REPLY );
188+
QVERIFY( workspaceSuccess );
189+
qDebug() << "CREATED NEW WORKSPACE:" << workspace;
190+
191+
// call userInfo to set active workspace
192+
QSignalSpy infoSpy( api, &MerginApi::userInfoReplyFinished );
193+
api->getUserInfo();
194+
QVERIFY( infoSpy.wait( TestUtils::LONG_REPLY ) );
195+
QVERIFY( api->userInfo()->activeWorkspaceId() >= 0 );
196+
197+
// change the data plan
198+
QString workspaceId = QString::number( api->userInfo()->activeWorkspaceId() );
199+
QSignalSpy wsStorageSpy( api, &MerginApi::updateWorkspaceService );
200+
201+
// Create JSON payload to change the data plan
202+
QString payload = QString( R"({
203+
"limits_override": {
204+
"storage": %1,
205+
"projects" : %2,
206+
"api_allowed" : true
207+
}
208+
})" ).arg( TEST_WORKSPACE_STORAGE_SIZE ).arg( TEST_WORKSPACE_PROJECT_NUMBER );
209+
210+
api->updateWorkspaceService( workspaceId, payload );
211+
bool workspaceStorageModified = wsStorageSpy.wait( TestUtils::LONG_REPLY );
212+
if ( workspaceStorageModified )
213+
{
214+
qDebug() << "Updated the storage limit" << workspace;
215+
}
216+
217+
// this needs to be cleared, as the user will be authorized in the test cases.
218+
api->clearAuth();
219+
220+
}
221+
131222
QString TestUtils::testDataDir()
132223
{
133224
QString dataDir( TEST_DATA_DIR );

app/test/testutils.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ namespace TestUtils
2121
{
2222
const int SHORT_REPLY = 5000;
2323
const int LONG_REPLY = 90000;
24+
const int TEST_WORKSPACE_STORAGE_SIZE = 1 * 1024 * 1024 * 1024; // 1 GB
25+
const int TEST_WORKSPACE_PROJECT_NUMBER = 100;
2426

2527
//! authorize user and select the active workspace
2628
void authorizeUser( MerginApi *api, const QString &username, const QString &password );
@@ -33,15 +35,22 @@ namespace TestUtils
3335
* - TEST_MERGIN_URL
3436
* - TEST_API_USERNAME
3537
* - TEST_API_PASSWORD
38+
* And if not found, generate a test run-specific user
3639
*/
3740
void merginGetAuthCredentials( MerginApi *api, QString &apiRoot, QString &username, QString &password );
3841

3942
//! Whether we need to auth again
4043
bool needsToAuthorizeAgain( MerginApi *api, const QString &username );
44+
void generateRandomUser( MerginApi *api, QString &username, QString &password );
4145

4246
QString generateUsername();
4347
QString generateEmail();
4448
QString generatePassword();
49+
/*
50+
* Create a workspace name from the generated username
51+
* Output: a workspace name: mmat-DayMonthYear-HourMinutes
52+
*/
53+
QString generateWorkspaceName( const QString &username );
4554

4655
QString testDataDir();
4756

0 commit comments

Comments
 (0)