Mercurial > hg > orthanc
comparison UnitTestsSources/MultiThreadingTests.cpp @ 2884:497a637366b4 db-changes
integration mainline->db-changes
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 12 Oct 2018 15:18:10 +0200 |
parents | 9d08edde614b |
children | 22524fd06225 |
comparison
equal
deleted
inserted
replaced
1762:2b91363cc1d1 | 2884:497a637366b4 |
---|---|
1 /** | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | 2 * Orthanc - A Lightweight, RESTful DICOM Store |
3 * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
4 * Department, University Hospital of Liege, Belgium | 4 * Department, University Hospital of Liege, Belgium |
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium | |
5 * | 6 * |
6 * This program is free software: you can redistribute it and/or | 7 * This program is free software: you can redistribute it and/or |
7 * modify it under the terms of the GNU General Public License as | 8 * modify it under the terms of the GNU General Public License as |
8 * published by the Free Software Foundation, either version 3 of the | 9 * published by the Free Software Foundation, either version 3 of the |
9 * License, or (at your option) any later version. | 10 * License, or (at your option) any later version. |
31 | 32 |
32 | 33 |
33 #include "PrecompiledHeadersUnitTests.h" | 34 #include "PrecompiledHeadersUnitTests.h" |
34 #include "gtest/gtest.h" | 35 #include "gtest/gtest.h" |
35 | 36 |
36 #include "../OrthancServer/Scheduler/ServerScheduler.h" | 37 #include "../Core/FileStorage/MemoryStorageArea.h" |
38 #include "../Core/JobsEngine/JobsEngine.h" | |
39 #include "../Core/Logging.h" | |
40 #include "../Core/MultiThreading/SharedMessageQueue.h" | |
37 #include "../Core/OrthancException.h" | 41 #include "../Core/OrthancException.h" |
42 #include "../Core/SerializationToolbox.h" | |
43 #include "../Core/SystemToolbox.h" | |
38 #include "../Core/Toolbox.h" | 44 #include "../Core/Toolbox.h" |
39 #include "../Core/MultiThreading/Locker.h" | 45 #include "../OrthancServer/DatabaseWrapper.h" |
40 #include "../Core/MultiThreading/Mutex.h" | 46 #include "../OrthancServer/ServerContext.h" |
41 #include "../Core/MultiThreading/ReaderWriterLock.h" | 47 #include "../OrthancServer/ServerJobs/LuaJobManager.h" |
48 #include "../OrthancServer/ServerJobs/OrthancJobUnserializer.h" | |
49 | |
50 #include "../Core/JobsEngine/Operations/JobOperationValues.h" | |
51 #include "../Core/JobsEngine/Operations/NullOperationValue.h" | |
52 #include "../Core/JobsEngine/Operations/StringOperationValue.h" | |
53 #include "../OrthancServer/ServerJobs/Operations/DicomInstanceOperationValue.h" | |
54 | |
55 #include "../Core/JobsEngine/Operations/LogJobOperation.h" | |
56 #include "../OrthancServer/ServerJobs/Operations/DeleteResourceOperation.h" | |
57 #include "../OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.h" | |
58 #include "../OrthancServer/ServerJobs/Operations/StorePeerOperation.h" | |
59 #include "../OrthancServer/ServerJobs/Operations/StoreScuOperation.h" | |
60 #include "../OrthancServer/ServerJobs/Operations/SystemCallOperation.h" | |
61 | |
62 #include "../OrthancServer/ServerJobs/ArchiveJob.h" | |
63 #include "../OrthancServer/ServerJobs/DicomModalityStoreJob.h" | |
64 #include "../OrthancServer/ServerJobs/MergeStudyJob.h" | |
65 #include "../OrthancServer/ServerJobs/OrthancPeerStoreJob.h" | |
66 #include "../OrthancServer/ServerJobs/ResourceModificationJob.h" | |
67 #include "../OrthancServer/ServerJobs/SplitStudyJob.h" | |
68 | |
42 | 69 |
43 using namespace Orthanc; | 70 using namespace Orthanc; |
44 | 71 |
45 namespace | 72 namespace |
46 { | 73 { |
74 class DummyJob : public IJob | |
75 { | |
76 private: | |
77 bool fails_; | |
78 unsigned int count_; | |
79 unsigned int steps_; | |
80 | |
81 public: | |
82 DummyJob() : | |
83 fails_(false), | |
84 count_(0), | |
85 steps_(4) | |
86 { | |
87 } | |
88 | |
89 explicit DummyJob(bool fails) : | |
90 fails_(fails), | |
91 count_(0), | |
92 steps_(4) | |
93 { | |
94 } | |
95 | |
96 virtual void Start() | |
97 { | |
98 } | |
99 | |
100 virtual void Reset() | |
101 { | |
102 } | |
103 | |
104 virtual JobStepResult Step() | |
105 { | |
106 if (fails_) | |
107 { | |
108 return JobStepResult::Failure(ErrorCode_ParameterOutOfRange); | |
109 } | |
110 else if (count_ == steps_ - 1) | |
111 { | |
112 return JobStepResult::Success(); | |
113 } | |
114 else | |
115 { | |
116 count_++; | |
117 return JobStepResult::Continue(); | |
118 } | |
119 } | |
120 | |
121 virtual void Stop(JobStopReason reason) | |
122 { | |
123 } | |
124 | |
125 virtual float GetProgress() | |
126 { | |
127 return static_cast<float>(count_) / static_cast<float>(steps_ - 1); | |
128 } | |
129 | |
130 virtual void GetJobType(std::string& type) | |
131 { | |
132 type = "DummyJob"; | |
133 } | |
134 | |
135 virtual bool Serialize(Json::Value& value) | |
136 { | |
137 value = Json::objectValue; | |
138 value["Type"] = "DummyJob"; | |
139 return true; | |
140 } | |
141 | |
142 virtual void GetPublicContent(Json::Value& value) | |
143 { | |
144 value["hello"] = "world"; | |
145 } | |
146 }; | |
147 | |
148 | |
149 class DummyInstancesJob : public SetOfInstancesJob | |
150 { | |
151 private: | |
152 bool trailingStepDone_; | |
153 | |
154 protected: | |
155 virtual bool HandleInstance(const std::string& instance) | |
156 { | |
157 return (instance != "nope"); | |
158 } | |
159 | |
160 virtual bool HandleTrailingStep() | |
161 { | |
162 if (HasTrailingStep()) | |
163 { | |
164 if (trailingStepDone_) | |
165 { | |
166 throw OrthancException(ErrorCode_InternalError); | |
167 } | |
168 else | |
169 { | |
170 trailingStepDone_ = true; | |
171 return true; | |
172 } | |
173 } | |
174 else | |
175 { | |
176 throw OrthancException(ErrorCode_InternalError); | |
177 } | |
178 } | |
179 | |
180 public: | |
181 DummyInstancesJob() : | |
182 trailingStepDone_(false) | |
183 { | |
184 } | |
185 | |
186 DummyInstancesJob(const Json::Value& value) : | |
187 SetOfInstancesJob(value) | |
188 { | |
189 if (HasTrailingStep()) | |
190 { | |
191 trailingStepDone_ = (GetPosition() == GetCommandsCount()); | |
192 } | |
193 else | |
194 { | |
195 trailingStepDone_ = false; | |
196 } | |
197 } | |
198 | |
199 bool IsTrailingStepDone() const | |
200 { | |
201 return trailingStepDone_; | |
202 } | |
203 | |
204 virtual void Stop(JobStopReason reason) | |
205 { | |
206 } | |
207 | |
208 virtual void GetJobType(std::string& s) | |
209 { | |
210 s = "DummyInstancesJob"; | |
211 } | |
212 }; | |
213 | |
214 | |
215 class DummyUnserializer : public GenericJobUnserializer | |
216 { | |
217 public: | |
218 virtual IJob* UnserializeJob(const Json::Value& value) | |
219 { | |
220 if (SerializationToolbox::ReadString(value, "Type") == "DummyInstancesJob") | |
221 { | |
222 return new DummyInstancesJob(value); | |
223 } | |
224 else if (SerializationToolbox::ReadString(value, "Type") == "DummyJob") | |
225 { | |
226 return new DummyJob; | |
227 } | |
228 else | |
229 { | |
230 return GenericJobUnserializer::UnserializeJob(value); | |
231 } | |
232 } | |
233 }; | |
234 | |
235 | |
47 class DynamicInteger : public IDynamicObject | 236 class DynamicInteger : public IDynamicObject |
48 { | 237 { |
49 private: | 238 private: |
50 int value_; | 239 int value_; |
51 std::set<int>& target_; | 240 std::set<int>& target_; |
102 { | 291 { |
103 } | 292 } |
104 } | 293 } |
105 | 294 |
106 | 295 |
107 TEST(MultiThreading, Mutex) | 296 |
108 { | 297 |
109 Mutex mutex; | 298 static bool CheckState(JobsRegistry& registry, |
110 Locker locker(mutex); | 299 const std::string& id, |
111 } | 300 JobState state) |
112 | 301 { |
113 | 302 JobState s; |
114 TEST(MultiThreading, ReaderWriterLock) | 303 if (registry.GetState(s, id)) |
115 { | 304 { |
116 ReaderWriterLock lock; | 305 return state == s; |
117 | 306 } |
118 { | 307 else |
119 Locker locker1(lock.ForReader()); | 308 { |
120 Locker locker2(lock.ForReader()); | 309 return false; |
121 } | 310 } |
122 | 311 } |
123 { | 312 |
124 Locker locker3(lock.ForWriter()); | 313 |
125 } | 314 static bool CheckErrorCode(JobsRegistry& registry, |
126 } | 315 const std::string& id, |
127 | 316 ErrorCode code) |
128 | 317 { |
129 | 318 JobInfo s; |
130 #include "../OrthancServer/DicomProtocol/ReusableDicomUserConnection.h" | 319 if (registry.GetJobInfo(s, id)) |
131 | 320 { |
132 TEST(ReusableDicomUserConnection, DISABLED_Basic) | 321 return code == s.GetStatus().GetErrorCode(); |
133 { | 322 } |
134 ReusableDicomUserConnection c; | 323 else |
135 c.SetMillisecondsBeforeClose(200); | 324 { |
136 printf("START\n"); fflush(stdout); | 325 return false; |
137 | 326 } |
138 { | 327 } |
139 RemoteModalityParameters remote("STORESCP", "localhost", 2000, ModalityManufacturer_Generic); | 328 |
140 ReusableDicomUserConnection::Locker lock(c, "ORTHANC", remote); | 329 |
141 lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676281"); | 330 TEST(JobsRegistry, Priority) |
142 } | 331 { |
143 | 332 JobsRegistry registry; |
144 printf("**\n"); fflush(stdout); | 333 |
145 Toolbox::USleep(1000000); | 334 std::string i1, i2, i3, i4; |
146 printf("**\n"); fflush(stdout); | 335 registry.Submit(i1, new DummyJob(), 10); |
147 | 336 registry.Submit(i2, new DummyJob(), 30); |
148 { | 337 registry.Submit(i3, new DummyJob(), 20); |
149 RemoteModalityParameters remote("STORESCP", "localhost", 2000, ModalityManufacturer_Generic); | 338 registry.Submit(i4, new DummyJob(), 5); |
150 ReusableDicomUserConnection::Locker lock(c, "ORTHANC", remote); | 339 |
151 lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676277"); | 340 registry.SetMaxCompletedJobs(2); |
152 } | 341 |
153 | 342 std::set<std::string> id; |
154 Toolbox::ServerBarrier(); | 343 registry.ListJobs(id); |
155 printf("DONE\n"); fflush(stdout); | 344 |
156 } | 345 ASSERT_EQ(4u, id.size()); |
157 | 346 ASSERT_TRUE(id.find(i1) != id.end()); |
158 | 347 ASSERT_TRUE(id.find(i2) != id.end()); |
159 | 348 ASSERT_TRUE(id.find(i3) != id.end()); |
160 class Tutu : public IServerCommand | 349 ASSERT_TRUE(id.find(i4) != id.end()); |
161 { | 350 |
162 private: | 351 ASSERT_TRUE(CheckState(registry, i2, JobState_Pending)); |
163 int factor_; | 352 |
164 | 353 { |
165 public: | 354 JobsRegistry::RunningJob job(registry, 0); |
166 Tutu(int f) : factor_(f) | 355 ASSERT_TRUE(job.IsValid()); |
167 { | 356 ASSERT_EQ(30, job.GetPriority()); |
168 } | 357 ASSERT_EQ(i2, job.GetId()); |
169 | 358 |
170 virtual bool Apply(ListOfStrings& outputs, | 359 ASSERT_TRUE(CheckState(registry, i2, JobState_Running)); |
171 const ListOfStrings& inputs) | 360 } |
172 { | 361 |
173 for (ListOfStrings::const_iterator | 362 ASSERT_TRUE(CheckState(registry, i2, JobState_Failure)); |
174 it = inputs.begin(); it != inputs.end(); ++it) | 363 ASSERT_TRUE(CheckState(registry, i3, JobState_Pending)); |
175 { | 364 |
176 int a = boost::lexical_cast<int>(*it); | 365 { |
177 int b = factor_ * a; | 366 JobsRegistry::RunningJob job(registry, 0); |
178 | 367 ASSERT_TRUE(job.IsValid()); |
179 printf("%d * %d = %d\n", a, factor_, b); | 368 ASSERT_EQ(20, job.GetPriority()); |
180 | 369 ASSERT_EQ(i3, job.GetId()); |
181 //if (a == 84) { printf("BREAK\n"); return false; } | 370 |
182 | 371 job.MarkSuccess(); |
183 outputs.push_back(boost::lexical_cast<std::string>(b)); | 372 |
184 } | 373 ASSERT_TRUE(CheckState(registry, i3, JobState_Running)); |
185 | 374 } |
186 Toolbox::USleep(30000); | 375 |
187 | 376 ASSERT_TRUE(CheckState(registry, i3, JobState_Success)); |
377 | |
378 { | |
379 JobsRegistry::RunningJob job(registry, 0); | |
380 ASSERT_TRUE(job.IsValid()); | |
381 ASSERT_EQ(10, job.GetPriority()); | |
382 ASSERT_EQ(i1, job.GetId()); | |
383 } | |
384 | |
385 { | |
386 JobsRegistry::RunningJob job(registry, 0); | |
387 ASSERT_TRUE(job.IsValid()); | |
388 ASSERT_EQ(5, job.GetPriority()); | |
389 ASSERT_EQ(i4, job.GetId()); | |
390 } | |
391 | |
392 { | |
393 JobsRegistry::RunningJob job(registry, 1); | |
394 ASSERT_FALSE(job.IsValid()); | |
395 } | |
396 | |
397 JobState s; | |
398 ASSERT_TRUE(registry.GetState(s, i1)); | |
399 ASSERT_FALSE(registry.GetState(s, i2)); // Removed because oldest | |
400 ASSERT_FALSE(registry.GetState(s, i3)); // Removed because second oldest | |
401 ASSERT_TRUE(registry.GetState(s, i4)); | |
402 | |
403 registry.SetMaxCompletedJobs(1); // (*) | |
404 ASSERT_FALSE(registry.GetState(s, i1)); // Just discarded by (*) | |
405 ASSERT_TRUE(registry.GetState(s, i4)); | |
406 } | |
407 | |
408 | |
409 TEST(JobsRegistry, Simultaneous) | |
410 { | |
411 JobsRegistry registry; | |
412 | |
413 std::string i1, i2; | |
414 registry.Submit(i1, new DummyJob(), 20); | |
415 registry.Submit(i2, new DummyJob(), 10); | |
416 | |
417 ASSERT_TRUE(CheckState(registry, i1, JobState_Pending)); | |
418 ASSERT_TRUE(CheckState(registry, i2, JobState_Pending)); | |
419 | |
420 { | |
421 JobsRegistry::RunningJob job1(registry, 0); | |
422 JobsRegistry::RunningJob job2(registry, 0); | |
423 | |
424 ASSERT_TRUE(job1.IsValid()); | |
425 ASSERT_TRUE(job2.IsValid()); | |
426 | |
427 job1.MarkFailure(); | |
428 job2.MarkSuccess(); | |
429 | |
430 ASSERT_TRUE(CheckState(registry, i1, JobState_Running)); | |
431 ASSERT_TRUE(CheckState(registry, i2, JobState_Running)); | |
432 } | |
433 | |
434 ASSERT_TRUE(CheckState(registry, i1, JobState_Failure)); | |
435 ASSERT_TRUE(CheckState(registry, i2, JobState_Success)); | |
436 } | |
437 | |
438 | |
439 TEST(JobsRegistry, Resubmit) | |
440 { | |
441 JobsRegistry registry; | |
442 | |
443 std::string id; | |
444 registry.Submit(id, new DummyJob(), 10); | |
445 | |
446 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
447 | |
448 registry.Resubmit(id); | |
449 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
450 | |
451 { | |
452 JobsRegistry::RunningJob job(registry, 0); | |
453 ASSERT_TRUE(job.IsValid()); | |
454 job.MarkFailure(); | |
455 | |
456 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
457 | |
458 registry.Resubmit(id); | |
459 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
460 } | |
461 | |
462 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
463 | |
464 registry.Resubmit(id); | |
465 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
466 | |
467 { | |
468 JobsRegistry::RunningJob job(registry, 0); | |
469 ASSERT_TRUE(job.IsValid()); | |
470 ASSERT_EQ(id, job.GetId()); | |
471 | |
472 job.MarkSuccess(); | |
473 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
474 } | |
475 | |
476 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
477 | |
478 registry.Resubmit(id); | |
479 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
480 } | |
481 | |
482 | |
483 TEST(JobsRegistry, Retry) | |
484 { | |
485 JobsRegistry registry; | |
486 | |
487 std::string id; | |
488 registry.Submit(id, new DummyJob(), 10); | |
489 | |
490 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
491 | |
492 { | |
493 JobsRegistry::RunningJob job(registry, 0); | |
494 ASSERT_TRUE(job.IsValid()); | |
495 job.MarkRetry(0); | |
496 | |
497 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
498 } | |
499 | |
500 ASSERT_TRUE(CheckState(registry, id, JobState_Retry)); | |
501 | |
502 registry.Resubmit(id); | |
503 ASSERT_TRUE(CheckState(registry, id, JobState_Retry)); | |
504 | |
505 registry.ScheduleRetries(); | |
506 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
507 | |
508 { | |
509 JobsRegistry::RunningJob job(registry, 0); | |
510 ASSERT_TRUE(job.IsValid()); | |
511 job.MarkSuccess(); | |
512 | |
513 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
514 } | |
515 | |
516 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
517 } | |
518 | |
519 | |
520 TEST(JobsRegistry, PausePending) | |
521 { | |
522 JobsRegistry registry; | |
523 | |
524 std::string id; | |
525 registry.Submit(id, new DummyJob(), 10); | |
526 | |
527 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
528 | |
529 registry.Pause(id); | |
530 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
531 | |
532 registry.Pause(id); | |
533 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
534 | |
535 registry.Resubmit(id); | |
536 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
537 | |
538 registry.Resume(id); | |
539 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
540 } | |
541 | |
542 | |
543 TEST(JobsRegistry, PauseRunning) | |
544 { | |
545 JobsRegistry registry; | |
546 | |
547 std::string id; | |
548 registry.Submit(id, new DummyJob(), 10); | |
549 | |
550 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
551 | |
552 { | |
553 JobsRegistry::RunningJob job(registry, 0); | |
554 ASSERT_TRUE(job.IsValid()); | |
555 | |
556 registry.Resubmit(id); | |
557 job.MarkPause(); | |
558 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
559 } | |
560 | |
561 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
562 | |
563 registry.Resubmit(id); | |
564 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
565 | |
566 registry.Resume(id); | |
567 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
568 | |
569 { | |
570 JobsRegistry::RunningJob job(registry, 0); | |
571 ASSERT_TRUE(job.IsValid()); | |
572 | |
573 job.MarkSuccess(); | |
574 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
575 } | |
576 | |
577 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
578 } | |
579 | |
580 | |
581 TEST(JobsRegistry, PauseRetry) | |
582 { | |
583 JobsRegistry registry; | |
584 | |
585 std::string id; | |
586 registry.Submit(id, new DummyJob(), 10); | |
587 | |
588 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
589 | |
590 { | |
591 JobsRegistry::RunningJob job(registry, 0); | |
592 ASSERT_TRUE(job.IsValid()); | |
593 | |
594 job.MarkRetry(0); | |
595 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
596 } | |
597 | |
598 ASSERT_TRUE(CheckState(registry, id, JobState_Retry)); | |
599 | |
600 registry.Pause(id); | |
601 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
602 | |
603 registry.Resume(id); | |
604 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
605 | |
606 { | |
607 JobsRegistry::RunningJob job(registry, 0); | |
608 ASSERT_TRUE(job.IsValid()); | |
609 | |
610 job.MarkSuccess(); | |
611 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
612 } | |
613 | |
614 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
615 } | |
616 | |
617 | |
618 TEST(JobsRegistry, Cancel) | |
619 { | |
620 JobsRegistry registry; | |
621 | |
622 std::string id; | |
623 registry.Submit(id, new DummyJob(), 10); | |
624 | |
625 ASSERT_FALSE(registry.Cancel("nope")); | |
626 | |
627 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
628 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
629 | |
630 ASSERT_TRUE(registry.Cancel(id)); | |
631 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
632 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
633 | |
634 ASSERT_TRUE(registry.Cancel(id)); | |
635 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
636 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
637 | |
638 ASSERT_TRUE(registry.Resubmit(id)); | |
639 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
640 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
641 | |
642 { | |
643 JobsRegistry::RunningJob job(registry, 0); | |
644 ASSERT_TRUE(job.IsValid()); | |
645 | |
646 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
647 | |
648 job.MarkSuccess(); | |
649 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
650 } | |
651 | |
652 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
653 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
654 | |
655 ASSERT_TRUE(registry.Cancel(id)); | |
656 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
657 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
658 | |
659 registry.Submit(id, new DummyJob(), 10); | |
660 | |
661 { | |
662 JobsRegistry::RunningJob job(registry, 0); | |
663 ASSERT_TRUE(job.IsValid()); | |
664 ASSERT_EQ(id, job.GetId()); | |
665 | |
666 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
667 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
668 | |
669 job.MarkCanceled(); | |
670 } | |
671 | |
672 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
673 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
674 | |
675 ASSERT_TRUE(registry.Resubmit(id)); | |
676 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
677 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
678 | |
679 ASSERT_TRUE(registry.Pause(id)); | |
680 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
681 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
682 | |
683 ASSERT_TRUE(registry.Cancel(id)); | |
684 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
685 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
686 | |
687 ASSERT_TRUE(registry.Resubmit(id)); | |
688 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
689 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
690 | |
691 { | |
692 JobsRegistry::RunningJob job(registry, 0); | |
693 ASSERT_TRUE(job.IsValid()); | |
694 ASSERT_EQ(id, job.GetId()); | |
695 | |
696 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
697 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
698 | |
699 job.MarkRetry(500); | |
700 } | |
701 | |
702 ASSERT_TRUE(CheckState(registry, id, JobState_Retry)); | |
703 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
704 | |
705 ASSERT_TRUE(registry.Cancel(id)); | |
706 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
707 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
708 } | |
709 | |
710 | |
711 | |
712 TEST(JobsEngine, SubmitAndWait) | |
713 { | |
714 JobsEngine engine; | |
715 engine.SetThreadSleep(10); | |
716 engine.SetWorkersCount(3); | |
717 engine.Start(); | |
718 | |
719 Json::Value content = Json::nullValue; | |
720 ASSERT_TRUE(engine.GetRegistry().SubmitAndWait(content, new DummyJob(), rand() % 10)); | |
721 ASSERT_EQ(Json::objectValue, content.type()); | |
722 ASSERT_EQ("world", content["hello"].asString()); | |
723 | |
724 content = Json::nullValue; | |
725 ASSERT_FALSE(engine.GetRegistry().SubmitAndWait(content, new DummyJob(true), rand() % 10)); | |
726 ASSERT_EQ(Json::nullValue, content.type()); | |
727 | |
728 engine.Stop(); | |
729 } | |
730 | |
731 | |
732 TEST(JobsEngine, DISABLED_SequenceOfOperationsJob) | |
733 { | |
734 JobsEngine engine; | |
735 engine.SetThreadSleep(10); | |
736 engine.SetWorkersCount(3); | |
737 engine.Start(); | |
738 | |
739 std::string id; | |
740 SequenceOfOperationsJob* job = NULL; | |
741 | |
742 { | |
743 std::auto_ptr<SequenceOfOperationsJob> a(new SequenceOfOperationsJob); | |
744 job = a.get(); | |
745 engine.GetRegistry().Submit(id, a.release(), 0); | |
746 } | |
747 | |
748 boost::this_thread::sleep(boost::posix_time::milliseconds(500)); | |
749 | |
750 { | |
751 SequenceOfOperationsJob::Lock lock(*job); | |
752 size_t i = lock.AddOperation(new LogJobOperation); | |
753 size_t j = lock.AddOperation(new LogJobOperation); | |
754 size_t k = lock.AddOperation(new LogJobOperation); | |
755 | |
756 StringOperationValue a("Hello"); | |
757 StringOperationValue b("World"); | |
758 lock.AddInput(i, a); | |
759 lock.AddInput(i, b); | |
760 | |
761 lock.Connect(i, j); | |
762 lock.Connect(j, k); | |
763 } | |
764 | |
765 boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); | |
766 | |
767 engine.Stop(); | |
768 | |
769 } | |
770 | |
771 | |
772 TEST(JobsEngine, DISABLED_Lua) | |
773 { | |
774 JobsEngine engine; | |
775 engine.SetThreadSleep(10); | |
776 engine.SetWorkersCount(2); | |
777 engine.Start(); | |
778 | |
779 LuaJobManager lua; | |
780 lua.SetMaxOperationsPerJob(5); | |
781 lua.SetTrailingOperationTimeout(200); | |
782 | |
783 for (size_t i = 0; i < 30; i++) | |
784 { | |
785 boost::this_thread::sleep(boost::posix_time::milliseconds(150)); | |
786 | |
787 LuaJobManager::Lock lock(lua, engine); | |
788 size_t a = lock.AddLogOperation(); | |
789 size_t b = lock.AddLogOperation(); | |
790 size_t c = lock.AddSystemCallOperation("echo"); | |
791 lock.AddStringInput(a, boost::lexical_cast<std::string>(i)); | |
792 lock.AddNullInput(a); | |
793 lock.Connect(a, b); | |
794 lock.Connect(a, c); | |
795 } | |
796 | |
797 boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); | |
798 | |
799 engine.Stop(); | |
800 } | |
801 | |
802 | |
803 static bool CheckSameJson(const Json::Value& a, | |
804 const Json::Value& b) | |
805 { | |
806 std::string s = a.toStyledString(); | |
807 std::string t = b.toStyledString(); | |
808 | |
809 if (s == t) | |
810 { | |
188 return true; | 811 return true; |
189 } | 812 } |
190 }; | 813 else |
191 | 814 { |
192 | 815 LOG(ERROR) << "Expected serialization: " << s; |
193 static void Tata(ServerScheduler* s, ServerJob* j, bool* done) | 816 LOG(ERROR) << "Actual serialization: " << t; |
194 { | 817 return false; |
195 typedef IServerCommand::ListOfStrings ListOfStrings; | 818 } |
196 | 819 } |
197 while (!(*done)) | 820 |
198 { | 821 |
199 ListOfStrings l; | 822 static bool CheckIdempotentSerialization(IJobUnserializer& unserializer, |
200 s->GetListOfJobs(l); | 823 IJob& job) |
201 for (ListOfStrings::iterator it = l.begin(); it != l.end(); ++it) | 824 { |
202 { | 825 Json::Value a = 42; |
203 printf(">> %s: %0.1f\n", it->c_str(), 100.0f * s->GetProgress(*it)); | 826 |
204 } | 827 if (!job.Serialize(a)) |
205 Toolbox::USleep(3000); | 828 { |
206 } | 829 return false; |
207 } | 830 } |
208 | 831 else |
209 | 832 { |
210 TEST(MultiThreading, ServerScheduler) | 833 std::auto_ptr<IJob> unserialized(unserializer.UnserializeJob(a)); |
211 { | 834 |
212 ServerScheduler scheduler(10); | 835 Json::Value b = 43; |
213 | 836 if (unserialized->Serialize(b)) |
214 ServerJob job; | 837 { |
215 ServerCommandInstance& f2 = job.AddCommand(new Tutu(2)); | 838 return (CheckSameJson(a, b)); |
216 ServerCommandInstance& f3 = job.AddCommand(new Tutu(3)); | 839 } |
217 ServerCommandInstance& f4 = job.AddCommand(new Tutu(4)); | 840 else |
218 ServerCommandInstance& f5 = job.AddCommand(new Tutu(5)); | 841 { |
219 f2.AddInput(boost::lexical_cast<std::string>(42)); | 842 return false; |
220 //f3.AddInput(boost::lexical_cast<std::string>(42)); | 843 } |
221 //f4.AddInput(boost::lexical_cast<std::string>(42)); | 844 } |
222 f2.ConnectOutput(f3); | 845 } |
223 f3.ConnectOutput(f4); | 846 |
224 f4.ConnectOutput(f5); | 847 |
225 | 848 static bool CheckIdempotentSetOfInstances(IJobUnserializer& unserializer, |
226 f3.SetConnectedToSink(true); | 849 SetOfInstancesJob& job) |
227 f5.SetConnectedToSink(true); | 850 { |
228 | 851 Json::Value a = 42; |
229 job.SetDescription("tutu"); | 852 |
230 | 853 if (!job.Serialize(a)) |
231 bool done = false; | 854 { |
232 boost::thread t(Tata, &scheduler, &job, &done); | 855 return false; |
233 | 856 } |
234 | 857 else |
235 //scheduler.Submit(job); | 858 { |
236 | 859 std::auto_ptr<SetOfInstancesJob> unserialized |
237 IServerCommand::ListOfStrings l; | 860 (dynamic_cast<SetOfInstancesJob*>(unserializer.UnserializeJob(a))); |
238 scheduler.SubmitAndWait(l, job); | 861 |
239 | 862 Json::Value b = 43; |
240 ASSERT_EQ(2u, l.size()); | 863 if (unserialized->Serialize(b)) |
241 ASSERT_EQ(42 * 2 * 3, boost::lexical_cast<int>(l.front())); | 864 { |
242 ASSERT_EQ(42 * 2 * 3 * 4 * 5, boost::lexical_cast<int>(l.back())); | 865 return (CheckSameJson(a, b) && |
243 | 866 job.HasTrailingStep() == unserialized->HasTrailingStep() && |
244 for (IServerCommand::ListOfStrings::iterator i = l.begin(); i != l.end(); i++) | 867 job.GetPosition() == unserialized->GetPosition() && |
245 { | 868 job.GetInstancesCount() == unserialized->GetInstancesCount() && |
246 printf("** %s\n", i->c_str()); | 869 job.GetCommandsCount() == unserialized->GetCommandsCount()); |
247 } | 870 } |
248 | 871 else |
249 //Toolbox::ServerBarrier(); | 872 { |
250 //Toolbox::USleep(3000000); | 873 return false; |
251 | 874 } |
252 scheduler.Stop(); | 875 } |
253 | 876 } |
254 done = true; | 877 |
255 if (t.joinable()) | 878 |
256 { | 879 static bool CheckIdempotentSerialization(IJobUnserializer& unserializer, |
257 t.join(); | 880 IJobOperation& operation) |
258 } | 881 { |
259 } | 882 Json::Value a = 42; |
883 operation.Serialize(a); | |
884 | |
885 std::auto_ptr<IJobOperation> unserialized(unserializer.UnserializeOperation(a)); | |
886 | |
887 Json::Value b = 43; | |
888 unserialized->Serialize(b); | |
889 | |
890 return CheckSameJson(a, b); | |
891 } | |
892 | |
893 | |
894 static bool CheckIdempotentSerialization(IJobUnserializer& unserializer, | |
895 JobOperationValue& value) | |
896 { | |
897 Json::Value a = 42; | |
898 value.Serialize(a); | |
899 | |
900 std::auto_ptr<JobOperationValue> unserialized(unserializer.UnserializeValue(a)); | |
901 | |
902 Json::Value b = 43; | |
903 unserialized->Serialize(b); | |
904 | |
905 return CheckSameJson(a, b); | |
906 } | |
907 | |
908 | |
909 TEST(JobsSerialization, BadFileFormat) | |
910 { | |
911 GenericJobUnserializer unserializer; | |
912 | |
913 Json::Value s; | |
914 | |
915 s = Json::objectValue; | |
916 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
917 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
918 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
919 | |
920 s = Json::arrayValue; | |
921 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
922 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
923 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
924 | |
925 s = "hello"; | |
926 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
927 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
928 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
929 | |
930 s = 42; | |
931 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
932 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
933 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
934 } | |
935 | |
936 | |
937 TEST(JobsSerialization, JobOperationValues) | |
938 { | |
939 Json::Value s; | |
940 | |
941 { | |
942 JobOperationValues values; | |
943 values.Append(new NullOperationValue); | |
944 values.Append(new StringOperationValue("hello")); | |
945 values.Append(new StringOperationValue("world")); | |
946 | |
947 s = 42; | |
948 values.Serialize(s); | |
949 } | |
950 | |
951 { | |
952 GenericJobUnserializer unserializer; | |
953 std::auto_ptr<JobOperationValues> values(JobOperationValues::Unserialize(unserializer, s)); | |
954 ASSERT_EQ(3u, values->GetSize()); | |
955 ASSERT_EQ(JobOperationValue::Type_Null, values->GetValue(0).GetType()); | |
956 ASSERT_EQ(JobOperationValue::Type_String, values->GetValue(1).GetType()); | |
957 ASSERT_EQ(JobOperationValue::Type_String, values->GetValue(2).GetType()); | |
958 | |
959 ASSERT_EQ("hello", dynamic_cast<const StringOperationValue&>(values->GetValue(1)).GetContent()); | |
960 ASSERT_EQ("world", dynamic_cast<const StringOperationValue&>(values->GetValue(2)).GetContent()); | |
961 } | |
962 } | |
963 | |
964 | |
965 TEST(JobsSerialization, GenericValues) | |
966 { | |
967 GenericJobUnserializer unserializer; | |
968 Json::Value s; | |
969 | |
970 { | |
971 NullOperationValue null; | |
972 | |
973 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, null)); | |
974 null.Serialize(s); | |
975 } | |
976 | |
977 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
978 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
979 | |
980 std::auto_ptr<JobOperationValue> value; | |
981 value.reset(unserializer.UnserializeValue(s)); | |
982 | |
983 ASSERT_EQ(JobOperationValue::Type_Null, value->GetType()); | |
984 | |
985 { | |
986 StringOperationValue str("Hello"); | |
987 | |
988 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, str)); | |
989 str.Serialize(s); | |
990 } | |
991 | |
992 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
993 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
994 value.reset(unserializer.UnserializeValue(s)); | |
995 | |
996 ASSERT_EQ(JobOperationValue::Type_String, value->GetType()); | |
997 ASSERT_EQ("Hello", dynamic_cast<StringOperationValue&>(*value).GetContent()); | |
998 } | |
999 | |
1000 | |
1001 TEST(JobsSerialization, GenericOperations) | |
1002 { | |
1003 DummyUnserializer unserializer; | |
1004 Json::Value s; | |
1005 | |
1006 { | |
1007 LogJobOperation operation; | |
1008 | |
1009 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, operation)); | |
1010 operation.Serialize(s); | |
1011 } | |
1012 | |
1013 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
1014 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
1015 | |
1016 { | |
1017 std::auto_ptr<IJobOperation> operation; | |
1018 operation.reset(unserializer.UnserializeOperation(s)); | |
1019 | |
1020 // Make sure that we have indeed unserialized a log operation | |
1021 Json::Value dummy; | |
1022 ASSERT_THROW(dynamic_cast<DeleteResourceOperation&>(*operation).Serialize(dummy), std::bad_cast); | |
1023 dynamic_cast<LogJobOperation&>(*operation).Serialize(dummy); | |
1024 } | |
1025 } | |
1026 | |
1027 | |
1028 TEST(JobsSerialization, GenericJobs) | |
1029 { | |
1030 Json::Value s; | |
1031 | |
1032 // This tests SetOfInstancesJob | |
1033 | |
1034 { | |
1035 DummyInstancesJob job; | |
1036 job.SetDescription("description"); | |
1037 job.AddInstance("hello"); | |
1038 job.AddInstance("nope"); | |
1039 job.AddInstance("world"); | |
1040 job.SetPermissive(true); | |
1041 ASSERT_THROW(job.Step(), OrthancException); // Not started yet | |
1042 ASSERT_FALSE(job.HasTrailingStep()); | |
1043 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1044 job.Start(); | |
1045 ASSERT_EQ(JobStepCode_Continue, job.Step().GetCode()); | |
1046 ASSERT_EQ(JobStepCode_Continue, job.Step().GetCode()); | |
1047 | |
1048 { | |
1049 DummyUnserializer unserializer; | |
1050 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1051 } | |
1052 | |
1053 ASSERT_TRUE(job.Serialize(s)); | |
1054 } | |
1055 | |
1056 { | |
1057 DummyUnserializer unserializer; | |
1058 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
1059 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
1060 | |
1061 std::auto_ptr<IJob> job; | |
1062 job.reset(unserializer.UnserializeJob(s)); | |
1063 | |
1064 const DummyInstancesJob& tmp = dynamic_cast<const DummyInstancesJob&>(*job); | |
1065 ASSERT_FALSE(tmp.IsStarted()); | |
1066 ASSERT_TRUE(tmp.IsPermissive()); | |
1067 ASSERT_EQ("description", tmp.GetDescription()); | |
1068 ASSERT_EQ(3u, tmp.GetInstancesCount()); | |
1069 ASSERT_EQ(2u, tmp.GetPosition()); | |
1070 ASSERT_EQ(1u, tmp.GetFailedInstances().size()); | |
1071 ASSERT_EQ("hello", tmp.GetInstance(0)); | |
1072 ASSERT_EQ("nope", tmp.GetInstance(1)); | |
1073 ASSERT_EQ("world", tmp.GetInstance(2)); | |
1074 ASSERT_TRUE(tmp.IsFailedInstance("nope")); | |
1075 } | |
1076 | |
1077 // SequenceOfOperationsJob | |
1078 | |
1079 { | |
1080 SequenceOfOperationsJob job; | |
1081 job.SetDescription("hello"); | |
1082 | |
1083 { | |
1084 SequenceOfOperationsJob::Lock lock(job); | |
1085 size_t a = lock.AddOperation(new LogJobOperation); | |
1086 size_t b = lock.AddOperation(new LogJobOperation); | |
1087 lock.Connect(a, b); | |
1088 | |
1089 StringOperationValue s1("hello"); | |
1090 StringOperationValue s2("world"); | |
1091 lock.AddInput(a, s1); | |
1092 lock.AddInput(a, s2); | |
1093 lock.SetDicomAssociationTimeout(200); | |
1094 lock.SetTrailingOperationTimeout(300); | |
1095 } | |
1096 | |
1097 ASSERT_EQ(JobStepCode_Continue, job.Step().GetCode()); | |
1098 | |
1099 { | |
1100 GenericJobUnserializer unserializer; | |
1101 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, job)); | |
1102 } | |
1103 | |
1104 ASSERT_TRUE(job.Serialize(s)); | |
1105 } | |
1106 | |
1107 { | |
1108 GenericJobUnserializer unserializer; | |
1109 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
1110 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
1111 | |
1112 std::auto_ptr<IJob> job; | |
1113 job.reset(unserializer.UnserializeJob(s)); | |
1114 | |
1115 std::string tmp; | |
1116 dynamic_cast<SequenceOfOperationsJob&>(*job).GetDescription(tmp); | |
1117 ASSERT_EQ("hello", tmp); | |
1118 } | |
1119 } | |
1120 | |
1121 | |
1122 static bool IsSameTagValue(ParsedDicomFile& dicom1, | |
1123 ParsedDicomFile& dicom2, | |
1124 DicomTag tag) | |
1125 { | |
1126 std::string a, b; | |
1127 return (dicom1.GetTagValue(a, tag) && | |
1128 dicom2.GetTagValue(b, tag) && | |
1129 (a == b)); | |
1130 } | |
1131 | |
1132 | |
1133 | |
1134 TEST(JobsSerialization, DicomModification) | |
1135 { | |
1136 Json::Value s; | |
1137 | |
1138 ParsedDicomFile source(true); | |
1139 source.Insert(DICOM_TAG_STUDY_DESCRIPTION, "Test 1", false); | |
1140 source.Insert(DICOM_TAG_SERIES_DESCRIPTION, "Test 2", false); | |
1141 source.Insert(DICOM_TAG_PATIENT_NAME, "Test 3", false); | |
1142 | |
1143 std::auto_ptr<ParsedDicomFile> modified(source.Clone(true)); | |
1144 | |
1145 { | |
1146 DicomModification modification; | |
1147 modification.SetLevel(ResourceType_Series); | |
1148 modification.Clear(DICOM_TAG_STUDY_DESCRIPTION); | |
1149 modification.Remove(DICOM_TAG_SERIES_DESCRIPTION); | |
1150 modification.Replace(DICOM_TAG_PATIENT_NAME, "Test 4", true); | |
1151 | |
1152 modification.Apply(*modified); | |
1153 | |
1154 s = 42; | |
1155 modification.Serialize(s); | |
1156 } | |
1157 | |
1158 { | |
1159 DicomModification modification(s); | |
1160 ASSERT_EQ(ResourceType_Series, modification.GetLevel()); | |
1161 | |
1162 std::auto_ptr<ParsedDicomFile> second(source.Clone(true)); | |
1163 modification.Apply(*second); | |
1164 | |
1165 std::string s; | |
1166 ASSERT_TRUE(second->GetTagValue(s, DICOM_TAG_STUDY_DESCRIPTION)); | |
1167 ASSERT_TRUE(s.empty()); | |
1168 ASSERT_FALSE(second->GetTagValue(s, DICOM_TAG_SERIES_DESCRIPTION)); | |
1169 ASSERT_TRUE(second->GetTagValue(s, DICOM_TAG_PATIENT_NAME)); | |
1170 ASSERT_EQ("Test 4", s); | |
1171 | |
1172 ASSERT_TRUE(IsSameTagValue(source, *modified, DICOM_TAG_STUDY_INSTANCE_UID)); | |
1173 ASSERT_TRUE(IsSameTagValue(source, *second, DICOM_TAG_STUDY_INSTANCE_UID)); | |
1174 | |
1175 ASSERT_FALSE(IsSameTagValue(source, *second, DICOM_TAG_SERIES_INSTANCE_UID)); | |
1176 ASSERT_TRUE(IsSameTagValue(*modified, *second, DICOM_TAG_SERIES_INSTANCE_UID)); | |
1177 } | |
1178 } | |
1179 | |
1180 | |
1181 TEST(JobsSerialization, DicomInstanceOrigin) | |
1182 { | |
1183 Json::Value s; | |
1184 std::string t; | |
1185 | |
1186 { | |
1187 DicomInstanceOrigin origin; | |
1188 | |
1189 s = 42; | |
1190 origin.Serialize(s); | |
1191 } | |
1192 | |
1193 { | |
1194 DicomInstanceOrigin origin(s); | |
1195 ASSERT_EQ(RequestOrigin_Unknown, origin.GetRequestOrigin()); | |
1196 ASSERT_EQ("", std::string(origin.GetRemoteAetC())); | |
1197 ASSERT_FALSE(origin.LookupRemoteIp(t)); | |
1198 ASSERT_FALSE(origin.LookupRemoteAet(t)); | |
1199 ASSERT_FALSE(origin.LookupCalledAet(t)); | |
1200 ASSERT_FALSE(origin.LookupHttpUsername(t)); | |
1201 } | |
1202 | |
1203 { | |
1204 DicomInstanceOrigin origin(DicomInstanceOrigin::FromDicomProtocol("host", "aet", "called")); | |
1205 | |
1206 s = 42; | |
1207 origin.Serialize(s); | |
1208 } | |
1209 | |
1210 { | |
1211 DicomInstanceOrigin origin(s); | |
1212 ASSERT_EQ(RequestOrigin_DicomProtocol, origin.GetRequestOrigin()); | |
1213 ASSERT_EQ("aet", std::string(origin.GetRemoteAetC())); | |
1214 ASSERT_TRUE(origin.LookupRemoteIp(t)); ASSERT_EQ("host", t); | |
1215 ASSERT_TRUE(origin.LookupRemoteAet(t)); ASSERT_EQ("aet", t); | |
1216 ASSERT_TRUE(origin.LookupCalledAet(t)); ASSERT_EQ("called", t); | |
1217 ASSERT_FALSE(origin.LookupHttpUsername(t)); | |
1218 } | |
1219 | |
1220 { | |
1221 DicomInstanceOrigin origin(DicomInstanceOrigin::FromHttp("host", "username")); | |
1222 | |
1223 s = 42; | |
1224 origin.Serialize(s); | |
1225 } | |
1226 | |
1227 { | |
1228 DicomInstanceOrigin origin(s); | |
1229 ASSERT_EQ(RequestOrigin_RestApi, origin.GetRequestOrigin()); | |
1230 ASSERT_EQ("", std::string(origin.GetRemoteAetC())); | |
1231 ASSERT_TRUE(origin.LookupRemoteIp(t)); ASSERT_EQ("host", t); | |
1232 ASSERT_FALSE(origin.LookupRemoteAet(t)); | |
1233 ASSERT_FALSE(origin.LookupCalledAet(t)); | |
1234 ASSERT_TRUE(origin.LookupHttpUsername(t)); ASSERT_EQ("username", t); | |
1235 } | |
1236 | |
1237 { | |
1238 DicomInstanceOrigin origin(DicomInstanceOrigin::FromLua()); | |
1239 | |
1240 s = 42; | |
1241 origin.Serialize(s); | |
1242 } | |
1243 | |
1244 { | |
1245 DicomInstanceOrigin origin(s); | |
1246 ASSERT_EQ(RequestOrigin_Lua, origin.GetRequestOrigin()); | |
1247 ASSERT_FALSE(origin.LookupRemoteIp(t)); | |
1248 ASSERT_FALSE(origin.LookupRemoteAet(t)); | |
1249 ASSERT_FALSE(origin.LookupCalledAet(t)); | |
1250 ASSERT_FALSE(origin.LookupHttpUsername(t)); | |
1251 } | |
1252 | |
1253 { | |
1254 DicomInstanceOrigin origin(DicomInstanceOrigin::FromPlugins()); | |
1255 | |
1256 s = 42; | |
1257 origin.Serialize(s); | |
1258 } | |
1259 | |
1260 { | |
1261 DicomInstanceOrigin origin(s); | |
1262 ASSERT_EQ(RequestOrigin_Plugins, origin.GetRequestOrigin()); | |
1263 ASSERT_FALSE(origin.LookupRemoteIp(t)); | |
1264 ASSERT_FALSE(origin.LookupRemoteAet(t)); | |
1265 ASSERT_FALSE(origin.LookupCalledAet(t)); | |
1266 ASSERT_FALSE(origin.LookupHttpUsername(t)); | |
1267 } | |
1268 } | |
1269 | |
1270 | |
1271 namespace | |
1272 { | |
1273 class OrthancJobsSerialization : public testing::Test | |
1274 { | |
1275 private: | |
1276 MemoryStorageArea storage_; | |
1277 DatabaseWrapper db_; // The SQLite DB is in memory | |
1278 std::auto_ptr<ServerContext> context_; | |
1279 TimeoutDicomConnectionManager manager_; | |
1280 | |
1281 public: | |
1282 OrthancJobsSerialization() | |
1283 { | |
1284 db_.Open(); | |
1285 context_.reset(new ServerContext(db_, storage_, true /* running unit tests */)); | |
1286 context_->SetupJobsEngine(true, false); | |
1287 } | |
1288 | |
1289 virtual ~OrthancJobsSerialization() | |
1290 { | |
1291 context_->Stop(); | |
1292 context_.reset(NULL); | |
1293 db_.Close(); | |
1294 } | |
1295 | |
1296 ServerContext& GetContext() | |
1297 { | |
1298 return *context_; | |
1299 } | |
1300 | |
1301 bool CreateInstance(std::string& id) | |
1302 { | |
1303 // Create a sample DICOM file | |
1304 ParsedDicomFile dicom(true); | |
1305 dicom.Replace(DICOM_TAG_PATIENT_NAME, std::string("JODOGNE"), | |
1306 false, DicomReplaceMode_InsertIfAbsent); | |
1307 | |
1308 DicomInstanceToStore toStore; | |
1309 toStore.SetParsedDicomFile(dicom); | |
1310 | |
1311 return (context_->Store(id, toStore) == StoreStatus_Success); | |
1312 } | |
1313 }; | |
1314 } | |
1315 | |
1316 | |
1317 TEST_F(OrthancJobsSerialization, Values) | |
1318 { | |
1319 std::string id; | |
1320 ASSERT_TRUE(CreateInstance(id)); | |
1321 | |
1322 Json::Value s; | |
1323 OrthancJobUnserializer unserializer(GetContext()); | |
1324 | |
1325 { | |
1326 DicomInstanceOperationValue instance(GetContext(), id); | |
1327 | |
1328 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, instance)); | |
1329 instance.Serialize(s); | |
1330 } | |
1331 | |
1332 std::auto_ptr<JobOperationValue> value; | |
1333 value.reset(unserializer.UnserializeValue(s)); | |
1334 ASSERT_EQ(JobOperationValue::Type_DicomInstance, value->GetType()); | |
1335 ASSERT_EQ(id, dynamic_cast<DicomInstanceOperationValue&>(*value).GetId()); | |
1336 | |
1337 { | |
1338 std::string content; | |
1339 dynamic_cast<DicomInstanceOperationValue&>(*value).ReadDicom(content); | |
1340 | |
1341 ParsedDicomFile dicom(content); | |
1342 ASSERT_TRUE(dicom.GetTagValue(content, DICOM_TAG_PATIENT_NAME)); | |
1343 ASSERT_EQ("JODOGNE", content); | |
1344 } | |
1345 } | |
1346 | |
1347 | |
1348 TEST_F(OrthancJobsSerialization, Operations) | |
1349 { | |
1350 std::string id; | |
1351 ASSERT_TRUE(CreateInstance(id)); | |
1352 | |
1353 Json::Value s; | |
1354 OrthancJobUnserializer unserializer(GetContext()); | |
1355 | |
1356 // DeleteResourceOperation | |
1357 | |
1358 { | |
1359 DeleteResourceOperation operation(GetContext()); | |
1360 | |
1361 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, operation)); | |
1362 operation.Serialize(s); | |
1363 } | |
1364 | |
1365 std::auto_ptr<IJobOperation> operation; | |
1366 | |
1367 { | |
1368 operation.reset(unserializer.UnserializeOperation(s)); | |
1369 | |
1370 Json::Value dummy; | |
1371 ASSERT_THROW(dynamic_cast<LogJobOperation&>(*operation).Serialize(dummy), std::bad_cast); | |
1372 dynamic_cast<DeleteResourceOperation&>(*operation).Serialize(dummy); | |
1373 } | |
1374 | |
1375 // StorePeerOperation | |
1376 | |
1377 { | |
1378 WebServiceParameters peer; | |
1379 peer.SetUrl("http://localhost/"); | |
1380 peer.SetCredentials("username", "password"); | |
1381 peer.SetPkcs11Enabled(true); | |
1382 | |
1383 StorePeerOperation operation(peer); | |
1384 | |
1385 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, operation)); | |
1386 operation.Serialize(s); | |
1387 } | |
1388 | |
1389 { | |
1390 operation.reset(unserializer.UnserializeOperation(s)); | |
1391 | |
1392 const StorePeerOperation& tmp = dynamic_cast<StorePeerOperation&>(*operation); | |
1393 ASSERT_EQ("http://localhost/", tmp.GetPeer().GetUrl()); | |
1394 ASSERT_EQ("username", tmp.GetPeer().GetUsername()); | |
1395 ASSERT_EQ("password", tmp.GetPeer().GetPassword()); | |
1396 ASSERT_TRUE(tmp.GetPeer().IsPkcs11Enabled()); | |
1397 } | |
1398 | |
1399 // StoreScuOperation | |
1400 | |
1401 { | |
1402 RemoteModalityParameters modality; | |
1403 modality.SetApplicationEntityTitle("REMOTE"); | |
1404 modality.SetHost("192.168.1.1"); | |
1405 modality.SetPortNumber(1000); | |
1406 modality.SetManufacturer(ModalityManufacturer_StoreScp); | |
1407 | |
1408 StoreScuOperation operation("TEST", modality); | |
1409 | |
1410 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, operation)); | |
1411 operation.Serialize(s); | |
1412 } | |
1413 | |
1414 { | |
1415 operation.reset(unserializer.UnserializeOperation(s)); | |
1416 | |
1417 const StoreScuOperation& tmp = dynamic_cast<StoreScuOperation&>(*operation); | |
1418 ASSERT_EQ("REMOTE", tmp.GetRemoteModality().GetApplicationEntityTitle()); | |
1419 ASSERT_EQ("192.168.1.1", tmp.GetRemoteModality().GetHost()); | |
1420 ASSERT_EQ(1000, tmp.GetRemoteModality().GetPortNumber()); | |
1421 ASSERT_EQ(ModalityManufacturer_StoreScp, tmp.GetRemoteModality().GetManufacturer()); | |
1422 ASSERT_EQ("TEST", tmp.GetLocalAet()); | |
1423 } | |
1424 | |
1425 // SystemCallOperation | |
1426 | |
1427 { | |
1428 SystemCallOperation operation(std::string("echo")); | |
1429 operation.AddPreArgument("a"); | |
1430 operation.AddPreArgument("b"); | |
1431 operation.AddPostArgument("c"); | |
1432 | |
1433 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, operation)); | |
1434 operation.Serialize(s); | |
1435 } | |
1436 | |
1437 { | |
1438 operation.reset(unserializer.UnserializeOperation(s)); | |
1439 | |
1440 const SystemCallOperation& tmp = dynamic_cast<SystemCallOperation&>(*operation); | |
1441 ASSERT_EQ("echo", tmp.GetCommand()); | |
1442 ASSERT_EQ(2u, tmp.GetPreArgumentsCount()); | |
1443 ASSERT_EQ(1u, tmp.GetPostArgumentsCount()); | |
1444 ASSERT_EQ("a", tmp.GetPreArgument(0)); | |
1445 ASSERT_EQ("b", tmp.GetPreArgument(1)); | |
1446 ASSERT_EQ("c", tmp.GetPostArgument(0)); | |
1447 } | |
1448 | |
1449 // ModifyInstanceOperation | |
1450 | |
1451 { | |
1452 std::auto_ptr<DicomModification> modification(new DicomModification); | |
1453 modification->SetupAnonymization(DicomVersion_2008); | |
1454 | |
1455 ModifyInstanceOperation operation(GetContext(), RequestOrigin_Lua, modification.release()); | |
1456 | |
1457 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, operation)); | |
1458 operation.Serialize(s); | |
1459 } | |
1460 | |
1461 { | |
1462 operation.reset(unserializer.UnserializeOperation(s)); | |
1463 | |
1464 const ModifyInstanceOperation& tmp = dynamic_cast<ModifyInstanceOperation&>(*operation); | |
1465 ASSERT_EQ(RequestOrigin_Lua, tmp.GetRequestOrigin()); | |
1466 ASSERT_TRUE(tmp.GetModification().IsRemoved(DICOM_TAG_STUDY_DESCRIPTION)); | |
1467 } | |
1468 } | |
1469 | |
1470 | |
1471 TEST_F(OrthancJobsSerialization, Jobs) | |
1472 { | |
1473 Json::Value s; | |
1474 | |
1475 // ArchiveJob | |
1476 | |
1477 { | |
1478 boost::shared_ptr<TemporaryFile> tmp(new TemporaryFile); | |
1479 ArchiveJob job(tmp, GetContext(), false, false); | |
1480 ASSERT_FALSE(job.Serialize(s)); // Cannot serialize this | |
1481 } | |
1482 | |
1483 // DicomModalityStoreJob | |
1484 | |
1485 OrthancJobUnserializer unserializer(GetContext()); | |
1486 | |
1487 { | |
1488 RemoteModalityParameters modality; | |
1489 modality.SetApplicationEntityTitle("REMOTE"); | |
1490 modality.SetHost("192.168.1.1"); | |
1491 modality.SetPortNumber(1000); | |
1492 modality.SetManufacturer(ModalityManufacturer_StoreScp); | |
1493 | |
1494 DicomModalityStoreJob job(GetContext()); | |
1495 job.SetLocalAet("LOCAL"); | |
1496 job.SetRemoteModality(modality); | |
1497 job.SetMoveOriginator("MOVESCU", 42); | |
1498 | |
1499 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1500 ASSERT_TRUE(job.Serialize(s)); | |
1501 } | |
1502 | |
1503 { | |
1504 std::auto_ptr<IJob> job; | |
1505 job.reset(unserializer.UnserializeJob(s)); | |
1506 | |
1507 DicomModalityStoreJob& tmp = dynamic_cast<DicomModalityStoreJob&>(*job); | |
1508 ASSERT_EQ("LOCAL", tmp.GetLocalAet()); | |
1509 ASSERT_EQ("REMOTE", tmp.GetRemoteModality().GetApplicationEntityTitle()); | |
1510 ASSERT_EQ("192.168.1.1", tmp.GetRemoteModality().GetHost()); | |
1511 ASSERT_EQ(1000, tmp.GetRemoteModality().GetPortNumber()); | |
1512 ASSERT_EQ(ModalityManufacturer_StoreScp, tmp.GetRemoteModality().GetManufacturer()); | |
1513 ASSERT_TRUE(tmp.HasMoveOriginator()); | |
1514 ASSERT_EQ("MOVESCU", tmp.GetMoveOriginatorAet()); | |
1515 ASSERT_EQ(42, tmp.GetMoveOriginatorId()); | |
1516 } | |
1517 | |
1518 // OrthancPeerStoreJob | |
1519 | |
1520 { | |
1521 WebServiceParameters peer; | |
1522 peer.SetUrl("http://localhost/"); | |
1523 peer.SetCredentials("username", "password"); | |
1524 peer.SetPkcs11Enabled(true); | |
1525 | |
1526 OrthancPeerStoreJob job(GetContext()); | |
1527 job.SetPeer(peer); | |
1528 | |
1529 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1530 ASSERT_TRUE(job.Serialize(s)); | |
1531 } | |
1532 | |
1533 { | |
1534 std::auto_ptr<IJob> job; | |
1535 job.reset(unserializer.UnserializeJob(s)); | |
1536 | |
1537 OrthancPeerStoreJob& tmp = dynamic_cast<OrthancPeerStoreJob&>(*job); | |
1538 ASSERT_EQ("http://localhost/", tmp.GetPeer().GetUrl()); | |
1539 ASSERT_EQ("username", tmp.GetPeer().GetUsername()); | |
1540 ASSERT_EQ("password", tmp.GetPeer().GetPassword()); | |
1541 ASSERT_TRUE(tmp.GetPeer().IsPkcs11Enabled()); | |
1542 } | |
1543 | |
1544 // ResourceModificationJob | |
1545 | |
1546 { | |
1547 std::auto_ptr<DicomModification> modification(new DicomModification); | |
1548 modification->SetupAnonymization(DicomVersion_2008); | |
1549 | |
1550 ResourceModificationJob job(GetContext()); | |
1551 job.SetModification(modification.release(), ResourceType_Patient, true); | |
1552 job.SetOrigin(DicomInstanceOrigin::FromLua()); | |
1553 | |
1554 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1555 ASSERT_TRUE(job.Serialize(s)); | |
1556 } | |
1557 | |
1558 { | |
1559 std::auto_ptr<IJob> job; | |
1560 job.reset(unserializer.UnserializeJob(s)); | |
1561 | |
1562 ResourceModificationJob& tmp = dynamic_cast<ResourceModificationJob&>(*job); | |
1563 ASSERT_TRUE(tmp.IsAnonymization()); | |
1564 ASSERT_EQ(RequestOrigin_Lua, tmp.GetOrigin().GetRequestOrigin()); | |
1565 ASSERT_TRUE(tmp.GetModification().IsRemoved(DICOM_TAG_STUDY_DESCRIPTION)); | |
1566 } | |
1567 | |
1568 // SplitStudyJob | |
1569 | |
1570 std::string instance; | |
1571 ASSERT_TRUE(CreateInstance(instance)); | |
1572 | |
1573 std::string study, series; | |
1574 | |
1575 { | |
1576 ServerContext::DicomCacheLocker lock(GetContext(), instance); | |
1577 study = lock.GetDicom().GetHasher().HashStudy(); | |
1578 series = lock.GetDicom().GetHasher().HashSeries(); | |
1579 } | |
1580 | |
1581 { | |
1582 std::list<std::string> tmp; | |
1583 GetContext().GetIndex().GetAllUuids(tmp, ResourceType_Study); | |
1584 ASSERT_EQ(1u, tmp.size()); | |
1585 ASSERT_EQ(study, tmp.front()); | |
1586 GetContext().GetIndex().GetAllUuids(tmp, ResourceType_Series); | |
1587 ASSERT_EQ(1u, tmp.size()); | |
1588 ASSERT_EQ(series, tmp.front()); | |
1589 } | |
1590 | |
1591 std::string study2; | |
1592 | |
1593 { | |
1594 std::string a, b; | |
1595 | |
1596 { | |
1597 ASSERT_THROW(SplitStudyJob(GetContext(), std::string("nope")), OrthancException); | |
1598 | |
1599 SplitStudyJob job(GetContext(), study); | |
1600 job.SetKeepSource(true); | |
1601 job.AddSourceSeries(series); | |
1602 ASSERT_THROW(job.AddSourceSeries("nope"), OrthancException); | |
1603 job.SetOrigin(DicomInstanceOrigin::FromLua()); | |
1604 job.Replace(DICOM_TAG_PATIENT_NAME, "hello"); | |
1605 job.Remove(DICOM_TAG_PATIENT_BIRTH_DATE); | |
1606 ASSERT_THROW(job.Replace(DICOM_TAG_SERIES_DESCRIPTION, "nope"), OrthancException); | |
1607 ASSERT_THROW(job.Remove(DICOM_TAG_SERIES_DESCRIPTION), OrthancException); | |
1608 | |
1609 ASSERT_TRUE(job.GetTargetStudy().empty()); | |
1610 a = job.GetTargetStudyUid(); | |
1611 ASSERT_TRUE(job.LookupTargetSeriesUid(b, series)); | |
1612 | |
1613 job.AddTrailingStep(); | |
1614 job.Start(); | |
1615 ASSERT_EQ(JobStepCode_Continue, job.Step().GetCode()); | |
1616 ASSERT_EQ(JobStepCode_Success, job.Step().GetCode()); | |
1617 | |
1618 study2 = job.GetTargetStudy(); | |
1619 ASSERT_FALSE(study2.empty()); | |
1620 | |
1621 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1622 ASSERT_TRUE(job.Serialize(s)); | |
1623 } | |
1624 | |
1625 { | |
1626 std::auto_ptr<IJob> job; | |
1627 job.reset(unserializer.UnserializeJob(s)); | |
1628 | |
1629 SplitStudyJob& tmp = dynamic_cast<SplitStudyJob&>(*job); | |
1630 ASSERT_TRUE(tmp.IsKeepSource()); | |
1631 ASSERT_EQ(study, tmp.GetSourceStudy()); | |
1632 ASSERT_EQ(a, tmp.GetTargetStudyUid()); | |
1633 ASSERT_EQ(RequestOrigin_Lua, tmp.GetOrigin().GetRequestOrigin()); | |
1634 | |
1635 std::string s; | |
1636 ASSERT_EQ(study2, tmp.GetTargetStudy()); | |
1637 ASSERT_FALSE(tmp.LookupTargetSeriesUid(s, "nope")); | |
1638 ASSERT_TRUE(tmp.LookupTargetSeriesUid(s, series)); | |
1639 ASSERT_EQ(b, s); | |
1640 | |
1641 ASSERT_FALSE(tmp.LookupReplacement(s, DICOM_TAG_STUDY_DESCRIPTION)); | |
1642 ASSERT_TRUE(tmp.LookupReplacement(s, DICOM_TAG_PATIENT_NAME)); | |
1643 ASSERT_EQ("hello", s); | |
1644 ASSERT_FALSE(tmp.IsRemoved(DICOM_TAG_PATIENT_NAME)); | |
1645 ASSERT_TRUE(tmp.IsRemoved(DICOM_TAG_PATIENT_BIRTH_DATE)); | |
1646 } | |
1647 } | |
1648 | |
1649 { | |
1650 std::list<std::string> tmp; | |
1651 GetContext().GetIndex().GetAllUuids(tmp, ResourceType_Study); | |
1652 ASSERT_EQ(2u, tmp.size()); | |
1653 GetContext().GetIndex().GetAllUuids(tmp, ResourceType_Series); | |
1654 ASSERT_EQ(2u, tmp.size()); | |
1655 } | |
1656 | |
1657 // MergeStudyJob | |
1658 | |
1659 { | |
1660 ASSERT_THROW(SplitStudyJob(GetContext(), std::string("nope")), OrthancException); | |
1661 | |
1662 MergeStudyJob job(GetContext(), study); | |
1663 job.SetKeepSource(true); | |
1664 job.AddSource(study2); | |
1665 ASSERT_THROW(job.AddSourceSeries("nope"), OrthancException); | |
1666 ASSERT_THROW(job.AddSourceStudy("nope"), OrthancException); | |
1667 ASSERT_THROW(job.AddSource("nope"), OrthancException); | |
1668 job.SetOrigin(DicomInstanceOrigin::FromLua()); | |
1669 | |
1670 ASSERT_EQ(job.GetTargetStudy(), study); | |
1671 | |
1672 job.AddTrailingStep(); | |
1673 job.Start(); | |
1674 ASSERT_EQ(JobStepCode_Continue, job.Step().GetCode()); | |
1675 ASSERT_EQ(JobStepCode_Success, job.Step().GetCode()); | |
1676 | |
1677 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1678 ASSERT_TRUE(job.Serialize(s)); | |
1679 } | |
1680 | |
1681 { | |
1682 std::list<std::string> tmp; | |
1683 GetContext().GetIndex().GetAllUuids(tmp, ResourceType_Study); | |
1684 ASSERT_EQ(2u, tmp.size()); | |
1685 GetContext().GetIndex().GetAllUuids(tmp, ResourceType_Series); | |
1686 ASSERT_EQ(3u, tmp.size()); | |
1687 } | |
1688 | |
1689 { | |
1690 std::auto_ptr<IJob> job; | |
1691 job.reset(unserializer.UnserializeJob(s)); | |
1692 | |
1693 MergeStudyJob& tmp = dynamic_cast<MergeStudyJob&>(*job); | |
1694 ASSERT_TRUE(tmp.IsKeepSource()); | |
1695 ASSERT_EQ(study, tmp.GetTargetStudy()); | |
1696 ASSERT_EQ(RequestOrigin_Lua, tmp.GetOrigin().GetRequestOrigin()); | |
1697 } | |
1698 } | |
1699 | |
1700 | |
1701 TEST(JobsSerialization, Registry) | |
1702 { | |
1703 Json::Value s; | |
1704 std::string i1, i2; | |
1705 | |
1706 { | |
1707 JobsRegistry registry; | |
1708 registry.Submit(i1, new DummyJob(), 10); | |
1709 registry.Submit(i2, new SequenceOfOperationsJob(), 30); | |
1710 registry.Serialize(s); | |
1711 } | |
1712 | |
1713 { | |
1714 DummyUnserializer unserializer; | |
1715 JobsRegistry registry(unserializer, s); | |
1716 | |
1717 Json::Value t; | |
1718 registry.Serialize(t); | |
1719 ASSERT_TRUE(CheckSameJson(s, t)); | |
1720 } | |
1721 } | |
1722 | |
1723 | |
1724 TEST(JobsSerialization, TrailingStep) | |
1725 { | |
1726 { | |
1727 Json::Value s; | |
1728 | |
1729 DummyInstancesJob job; | |
1730 ASSERT_EQ(0, job.GetCommandsCount()); | |
1731 ASSERT_EQ(0, job.GetInstancesCount()); | |
1732 | |
1733 job.Start(); | |
1734 ASSERT_EQ(0, job.GetPosition()); | |
1735 ASSERT_FALSE(job.HasTrailingStep()); | |
1736 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1737 | |
1738 { | |
1739 DummyUnserializer unserializer; | |
1740 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1741 } | |
1742 | |
1743 ASSERT_EQ(JobStepCode_Success, job.Step().GetCode()); | |
1744 ASSERT_EQ(1, job.GetPosition()); | |
1745 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1746 | |
1747 { | |
1748 DummyUnserializer unserializer; | |
1749 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1750 } | |
1751 | |
1752 ASSERT_THROW(job.Step(), OrthancException); | |
1753 } | |
1754 | |
1755 { | |
1756 Json::Value s; | |
1757 | |
1758 DummyInstancesJob job; | |
1759 job.AddInstance("hello"); | |
1760 job.AddInstance("world"); | |
1761 ASSERT_EQ(2, job.GetCommandsCount()); | |
1762 ASSERT_EQ(2, job.GetInstancesCount()); | |
1763 | |
1764 job.Start(); | |
1765 ASSERT_EQ(0, job.GetPosition()); | |
1766 ASSERT_FALSE(job.HasTrailingStep()); | |
1767 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1768 | |
1769 { | |
1770 DummyUnserializer unserializer; | |
1771 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1772 } | |
1773 | |
1774 ASSERT_EQ(JobStepCode_Continue, job.Step().GetCode()); | |
1775 ASSERT_EQ(1, job.GetPosition()); | |
1776 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1777 | |
1778 { | |
1779 DummyUnserializer unserializer; | |
1780 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1781 } | |
1782 | |
1783 ASSERT_EQ(JobStepCode_Success, job.Step().GetCode()); | |
1784 ASSERT_EQ(2, job.GetPosition()); | |
1785 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1786 | |
1787 { | |
1788 DummyUnserializer unserializer; | |
1789 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1790 } | |
1791 | |
1792 ASSERT_THROW(job.Step(), OrthancException); | |
1793 } | |
1794 | |
1795 { | |
1796 Json::Value s; | |
1797 | |
1798 DummyInstancesJob job; | |
1799 ASSERT_EQ(0, job.GetInstancesCount()); | |
1800 ASSERT_EQ(0, job.GetCommandsCount()); | |
1801 job.AddTrailingStep(); | |
1802 ASSERT_EQ(0, job.GetInstancesCount()); | |
1803 ASSERT_EQ(1, job.GetCommandsCount()); | |
1804 | |
1805 job.Start(); // This adds the trailing step | |
1806 ASSERT_EQ(0, job.GetPosition()); | |
1807 ASSERT_TRUE(job.HasTrailingStep()); | |
1808 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1809 | |
1810 { | |
1811 DummyUnserializer unserializer; | |
1812 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1813 } | |
1814 | |
1815 ASSERT_EQ(JobStepCode_Success, job.Step().GetCode()); | |
1816 ASSERT_EQ(1, job.GetPosition()); | |
1817 ASSERT_TRUE(job.IsTrailingStepDone()); | |
1818 | |
1819 { | |
1820 DummyUnserializer unserializer; | |
1821 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1822 } | |
1823 | |
1824 ASSERT_THROW(job.Step(), OrthancException); | |
1825 } | |
1826 | |
1827 { | |
1828 Json::Value s; | |
1829 | |
1830 DummyInstancesJob job; | |
1831 job.AddInstance("hello"); | |
1832 ASSERT_EQ(1, job.GetInstancesCount()); | |
1833 ASSERT_EQ(1, job.GetCommandsCount()); | |
1834 job.AddTrailingStep(); | |
1835 ASSERT_EQ(1, job.GetInstancesCount()); | |
1836 ASSERT_EQ(2, job.GetCommandsCount()); | |
1837 | |
1838 job.Start(); | |
1839 ASSERT_EQ(2, job.GetCommandsCount()); | |
1840 ASSERT_EQ(0, job.GetPosition()); | |
1841 ASSERT_TRUE(job.HasTrailingStep()); | |
1842 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1843 | |
1844 { | |
1845 DummyUnserializer unserializer; | |
1846 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1847 } | |
1848 | |
1849 ASSERT_EQ(JobStepCode_Continue, job.Step().GetCode()); | |
1850 ASSERT_EQ(1, job.GetPosition()); | |
1851 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1852 | |
1853 { | |
1854 DummyUnserializer unserializer; | |
1855 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1856 } | |
1857 | |
1858 ASSERT_EQ(JobStepCode_Success, job.Step().GetCode()); | |
1859 ASSERT_EQ(2, job.GetPosition()); | |
1860 ASSERT_TRUE(job.IsTrailingStepDone()); | |
1861 | |
1862 { | |
1863 DummyUnserializer unserializer; | |
1864 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1865 } | |
1866 | |
1867 ASSERT_THROW(job.Step(), OrthancException); | |
1868 } | |
1869 } | |
1870 | |
1871 | |
1872 TEST(JobsSerialization, RemoteModalityParameters) | |
1873 { | |
1874 Json::Value s; | |
1875 | |
1876 { | |
1877 RemoteModalityParameters modality; | |
1878 ASSERT_FALSE(modality.IsAdvancedFormatNeeded()); | |
1879 modality.Serialize(s, false); | |
1880 ASSERT_EQ(Json::arrayValue, s.type()); | |
1881 } | |
1882 | |
1883 { | |
1884 RemoteModalityParameters modality(s); | |
1885 ASSERT_EQ("ORTHANC", modality.GetApplicationEntityTitle()); | |
1886 ASSERT_EQ("127.0.0.1", modality.GetHost()); | |
1887 ASSERT_EQ(104u, modality.GetPortNumber()); | |
1888 ASSERT_EQ(ModalityManufacturer_Generic, modality.GetManufacturer()); | |
1889 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Echo)); | |
1890 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Find)); | |
1891 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Get)); | |
1892 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Store)); | |
1893 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Move)); | |
1894 } | |
1895 | |
1896 s = Json::nullValue; | |
1897 | |
1898 { | |
1899 RemoteModalityParameters modality; | |
1900 ASSERT_FALSE(modality.IsAdvancedFormatNeeded()); | |
1901 ASSERT_THROW(modality.SetPortNumber(0), OrthancException); | |
1902 ASSERT_THROW(modality.SetPortNumber(65535), OrthancException); | |
1903 modality.SetApplicationEntityTitle("HELLO"); | |
1904 modality.SetHost("world"); | |
1905 modality.SetPortNumber(45); | |
1906 modality.SetManufacturer(ModalityManufacturer_Dcm4Chee); | |
1907 modality.Serialize(s, true); | |
1908 ASSERT_EQ(Json::objectValue, s.type()); | |
1909 } | |
1910 | |
1911 { | |
1912 RemoteModalityParameters modality(s); | |
1913 ASSERT_EQ("HELLO", modality.GetApplicationEntityTitle()); | |
1914 ASSERT_EQ("world", modality.GetHost()); | |
1915 ASSERT_EQ(45u, modality.GetPortNumber()); | |
1916 ASSERT_EQ(ModalityManufacturer_Dcm4Chee, modality.GetManufacturer()); | |
1917 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Echo)); | |
1918 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Find)); | |
1919 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Get)); | |
1920 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Store)); | |
1921 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Move)); | |
1922 } | |
1923 | |
1924 s["Port"] = "46"; | |
1925 | |
1926 { | |
1927 RemoteModalityParameters modality(s); | |
1928 ASSERT_EQ(46u, modality.GetPortNumber()); | |
1929 } | |
1930 | |
1931 s["Port"] = -1; ASSERT_THROW(RemoteModalityParameters m(s), OrthancException); | |
1932 s["Port"] = 65535; ASSERT_THROW(RemoteModalityParameters m(s), OrthancException); | |
1933 s["Port"] = "nope"; ASSERT_THROW(RemoteModalityParameters m(s), OrthancException); | |
1934 | |
1935 std::set<DicomRequestType> operations; | |
1936 operations.insert(DicomRequestType_Echo); | |
1937 operations.insert(DicomRequestType_Find); | |
1938 operations.insert(DicomRequestType_Get); | |
1939 operations.insert(DicomRequestType_Move); | |
1940 operations.insert(DicomRequestType_Store); | |
1941 | |
1942 ASSERT_EQ(5u, operations.size()); | |
1943 | |
1944 for (std::set<DicomRequestType>::const_iterator | |
1945 it = operations.begin(); it != operations.end(); ++it) | |
1946 { | |
1947 { | |
1948 RemoteModalityParameters modality; | |
1949 modality.SetRequestAllowed(*it, false); | |
1950 ASSERT_TRUE(modality.IsAdvancedFormatNeeded()); | |
1951 | |
1952 modality.Serialize(s, false); | |
1953 ASSERT_EQ(Json::objectValue, s.type()); | |
1954 } | |
1955 | |
1956 { | |
1957 RemoteModalityParameters modality(s); | |
1958 | |
1959 ASSERT_FALSE(modality.IsRequestAllowed(*it)); | |
1960 | |
1961 for (std::set<DicomRequestType>::const_iterator | |
1962 it2 = operations.begin(); it2 != operations.end(); ++it2) | |
1963 { | |
1964 if (*it2 != *it) | |
1965 { | |
1966 ASSERT_TRUE(modality.IsRequestAllowed(*it2)); | |
1967 } | |
1968 } | |
1969 } | |
1970 } | |
1971 } |