Skip to content

Commit 8f83bd3

Browse files
committed
test(migration): wip! test each migration scenarion.
Signed-off-by: Camila Ayres <[email protected]>
1 parent a680e4b commit 8f83bd3

File tree

3 files changed

+293
-0
lines changed

3 files changed

+293
-0
lines changed

src/gui/folderman.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class EndToEndTestHelper;
2828
class TestSyncConflictsModel;
2929
class TestRemoteWipe;
3030
class FolderManTestHelper;
31+
class TestMigration;
3132

3233
namespace OCC {
3334

@@ -418,6 +419,7 @@ private slots:
418419
friend class ::TestFolderStatusModel;
419420
friend class ::TestRemoteWipe;
420421
friend class ::FolderManTestHelper;
422+
friend class ::TestMigration;
421423
};
422424

423425
} // namespace OCC

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ nextcloud_add_test(Account)
149149
nextcloud_add_test(Folder)
150150
nextcloud_add_test(FolderMan)
151151
nextcloud_add_test(RemoteWipe)
152+
nextcloud_add_test(Migration)
152153

153154
if(NOT BUILD_FILE_PROVIDER_MODULE)
154155
# the File Provider build crashes this test in CI for some reason

test/testmigration.cpp

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: GPL-2.0-or-later
4+
*/
5+
6+
#include <qglobal.h>
7+
#include <QTemporaryDir>
8+
#include <QtTest>
9+
#include <QtTest/qtestcase.h>
10+
11+
#include "common/utility.h"
12+
#include "folderman.h"
13+
#include "account.h"
14+
#include "accountstate.h"
15+
#include "accountmanager.h"
16+
#include "configfile.h"
17+
#include "syncenginetestutils.h"
18+
#include "testhelper.h"
19+
#include "version.h"
20+
21+
using namespace OCC;
22+
23+
class TestMigration: public QObject
24+
{
25+
Q_OBJECT
26+
27+
ConfigFile _configFile;
28+
QTemporaryDir _temporaryDir;
29+
std::unique_ptr<FolderMan> _folderMan;
30+
31+
private:
32+
static constexpr char legacyAppName[] = "ownCloud";
33+
static constexpr char standardAppName[] = "Nextcloud";
34+
static constexpr char brandedAppName[] = "Branded";
35+
static constexpr char ocBrandedAppName[] = "branded";
36+
static constexpr char legacyAppConfigContent[] = "[General]\n"
37+
"clientVersion=5.3.2.15463\n"
38+
"issuesWidgetFilter=FatalError, BlacklistedError, Excluded, Message, FilenameReserved\n"
39+
"logHttp=false\n"
40+
"optionalDesktopNotifications=true\n"
41+
"\n"
42+
"[Accounts]e\n"
43+
"0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\davUrl=@Variant(http://oc.de/remote.php/dav/files/admin/)\n"
44+
"0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\deployed=false\n"
45+
"0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\displayString=ownCloud\n"
46+
"0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\ignoreHiddenFiles=true\n"
47+
"0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\journalPath=.sync_journal.db\n"
48+
"0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\localPath=/ownCloud/\n"
49+
"0\\Folders\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\paused=false\n"
50+
"0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\priority=0\n"
51+
"0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\targetPath=/\n"
52+
"0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\version=13\n"
53+
"0\\Folders\\2ba4b09a-1223-aaaa-abcd-c2df238816d8\\virtualFilesMode=off\n"
54+
"0\\capabilities=@QVariant()\n"
55+
"0\\dav_user=admin\n"
56+
"0\\default_sync_root=/ownCloud\n"
57+
"0\\display-name=admin\n"
58+
"0\\http_CredentialVersion=1\n"
59+
"0\\http_oauth=false\n"
60+
"0\\http_user=admin\n"
61+
"0\\supportsSpaces=true\n"
62+
"0\\url=http://oc.de/\n"
63+
"0\\user=admin\n"
64+
"0\\userExplicitlySignedOut=false\n"
65+
"0\\uuid=@Variant()\n"
66+
"0\\version=13\n"
67+
"version=13\n"
68+
"\n"
69+
"[Credentials]\n"
70+
"ownCloud_credentials%oc.de%2ba4b09a-1223-aaaa-abcd-c2df238816d8\\http\\password=true";
71+
72+
private slots:
73+
void setupStandardConfigFolder()
74+
{
75+
QVERIFY(QDir(_temporaryDir.path()).mkpath(standardAppName));
76+
const auto standardConfigFolder = QString(_temporaryDir.path() + "/" + standardAppName);
77+
_configFile.setConfDir(standardConfigFolder);
78+
}
79+
80+
void setupStandarConfig(const QString &version)
81+
{
82+
setupStandardConfigFolder();
83+
QSettings settings(_configFile.configFile(), QSettings::IniFormat);
84+
_configFile.setClientVersionString(version);
85+
_configFile.setOptionalServerNotifications(true);
86+
_configFile.setShowChatNotifications(true);
87+
_configFile.setShowCallNotifications(true);
88+
_configFile.setShowInExplorerNavigationPane(true);
89+
_configFile.setShowInExplorerNavigationPane(true);
90+
_configFile.setRemotePollInterval(std::chrono::milliseconds(1000));
91+
_configFile.setAutoUpdateCheck(true, QString());
92+
_configFile.setUpdateChannel("beta");
93+
_configFile.setOverrideServerUrl("http://example.de");
94+
_configFile.setOverrideLocalDir("A");
95+
_configFile.setVfsEnabled(true);
96+
_configFile.setProxyType(0);
97+
_configFile.setVfsEnabled(true);
98+
_configFile.setUseUploadLimit(0);
99+
_configFile.setUploadLimit(1);
100+
_configFile.setUseDownloadLimit(0);
101+
_configFile.setUseDownloadLimit(1);
102+
_configFile.setNewBigFolderSizeLimit(true, 500);
103+
_configFile.setNotifyExistingFoldersOverLimit(true);
104+
_configFile.setStopSyncingExistingFoldersOverLimit(true);
105+
_configFile.setConfirmExternalStorage(true);
106+
_configFile.setMoveToTrash(true);
107+
_configFile.setForceLoginV2(true);
108+
_configFile.setPromptDeleteFiles(true);
109+
_configFile.setDeleteFilesThreshold(1);
110+
_configFile.setMonoIcons(true);
111+
_configFile.setAutomaticLogDir(true);
112+
_configFile.setLogDir(_temporaryDir.path());
113+
_configFile.setLogDebug(true);
114+
_configFile.setLogExpire(72);
115+
_configFile.setLogFlush(true);
116+
_configFile.setCertificatePath(_temporaryDir.path());
117+
_configFile.setCertificatePasswd("123456");
118+
_configFile.setLaunchOnSystemStartup(true);
119+
_configFile.setServerHasValidSubscription(true);
120+
_configFile.setDesktopEnterpriseChannel("stable");
121+
_configFile.setLanguage("pt");
122+
settings.sync();
123+
QVERIFY(_configFile.exists());
124+
QScopedPointer<FakeQNAM> fakeQnam(new FakeQNAM({}));
125+
OCC::AccountPtr account = OCC::Account::create();
126+
account->setDavUser("user");
127+
account->setDavDisplayName("Nextcloud user");
128+
account->setProxyType(QNetworkProxy::ProxyType::HttpProxy);
129+
account->setProxyUser("proxyuser");
130+
account->setDownloadLimit(120);
131+
account->setUploadLimit(120);
132+
account->setDownloadLimitSetting(OCC::Account::AccountNetworkTransferLimitSetting::ManualLimit);
133+
account->setServerVersion("30");
134+
account->setCredentials(new FakeCredentials{fakeQnam.data()});
135+
account->setUrl(QUrl(("http://example.de")));
136+
const auto accountState = OCC::AccountManager::instance()->addAccount(account);
137+
OCC::AccountManager::instance()->saveAccount(accountState->account());
138+
OCC::FolderDefinition folderDefinition;
139+
folderDefinition.localPath = "/standardAppName";
140+
folderDefinition.targetPath = "/";
141+
folderDefinition.alias = standardAppName;
142+
_folderMan.reset({});
143+
_folderMan.reset(new FolderMan{});
144+
QVERIFY(_folderMan->addFolder(accountState, folderDefinition));
145+
}
146+
147+
148+
void initTestCase()
149+
{
150+
OCC::Logger::instance()->setLogFlush(true);
151+
OCC::Logger::instance()->setLogDebug(true);
152+
153+
QStandardPaths::setTestModeEnabled(true);
154+
}
155+
156+
// Upgrade - TODO: test running app with --confdir
157+
void testUpgrade()
158+
{
159+
// create Nextcloud config with older version
160+
setupStandarConfig("1.0.0");
161+
const auto oldAppVersionNumber = QVersionNumber::fromString(_configFile.clientVersionString());
162+
QVERIFY(_configFile.isUpgrade());
163+
164+
// backup old config
165+
const auto backupFilesList = _configFile.backupConfigFiles();
166+
QCOMPARE_GE(backupFilesList.size(), 1);
167+
168+
// successfully upgrade to new config
169+
const auto afterUpgradeVersionNumber = MIRALL_VERSION_STRING;
170+
_configFile.setClientVersionString(afterUpgradeVersionNumber);
171+
QVERIFY(MIRALL_VERSION_STRING == _configFile.clientVersionString());
172+
173+
QCOMPARE_GE(AccountManager::instance()->accounts().size(), 1);
174+
auto accounts = AccountManager::instance()->accounts().first()->settings();
175+
QCOMPARE_GE(accounts->childGroups().size(), 1);
176+
accounts->beginGroup(QLatin1String("Folders"));
177+
QCOMPARE_GE(accounts->childGroups().size(), 1);
178+
accounts->endGroup();
179+
}
180+
181+
// From oC client to Nextcloud
182+
void testMigrationFromOctoNextcloud()
183+
{
184+
QTemporaryDir tempDir;
185+
QVERIFY(QDir(tempDir.path()).mkpath(legacyAppName));
186+
const auto ocConfigFolder = QString(tempDir.path() + "/" + legacyAppName);
187+
const auto ocConfig = QString(ocConfigFolder + "/" + QString(legacyAppName).toLower() + ".cfg");
188+
QFile ocConfigFile(ocConfig);
189+
QVERIFY(ocConfigFile.open(QFile::WriteOnly));
190+
QCOMPARE_GE(ocConfigFile.write(legacyAppConfigContent, qstrlen(legacyAppConfigContent)), 0);
191+
ocConfigFile.close();
192+
193+
ConfigFile configFile;
194+
195+
QVERIFY(QDir(tempDir.path()).mkpath(standardAppName));
196+
const auto standardConfigFolder = QString(tempDir.path() + "/" + standardAppName);
197+
configFile.setConfDir(standardConfigFolder);
198+
199+
// Nextcloud config file does not exist
200+
QVERIFY(!configFile.exists());
201+
202+
// owncloud config files exists
203+
configFile.findLegacyClientConfigFile();
204+
const auto legacyConfigFile = configFile.discoveredLegacyConfigFile();
205+
QVERIFY(!legacyConfigFile.isEmpty());
206+
QCOMPARE(legacyConfigFile, ocConfig);
207+
208+
// TODO: add accounts and folders to AccountManager and FolderMan without UI interference
209+
//_folderMan.reset({});
210+
// _folderMan.reset(new FolderMan{});
211+
// create accounts and folders from a legacy desktop client or for a new config file
212+
// QVERIFY(AccountManager::instance()->restore(configFile.configFileToRestore()) != AccountManager::AccountsRestoreFailure);
213+
// QCOMPARE_GE(FolderMan::instance()->setupFoldersMigration(), 1);
214+
// QVERIFY(configFile.configFile().contains("nextcloud"));
215+
// QCOMPARE_GE(AccountManager::instance()->accounts().size(), 1);
216+
// auto accounts = AccountManager::instance()->accounts().first()->settings();
217+
// QCOMPARE_GE(accounts->childGroups().size(), 1);
218+
// accounts->beginGroup(QLatin1String("Folders"));
219+
// QCOMPARE_GE(accounts->childGroups().size(), 1);
220+
// accounts->endGroup();
221+
}
222+
223+
// From branded oC client to branded Nextcloud
224+
void testMigrationFromBrandedOctoBrandedNextcloud()
225+
{
226+
QCoreApplication::setApplicationName(brandedAppName);
227+
setupStandardConfigFolder();
228+
229+
// branded legacy have directory name in lower case
230+
QTemporaryDir tempDir;
231+
QVERIFY(QDir(tempDir.path()).mkpath(ocBrandedAppName));
232+
const auto ocBrandedConfigFolder = QString(tempDir.path() + "/" + ocBrandedAppName);
233+
const auto ocBrandedConfig = QString(ocBrandedConfigFolder + "/" + QString(ocBrandedAppName) + ".cfg");
234+
QFile::copy(_configFile.configFile(), QFileInfo(ocBrandedConfig).filePath());
235+
236+
QFile ocBrandedConfigFile(ocBrandedConfig);
237+
QVERIFY(ocBrandedConfigFile.open(QFile::WriteOnly));
238+
QCOMPARE_GE(ocBrandedConfigFile.write(legacyAppConfigContent, qstrlen(legacyAppConfigContent)), 0);
239+
ocBrandedConfigFile.close();
240+
241+
ConfigFile configFile;
242+
QVERIFY(QDir(tempDir.path()).mkpath(brandedAppName));
243+
const auto brandedConfigFolder = QString(tempDir.path() + "/" + brandedAppName);
244+
configFile.setConfDir(brandedConfigFolder);
245+
246+
const auto path3 = _configFile.configFile();
247+
const auto path4 = configFile.configFile();
248+
249+
// our branded config file does not exist
250+
QVERIFY(!configFile.exists());
251+
252+
// branded owncloud config files exists
253+
configFile.findLegacyClientConfigFile();
254+
const auto legacyConfigFile = configFile.discoveredLegacyConfigFile();
255+
QVERIFY(!legacyConfigFile.isEmpty());
256+
QCOMPARE(legacyConfigFile, ocBrandedConfig);
257+
}
258+
259+
260+
// From the standard Nextcloud client to a branded version
261+
void testMigrationFromNextcloudToBranded()
262+
{
263+
setupStandardConfigFolder();
264+
265+
QTemporaryDir tempDir;
266+
QVERIFY(QDir(tempDir.path()).mkpath(brandedAppName));
267+
const auto brandedConfigFolder = QString(tempDir.path() + "/" + brandedAppName);
268+
const auto brandedConfig = QString(brandedConfigFolder + "/" + QString(brandedAppName).toLower() + ".cfg");
269+
QFile::copy(_configFile.configFile(), QFileInfo(brandedConfig).filePath());
270+
271+
ConfigFile configFile;
272+
QVERIFY(QDir(tempDir.path()).mkpath(standardAppName));
273+
const auto standardConfigFolder = QString(tempDir.path() + "/" + standardAppName);
274+
configFile.setConfDir(standardConfigFolder);
275+
276+
// Nextcloud config file does not exist
277+
QVERIFY(!configFile.exists());
278+
279+
// owncloud config files exists
280+
configFile.findLegacyClientConfigFile();
281+
const auto legacyConfigFile = configFile.discoveredLegacyConfigFile();
282+
QVERIFY(!legacyConfigFile.isEmpty());
283+
QCOMPARE(legacyConfigFile, brandedConfig);
284+
}
285+
286+
// TODO: Downgrade
287+
};
288+
289+
QTEST_GUILESS_MAIN(TestMigration)
290+
#include "testmigration.moc"

0 commit comments

Comments
 (0)