1 /*=========================================================================
2
3 Library: CTK
4
5 Copyright (c) 2013 University College London, Centre for Medical Image Computing
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0.txt
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19 =========================================================================*/
20
21 #include "ctkXnatSessionTest.h"
22
23 #include <QCoreApplication>
24 #include <QCryptographicHash>
25 #include <QDebug>
26 #include <QDir>
27 #include <QSignalSpy>
28 #include <QStringList>
29 #include <QTest>
30 #include <QTime>
31 #include <QTimer>
32 #include <QUrl>
33 #include <QUuid>
34
35 #include <ctkXnatDataModel.h>
36 #include <ctkXnatException.h>
37 #include <ctkXnatFile.h>
38 #include <ctkXnatLoginProfile.h>
39 #include <ctkXnatProject.h>
40 #include <ctkXnatResource.h>
41 #include <ctkXnatResourceFolder.h>
42 #include <ctkXnatSession.h>
43 #include <ctkXnatSubject.h>
44
45 class ctkXnatSessionTestCasePrivate
46 {
47 public:
48 ctkXnatSession* Session;
49
50 ctkXnatLoginProfile LoginProfile;
51
52 QString Project;
53 QString Subject;
54 QString Experiment;
55
56 QDateTime DateTime;
57 };
58
59 // --------------------------------------------------------------------------
ctkXnatSessionTestCase()60 ctkXnatSessionTestCase::ctkXnatSessionTestCase()
61 : d_ptr(new ctkXnatSessionTestCasePrivate())
62 {
63 }
64
65 // --------------------------------------------------------------------------
~ctkXnatSessionTestCase()66 ctkXnatSessionTestCase::~ctkXnatSessionTestCase()
67 {
68 }
69
70 // --------------------------------------------------------------------------
initTestCase()71 void ctkXnatSessionTestCase::initTestCase()
72 {
73 Q_D(ctkXnatSessionTestCase);
74
75 d->LoginProfile.setName("ctk");
76 d->LoginProfile.setServerUrl(QString("https://central.xnat.org"));
77 d->LoginProfile.setUserName("ctk");
78 d->LoginProfile.setPassword("ctk-xnat2015");
79 }
80
81 // --------------------------------------------------------------------------
init()82 void ctkXnatSessionTestCase::init()
83 {
84 Q_D(ctkXnatSessionTestCase);
85
86 d->DateTime = QDateTime::currentDateTime();
87 d->Session = new ctkXnatSession(d->LoginProfile);
88 d->Session->open();
89 }
90
91 // --------------------------------------------------------------------------
cleanupTestCase()92 void ctkXnatSessionTestCase::cleanupTestCase()
93 {
94 }
95
96 // --------------------------------------------------------------------------
cleanup()97 void ctkXnatSessionTestCase::cleanup()
98 {
99 Q_D(ctkXnatSessionTestCase);
100
101 delete d->Session;
102 d->Session = NULL;
103 }
104
105 // --------------------------------------------------------------------------
testProjectList()106 void ctkXnatSessionTestCase::testProjectList()
107 {
108 Q_D(ctkXnatSessionTestCase);
109
110 ctkXnatObject* dataModel = d->Session->dataModel();
111 dataModel->fetch();
112
113 QList<ctkXnatObject*> projects = dataModel->children();
114
115 QVERIFY(projects.size() > 0);
116 }
117
118 // --------------------------------------------------------------------------
testResourceUri()119 void ctkXnatSessionTestCase::testResourceUri()
120 {
121 Q_D(ctkXnatSessionTestCase);
122
123 ctkXnatObject* dataModel = d->Session->dataModel();
124 QVERIFY(!dataModel->resourceUri().isNull());
125 QVERIFY(dataModel->resourceUri().isEmpty());
126 }
127
128 // --------------------------------------------------------------------------
testParentChild()129 void ctkXnatSessionTestCase::testParentChild()
130 {
131 Q_D(ctkXnatSessionTestCase);
132
133 ctkXnatDataModel* dataModel = d->Session->dataModel();
134
135 ctkXnatProject* project = new ctkXnatProject(dataModel);
136
137 QVERIFY(project->parent() == dataModel);
138
139 QVERIFY(dataModel->children().contains(project));
140
141 dataModel->add(project);
142
143 int numberOfOccurrences = 0;
144 foreach (ctkXnatObject* serverProject, dataModel->children())
145 {
146 if (serverProject == project || serverProject->id() == project->id())
147 {
148 ++numberOfOccurrences;
149 }
150 }
151 QVERIFY(numberOfOccurrences == 1);
152
153 dataModel->remove(project);
154 numberOfOccurrences = 0;
155 foreach (ctkXnatObject* serverProject, dataModel->children())
156 {
157 if (serverProject == project || serverProject->id() == project->id())
158 {
159 ++numberOfOccurrences;
160 }
161 }
162 QVERIFY(numberOfOccurrences == 0);
163 delete project;
164 }
165
166 // --------------------------------------------------------------------------
testSession()167 void ctkXnatSessionTestCase::testSession()
168 {
169 Q_D(ctkXnatSessionTestCase);
170
171 QVERIFY(d->Session->isOpen());
172 QDateTime expirationDate = d->Session->expirationDate();
173
174 QVERIFY(d->DateTime < expirationDate);
175
176 QTest::qSleep(2000);
177
178 QUuid uuid = d->Session->httpGet("/data/version");
179 QVERIFY(!uuid.isNull());
180 d->Session->httpSync(uuid);
181
182 QVERIFY(expirationDate < d->Session->expirationDate());
183
184 try
185 {
186 d->Session->httpSync(uuid);
187 QFAIL("Exception for unknown uuid expected");
188 }
189 catch(const ctkInvalidArgumentException&)
190 {}
191
192 d->Session->close();
193 try
194 {
195 d->Session->dataModel();
196 QFAIL("Exception for closed session expected");
197 }
198 catch(const ctkXnatInvalidSessionException&)
199 {}
200 }
201
202 // --------------------------------------------------------------------------
testAuthenticationError()203 void ctkXnatSessionTestCase::testAuthenticationError()
204 {
205 ctkXnatLoginProfile loginProfile;
206 loginProfile.setName("error");
207 loginProfile.setServerUrl(QString("https://central.xnat.org"));
208 loginProfile.setUserName("x");
209 loginProfile.setPassword("y");
210
211 ctkXnatSession session(loginProfile);
212 try
213 {
214 session.open();
215 QFAIL("Authenication error exception expected");
216 }
217 catch (const ctkXnatAuthenticationException&)
218 {}
219 }
220
221 // --------------------------------------------------------------------------
testCreateProject()222 void ctkXnatSessionTestCase::testCreateProject()
223 {
224 Q_D(ctkXnatSessionTestCase);
225
226 ctkXnatDataModel* dataModel = d->Session->dataModel();
227
228 QString projectId = QString("CTK_") + QUuid::createUuid().toString().mid(1, 8);
229 d->Project = projectId;
230
231 ctkXnatProject* project = new ctkXnatProject(dataModel);
232 project->setId(projectId);
233 project->setName(projectId);
234 project->setDescription("CTK_test_project");
235
236 bool exists = d->Session->exists(project);
237 QVERIFY(!exists);
238
239 project->save();
240
241 exists = d->Session->exists(project);
242 QVERIFY(exists);
243
244 d->Session->remove(project);
245
246 exists = d->Session->exists(project);
247 QVERIFY(!exists);
248 }
249
250 // --------------------------------------------------------------------------
testCreateSubject()251 void ctkXnatSessionTestCase::testCreateSubject()
252 {
253 Q_D(ctkXnatSessionTestCase);
254
255 ctkXnatDataModel* dataModel = d->Session->dataModel();
256
257 QString projectId = QString("CTK_") + QUuid::createUuid().toString().mid(1, 8);
258 d->Project = projectId;
259
260 ctkXnatProject* project = new ctkXnatProject(dataModel);
261 project->setId(projectId);
262 project->setName(projectId);
263 project->setDescription("CTK_test_project");
264
265 QVERIFY(!project->exists());
266
267 project->save();
268
269 QVERIFY(project->exists());
270
271 ctkXnatSubject* subject = new ctkXnatSubject(project);
272
273 QString subjectName = QString("CTK_S") + QUuid::createUuid().toString().mid(1, 8);
274 subject->setName(subjectName);
275
276 subject->save();
277
278 QVERIFY(!subject->id().isNull());
279
280 subject->erase();
281
282 QVERIFY(!subject->exists());
283
284 project->erase();
285
286 QVERIFY(!project->exists());
287 }
288
289 // --------------------------------------------------------------------------
testAddResourceFolder()290 void ctkXnatSessionTestCase::testAddResourceFolder()
291 {
292 Q_D(ctkXnatSessionTestCase);
293
294 ctkXnatDataModel* dataModel = d->Session->dataModel();
295
296 QString projectId = QString("CTK_") + QUuid::createUuid().toString().mid(1, 8);
297 d->Project = projectId;
298
299 ctkXnatProject* project = new ctkXnatProject(dataModel);
300 project->setId(projectId);
301 project->setName(projectId);
302 project->setDescription("CTK_test_project");
303
304 QVERIFY(!project->exists());
305
306 project->save();
307
308 QVERIFY(project->exists());
309
310 ctkXnatResource* resource = project->addResourceFolder("TestResource", "testFormat", "testContent", "testTag1,testTag2");
311 QVERIFY(resource->exists());
312 QVERIFY(resource->name() == "TestResource");
313 QVERIFY(resource->format() == "testFormat");
314 QVERIFY(resource->content() == "testContent");
315 QVERIFY(resource->tags() == "testTag1,testTag2");
316
317 ctkXnatResourceFolder* folder = dynamic_cast<ctkXnatResourceFolder*>(resource->parent());
318 QVERIFY(folder->exists());
319 QVERIFY(folder != 0);
320 QVERIFY(folder->name() == "Resources");
321
322 project->erase();
323 QVERIFY(!project->exists());
324 QVERIFY(!folder->exists());
325 QVERIFY(!resource->exists());
326 }
327
328 // --------------------------------------------------------------------------
testUploadAndDownloadFile()329 void ctkXnatSessionTestCase::testUploadAndDownloadFile()
330 {
331 Q_D(ctkXnatSessionTestCase);
332
333 ctkXnatDataModel* dataModel = d->Session->dataModel();
334
335 QString projectId = QString("CTK_") + QUuid::createUuid().toString().mid(1, 8);
336 d->Project = projectId;
337
338 ctkXnatProject* project = new ctkXnatProject(dataModel);
339 project->setId(projectId);
340 project->setName(projectId);
341 project->setDescription("CTK_test_project");
342
343 QVERIFY(!project->exists());
344
345 project->save();
346
347 QVERIFY(project->exists());
348
349 ctkXnatResource* resource = project->addResourceFolder("TestResourceContainingData");
350 QVERIFY(resource->exists());
351 QVERIFY(resource->name() == "TestResourceContainingData");
352 QVERIFY(resource->format() == "");
353 QVERIFY(resource->content() == "");
354 QVERIFY(resource->tags() == "");
355
356 QString tempDirPath = QDir::tempPath() + QUuid::createUuid().toString().mid(1, 8);
357 QString uploadFileName = tempDirPath + "/ctk_xnat_upload_" + QUuid::createUuid().toString().mid(1, 8) + ".txt";
358 QString downloadFileName = tempDirPath + "/ctk_xnat_download_" + QUuid::createUuid().toString().mid(1, 8) + ".txt";
359
360 QDir tempDir;
361 if (tempDir.mkdir(tempDirPath))
362 {
363 QFile uploadedFile(uploadFileName);
364
365 if (uploadedFile.open(QFile::ReadWrite))
366 {
367 QTextStream stream( &uploadedFile );
368 stream << "Hi, I am a CTK test file! ;-)" << endl;
369
370 QFileInfo fileInfo;
371 fileInfo.setFile(uploadFileName);
372 // Create xnatFile object
373 ctkXnatFile* xnatFile = new ctkXnatFile(resource);
374 xnatFile->setLocalFilePath(fileInfo.filePath());
375 xnatFile->setName(fileInfo.fileName());
376 xnatFile->setFileFormat("some format");
377 xnatFile->setFileContent("some content");
378 xnatFile->setFileTags("some, tags");
379 resource->add(xnatFile);
380
381 // Actual file upload
382 xnatFile->save();
383
384 QVERIFY(xnatFile->exists());
385
386 xnatFile->download(downloadFileName);
387
388 QFile downloadedFile(downloadFileName);
389
390 QVERIFY(downloadedFile.exists());
391
392 uploadedFile.close();
393 if (downloadedFile.open(QFile::ReadOnly) && uploadedFile.open(QFile::ReadOnly))
394 {
395 QCryptographicHash hashUploaded(QCryptographicHash::Md5);
396 QCryptographicHash hashDownloaded(QCryptographicHash::Md5);
397
398 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
399 hashUploaded.addData(&uploadedFile);
400 hashDownloaded.addData(&downloadedFile);
401 #else
402 hashUploaded.addData(uploadedFile.readAll());
403 hashDownloaded.addData(downloadedFile.readAll());
404 #endif
405
406 QString md5ChecksumUploaded(hashUploaded.result().toHex());
407 QString md5ChecksumDownloaded(hashDownloaded.result().toHex());
408
409 QVERIFY (md5ChecksumDownloaded == md5ChecksumUploaded);
410
411 // Remove the data from XNAT
412 project->erase();
413 QVERIFY(!project->exists());
414 QVERIFY(!resource->exists());
415 QVERIFY(!xnatFile->exists());
416
417 // Remove the local data
418 uploadedFile.close();
419 downloadedFile.close();
420 uploadedFile.remove();
421 downloadedFile.remove();
422 tempDir.cdUp();
423 tempDir.rmdir(tempDirPath);
424 }
425 else
426 {
427 qWarning()<<"Could not open files for validation! Could not finish test!";
428 }
429 }
430 else
431 {
432 qWarning()<<"Could not create temporary file for upload! Could not finish test!";
433 return;
434 }
435 }
436 else
437 {
438 qWarning()<<"Could not create temporary directory! Could not finish test!";
439 }
440 }
441
442 // --------------------------------------------------------------------------
ctkXnatSessionTest(int argc,char * argv[])443 int ctkXnatSessionTest(int argc, char* argv[])
444 {
445 QCoreApplication app(argc, argv);
446 ctkXnatSessionTestCase test;
447 return QTest::qExec(&test, argc, argv);
448 }
449