1 /*
2 SPDX-FileCopyrightText: 2014 Vishesh Handa <me@vhanda.in>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
7 #include "filewatch.h"
8 #include "fileindexerconfigutils.h"
9 #include "database.h"
10 #include "fileindexerconfig.h"
11 #include "pendingfilequeue.h"
12
13 #include <QTest>
14 #include <QSignalSpy>
15 #include <QTemporaryDir>
16 #include <KFileMetaData/UserMetaData>
17
18 namespace Baloo {
19
20 class FileWatchTest : public QObject
21 {
22 Q_OBJECT
23 private Q_SLOTS:
24
25 void testFileCreation();
26 void testConfigChange();
27 };
28
29 }
30
31 using namespace Baloo;
32
33 namespace {
createFile(const QString & fileUrl)34 bool createFile(const QString& fileUrl) {
35 QFile f1(fileUrl);
36 f1.open(QIODevice::WriteOnly);
37 f1.close();
38 return QFile::exists(fileUrl);
39 }
40
modifyFile(const QString & fileUrl)41 void modifyFile(const QString& fileUrl) {
42 QFile f1(fileUrl);
43 f1.open(QIODevice::Append | QIODevice::Text);
44
45 QTextStream stream(&f1);
46 stream << "1";
47 }
48 }
49
testFileCreation()50 void FileWatchTest::testFileCreation()
51 {
52 QTemporaryDir includeDir;
53
54 QStringList includeFolders;
55 includeFolders << includeDir.path();
56
57 QStringList excludeFolders;
58 Test::writeIndexerConfig(includeFolders, excludeFolders);
59
60 QTemporaryDir dbDir;
61 Database db(dbDir.path());
62 db.open(Baloo::Database::CreateDatabase);
63
64 FileIndexerConfig config;
65
66 FileWatch fileWatch(&db, &config);
67 fileWatch.m_pendingFileQueue->setMaximumTimeout(0);
68 fileWatch.m_pendingFileQueue->setMinimumTimeout(0);
69 fileWatch.m_pendingFileQueue->setTrackingTime(0);
70
71 QSignalSpy spy(&fileWatch, SIGNAL(installedWatches()));
72 QVERIFY(spy.isValid());
73
74 fileWatch.updateIndexedFoldersWatches();
75 QVERIFY(spy.count() || spy.wait());
76
77 QSignalSpy spyIndexNew(&fileWatch, SIGNAL(indexNewFile(QString)));
78 QSignalSpy spyIndexModified(&fileWatch, SIGNAL(indexModifiedFile(QString)));
79 QSignalSpy spyIndexXattr(&fileWatch, SIGNAL(indexXAttr(QString)));
80
81 QVERIFY(spyIndexNew.isValid());
82 QVERIFY(spyIndexModified.isValid());
83 QVERIFY(spyIndexXattr.isValid());
84
85 // Create a file and see if it is indexed
86 QString fileUrl(includeDir.path() + QStringLiteral("/t1"));
87 QVERIFY(createFile(fileUrl));
88
89 QVERIFY(spyIndexNew.wait());
90 QCOMPARE(spyIndexNew.count(), 1);
91 QCOMPARE(spyIndexModified.count(), 0);
92 QCOMPARE(spyIndexXattr.count(), 0);
93
94 spyIndexNew.clear();
95 spyIndexModified.clear();
96 spyIndexXattr.clear();
97
98 //
99 // Modify the file
100 //
101 modifyFile(fileUrl);
102
103 QVERIFY(spyIndexModified.wait());
104 QCOMPARE(spyIndexNew.count(), 0);
105 QCOMPARE(spyIndexModified.count(), 1);
106 QCOMPARE(spyIndexXattr.count(), 0);
107
108 spyIndexNew.clear();
109 spyIndexModified.clear();
110 spyIndexXattr.clear();
111
112 //
113 // Set an Xattr
114 //
115 KFileMetaData::UserMetaData umd(fileUrl);
116 if (!umd.isSupported()) {
117 qWarning() << "Xattr not supported on this filesystem:" << fileUrl;
118 return;
119 }
120
121 const QString userComment(QStringLiteral("UserComment"));
122 QVERIFY(umd.setUserComment(userComment) == KFileMetaData::UserMetaData::NoError);
123
124 QVERIFY(spyIndexXattr.wait());
125 QCOMPARE(spyIndexNew.count(), 0);
126 QCOMPARE(spyIndexModified.count(), 0);
127 QCOMPARE(spyIndexXattr.count(), 1);
128
129 spyIndexNew.clear();
130 spyIndexModified.clear();
131 spyIndexXattr.clear();
132 }
133
testConfigChange()134 void FileWatchTest::testConfigChange()
135 {
136 QTemporaryDir tmpDir;
137
138 Database db(tmpDir.path());
139 db.open(Baloo::Database::CreateDatabase);
140
141 QString d1 = tmpDir.path() + QStringLiteral("/d1");
142 QString d2 = tmpDir.path() + QStringLiteral("/d2");
143 QString d11 = tmpDir.path() + QStringLiteral("/d1/d11");
144 QString d21 = tmpDir.path() + QStringLiteral("/d2/d21");
145 QString d22 = tmpDir.path() + QStringLiteral("/d2/d22");
146
147 QDir().mkpath(d11);
148 QDir().mkpath(d21);
149 QDir().mkpath(d22);
150
151 // parameters: includeFolders list, excludeFolders list
152 Test::writeIndexerConfig({d1, d2}, {d11, d21});
153 FileIndexerConfig config;
154
155 FileWatch fileWatch(&db, &config);
156 fileWatch.m_pendingFileQueue->setMaximumTimeout(0);
157 fileWatch.m_pendingFileQueue->setMinimumTimeout(0);
158 fileWatch.m_pendingFileQueue->setTrackingTime(0);
159
160 QSignalSpy spy(&fileWatch, SIGNAL(installedWatches()));
161 QVERIFY(spy.isValid());
162
163 fileWatch.updateIndexedFoldersWatches();
164 QVERIFY(spy.count() || spy.wait());
165
166 QSignalSpy spyIndexNew(&fileWatch, SIGNAL(indexNewFile(QString)));
167 QVERIFY(spyIndexNew.isValid());
168 QVERIFY(createFile(d1 + QStringLiteral("/t1")));
169 QVERIFY(createFile(d2 + QStringLiteral("/t2")));
170
171 QVERIFY(spyIndexNew.wait());
172 QCOMPARE(spyIndexNew.count(), 2);
173 spyIndexNew.clear();
174
175 // dir d22 is not yet excluded, so one event is expected
176 QVERIFY(createFile(d11 + QStringLiteral("/tx1")));
177 QVERIFY(createFile(d21 + QStringLiteral("/tx2")));
178 QVERIFY(createFile(d22 + QStringLiteral("/tx3")));
179
180 QVERIFY(spyIndexNew.wait());
181 QCOMPARE(spyIndexNew.count(), 1);
182 QList<QVariant> event = spyIndexNew.at(0);
183 QCOMPARE(event.at(0).toString(), d22 + QStringLiteral("/tx3"));
184 spyIndexNew.clear();
185
186 Test::writeIndexerConfig({d2}, {d22});
187 config.forceConfigUpdate();
188 fileWatch.updateIndexedFoldersWatches();
189
190 // dir d1 is no longer included
191 QVERIFY(createFile(d1 + QStringLiteral("/tx1a")));
192 QVERIFY(createFile(d2 + QStringLiteral("/tx2a")));
193 QVERIFY(spyIndexNew.wait());
194 QList<QString> result;
195 for (const QList<QVariant>& event : std::as_const(spyIndexNew)) {
196 result.append(event.at(0).toString());
197 }
198 QCOMPARE(result, {d2 + QStringLiteral("/tx2a")});
199 spyIndexNew.clear();
200 result.clear();
201
202 // d11 is implicitly excluded, as d1 is no longer included
203 // d22 is explicitly excluded now, d21 is included
204 QVERIFY(createFile(d11 + QStringLiteral("/tx1b")));
205 QVERIFY(createFile(d21 + QStringLiteral("/tx2b")));
206 QVERIFY(createFile(d22 + QStringLiteral("/tx3b")));
207
208 QVERIFY(spyIndexNew.wait(500));
209 for (const QList<QVariant>& event : std::as_const(spyIndexNew)) {
210 result.append(event.at(0).toString());
211 }
212 QCOMPARE(result, {d21 + QStringLiteral("/tx2b")});
213 }
214
215 QTEST_MAIN(FileWatchTest)
216
217 #include "filewatchtest.moc"
218