Mercurial > hg > orthanc
comparison OrthancFramework/UnitTestsSources/JobsTests.cpp @ 4060:149172a06b4d framework
splitting MultiThreadingTests.cpp into JobsTests.cpp and ServerJobsTests.cpp
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 11 Jun 2020 14:29:14 +0200 |
parents | OrthancServer/UnitTestsSources/MultiThreadingTests.cpp@05b8fd21089c |
children | 0953b3dc3261 |
comparison
equal
deleted
inserted
replaced
4059:e241e5f3f088 | 4060:149172a06b4d |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1 | |
35 # include <OrthancFramework.h> | |
36 #endif | |
37 | |
38 #include "gtest/gtest.h" | |
39 | |
40 #include "../../OrthancFramework/Sources/Compatibility.h" | |
41 #include "../../OrthancFramework/Sources/DicomNetworking/RemoteModalityParameters.h" | |
42 #include "../../OrthancFramework/Sources/DicomParsing/DicomModification.h" | |
43 #include "../../OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h" | |
44 #include "../../OrthancFramework/Sources/JobsEngine/GenericJobUnserializer.h" | |
45 #include "../../OrthancFramework/Sources/JobsEngine/JobsEngine.h" | |
46 #include "../../OrthancFramework/Sources/JobsEngine/Operations/JobOperationValues.h" | |
47 #include "../../OrthancFramework/Sources/JobsEngine/Operations/LogJobOperation.h" | |
48 #include "../../OrthancFramework/Sources/JobsEngine/Operations/NullOperationValue.h" | |
49 #include "../../OrthancFramework/Sources/JobsEngine/Operations/SequenceOfOperationsJob.h" | |
50 #include "../../OrthancFramework/Sources/JobsEngine/Operations/StringOperationValue.h" | |
51 #include "../../OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h" | |
52 #include "../../OrthancFramework/Sources/Logging.h" | |
53 #include "../../OrthancFramework/Sources/MultiThreading/SharedMessageQueue.h" | |
54 #include "../../OrthancFramework/Sources/OrthancException.h" | |
55 #include "../../OrthancFramework/Sources/SerializationToolbox.h" | |
56 | |
57 | |
58 using namespace Orthanc; | |
59 | |
60 namespace | |
61 { | |
62 class DummyJob : public IJob | |
63 { | |
64 private: | |
65 bool fails_; | |
66 unsigned int count_; | |
67 unsigned int steps_; | |
68 | |
69 public: | |
70 DummyJob() : | |
71 fails_(false), | |
72 count_(0), | |
73 steps_(4) | |
74 { | |
75 } | |
76 | |
77 explicit DummyJob(bool fails) : | |
78 fails_(fails), | |
79 count_(0), | |
80 steps_(4) | |
81 { | |
82 } | |
83 | |
84 virtual void Start() ORTHANC_OVERRIDE | |
85 { | |
86 } | |
87 | |
88 virtual void Reset() ORTHANC_OVERRIDE | |
89 { | |
90 } | |
91 | |
92 virtual JobStepResult Step(const std::string& jobId) ORTHANC_OVERRIDE | |
93 { | |
94 if (fails_) | |
95 { | |
96 return JobStepResult::Failure(ErrorCode_ParameterOutOfRange, NULL); | |
97 } | |
98 else if (count_ == steps_ - 1) | |
99 { | |
100 return JobStepResult::Success(); | |
101 } | |
102 else | |
103 { | |
104 count_++; | |
105 return JobStepResult::Continue(); | |
106 } | |
107 } | |
108 | |
109 virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE | |
110 { | |
111 } | |
112 | |
113 virtual float GetProgress() ORTHANC_OVERRIDE | |
114 { | |
115 return static_cast<float>(count_) / static_cast<float>(steps_ - 1); | |
116 } | |
117 | |
118 virtual void GetJobType(std::string& type) ORTHANC_OVERRIDE | |
119 { | |
120 type = "DummyJob"; | |
121 } | |
122 | |
123 virtual bool Serialize(Json::Value& value) ORTHANC_OVERRIDE | |
124 { | |
125 value = Json::objectValue; | |
126 value["Type"] = "DummyJob"; | |
127 return true; | |
128 } | |
129 | |
130 virtual void GetPublicContent(Json::Value& value) ORTHANC_OVERRIDE | |
131 { | |
132 value["hello"] = "world"; | |
133 } | |
134 | |
135 virtual bool GetOutput(std::string& output, | |
136 MimeType& mime, | |
137 const std::string& key) ORTHANC_OVERRIDE | |
138 { | |
139 return false; | |
140 } | |
141 }; | |
142 | |
143 | |
144 class DummyInstancesJob : public SetOfInstancesJob | |
145 { | |
146 private: | |
147 bool trailingStepDone_; | |
148 | |
149 protected: | |
150 virtual bool HandleInstance(const std::string& instance) ORTHANC_OVERRIDE | |
151 { | |
152 return (instance != "nope"); | |
153 } | |
154 | |
155 virtual bool HandleTrailingStep() ORTHANC_OVERRIDE | |
156 { | |
157 if (HasTrailingStep()) | |
158 { | |
159 if (trailingStepDone_) | |
160 { | |
161 throw OrthancException(ErrorCode_InternalError); | |
162 } | |
163 else | |
164 { | |
165 trailingStepDone_ = true; | |
166 return true; | |
167 } | |
168 } | |
169 else | |
170 { | |
171 throw OrthancException(ErrorCode_InternalError); | |
172 } | |
173 } | |
174 | |
175 public: | |
176 DummyInstancesJob() : | |
177 trailingStepDone_(false) | |
178 { | |
179 } | |
180 | |
181 DummyInstancesJob(const Json::Value& value) : | |
182 SetOfInstancesJob(value) | |
183 { | |
184 if (HasTrailingStep()) | |
185 { | |
186 trailingStepDone_ = (GetPosition() == GetCommandsCount()); | |
187 } | |
188 else | |
189 { | |
190 trailingStepDone_ = false; | |
191 } | |
192 } | |
193 | |
194 bool IsTrailingStepDone() const | |
195 { | |
196 return trailingStepDone_; | |
197 } | |
198 | |
199 virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE | |
200 { | |
201 } | |
202 | |
203 virtual void GetJobType(std::string& s) ORTHANC_OVERRIDE | |
204 { | |
205 s = "DummyInstancesJob"; | |
206 } | |
207 }; | |
208 | |
209 | |
210 class DummyUnserializer : public GenericJobUnserializer | |
211 { | |
212 public: | |
213 virtual IJob* UnserializeJob(const Json::Value& value) ORTHANC_OVERRIDE | |
214 { | |
215 if (SerializationToolbox::ReadString(value, "Type") == "DummyInstancesJob") | |
216 { | |
217 return new DummyInstancesJob(value); | |
218 } | |
219 else if (SerializationToolbox::ReadString(value, "Type") == "DummyJob") | |
220 { | |
221 return new DummyJob; | |
222 } | |
223 else | |
224 { | |
225 return GenericJobUnserializer::UnserializeJob(value); | |
226 } | |
227 } | |
228 }; | |
229 | |
230 | |
231 class DynamicInteger : public IDynamicObject | |
232 { | |
233 private: | |
234 int value_; | |
235 std::set<int>& target_; | |
236 | |
237 public: | |
238 DynamicInteger(int value, std::set<int>& target) : | |
239 value_(value), target_(target) | |
240 { | |
241 } | |
242 | |
243 int GetValue() const | |
244 { | |
245 return value_; | |
246 } | |
247 }; | |
248 } | |
249 | |
250 | |
251 TEST(MultiThreading, SharedMessageQueueBasic) | |
252 { | |
253 std::set<int> s; | |
254 | |
255 SharedMessageQueue q; | |
256 ASSERT_TRUE(q.WaitEmpty(0)); | |
257 q.Enqueue(new DynamicInteger(10, s)); | |
258 ASSERT_FALSE(q.WaitEmpty(1)); | |
259 q.Enqueue(new DynamicInteger(20, s)); | |
260 q.Enqueue(new DynamicInteger(30, s)); | |
261 q.Enqueue(new DynamicInteger(40, s)); | |
262 | |
263 std::unique_ptr<DynamicInteger> i; | |
264 i.reset(dynamic_cast<DynamicInteger*>(q.Dequeue(1))); ASSERT_EQ(10, i->GetValue()); | |
265 i.reset(dynamic_cast<DynamicInteger*>(q.Dequeue(1))); ASSERT_EQ(20, i->GetValue()); | |
266 i.reset(dynamic_cast<DynamicInteger*>(q.Dequeue(1))); ASSERT_EQ(30, i->GetValue()); | |
267 ASSERT_FALSE(q.WaitEmpty(1)); | |
268 i.reset(dynamic_cast<DynamicInteger*>(q.Dequeue(1))); ASSERT_EQ(40, i->GetValue()); | |
269 ASSERT_TRUE(q.WaitEmpty(0)); | |
270 ASSERT_EQ(NULL, q.Dequeue(1)); | |
271 } | |
272 | |
273 | |
274 TEST(MultiThreading, SharedMessageQueueClean) | |
275 { | |
276 std::set<int> s; | |
277 | |
278 try | |
279 { | |
280 SharedMessageQueue q; | |
281 q.Enqueue(new DynamicInteger(10, s)); | |
282 q.Enqueue(new DynamicInteger(20, s)); | |
283 throw OrthancException(ErrorCode_InternalError); | |
284 } | |
285 catch (OrthancException&) | |
286 { | |
287 } | |
288 } | |
289 | |
290 | |
291 | |
292 | |
293 static bool CheckState(JobsRegistry& registry, | |
294 const std::string& id, | |
295 JobState state) | |
296 { | |
297 JobState s; | |
298 if (registry.GetState(s, id)) | |
299 { | |
300 return state == s; | |
301 } | |
302 else | |
303 { | |
304 return false; | |
305 } | |
306 } | |
307 | |
308 | |
309 static bool CheckErrorCode(JobsRegistry& registry, | |
310 const std::string& id, | |
311 ErrorCode code) | |
312 { | |
313 JobInfo s; | |
314 if (registry.GetJobInfo(s, id)) | |
315 { | |
316 return code == s.GetStatus().GetErrorCode(); | |
317 } | |
318 else | |
319 { | |
320 return false; | |
321 } | |
322 } | |
323 | |
324 | |
325 TEST(JobsRegistry, Priority) | |
326 { | |
327 JobsRegistry registry(10); | |
328 | |
329 std::string i1, i2, i3, i4; | |
330 registry.Submit(i1, new DummyJob(), 10); | |
331 registry.Submit(i2, new DummyJob(), 30); | |
332 registry.Submit(i3, new DummyJob(), 20); | |
333 registry.Submit(i4, new DummyJob(), 5); | |
334 | |
335 registry.SetMaxCompletedJobs(2); | |
336 | |
337 std::set<std::string> id; | |
338 registry.ListJobs(id); | |
339 | |
340 ASSERT_EQ(4u, id.size()); | |
341 ASSERT_TRUE(id.find(i1) != id.end()); | |
342 ASSERT_TRUE(id.find(i2) != id.end()); | |
343 ASSERT_TRUE(id.find(i3) != id.end()); | |
344 ASSERT_TRUE(id.find(i4) != id.end()); | |
345 | |
346 ASSERT_TRUE(CheckState(registry, i2, JobState_Pending)); | |
347 | |
348 { | |
349 JobsRegistry::RunningJob job(registry, 0); | |
350 ASSERT_TRUE(job.IsValid()); | |
351 ASSERT_EQ(30, job.GetPriority()); | |
352 ASSERT_EQ(i2, job.GetId()); | |
353 | |
354 ASSERT_TRUE(CheckState(registry, i2, JobState_Running)); | |
355 } | |
356 | |
357 ASSERT_TRUE(CheckState(registry, i2, JobState_Failure)); | |
358 ASSERT_TRUE(CheckState(registry, i3, JobState_Pending)); | |
359 | |
360 { | |
361 JobsRegistry::RunningJob job(registry, 0); | |
362 ASSERT_TRUE(job.IsValid()); | |
363 ASSERT_EQ(20, job.GetPriority()); | |
364 ASSERT_EQ(i3, job.GetId()); | |
365 | |
366 job.MarkSuccess(); | |
367 | |
368 ASSERT_TRUE(CheckState(registry, i3, JobState_Running)); | |
369 } | |
370 | |
371 ASSERT_TRUE(CheckState(registry, i3, JobState_Success)); | |
372 | |
373 { | |
374 JobsRegistry::RunningJob job(registry, 0); | |
375 ASSERT_TRUE(job.IsValid()); | |
376 ASSERT_EQ(10, job.GetPriority()); | |
377 ASSERT_EQ(i1, job.GetId()); | |
378 } | |
379 | |
380 { | |
381 JobsRegistry::RunningJob job(registry, 0); | |
382 ASSERT_TRUE(job.IsValid()); | |
383 ASSERT_EQ(5, job.GetPriority()); | |
384 ASSERT_EQ(i4, job.GetId()); | |
385 } | |
386 | |
387 { | |
388 JobsRegistry::RunningJob job(registry, 1); | |
389 ASSERT_FALSE(job.IsValid()); | |
390 } | |
391 | |
392 JobState s; | |
393 ASSERT_TRUE(registry.GetState(s, i1)); | |
394 ASSERT_FALSE(registry.GetState(s, i2)); // Removed because oldest | |
395 ASSERT_FALSE(registry.GetState(s, i3)); // Removed because second oldest | |
396 ASSERT_TRUE(registry.GetState(s, i4)); | |
397 | |
398 registry.SetMaxCompletedJobs(1); // (*) | |
399 ASSERT_FALSE(registry.GetState(s, i1)); // Just discarded by (*) | |
400 ASSERT_TRUE(registry.GetState(s, i4)); | |
401 } | |
402 | |
403 | |
404 TEST(JobsRegistry, Simultaneous) | |
405 { | |
406 JobsRegistry registry(10); | |
407 | |
408 std::string i1, i2; | |
409 registry.Submit(i1, new DummyJob(), 20); | |
410 registry.Submit(i2, new DummyJob(), 10); | |
411 | |
412 ASSERT_TRUE(CheckState(registry, i1, JobState_Pending)); | |
413 ASSERT_TRUE(CheckState(registry, i2, JobState_Pending)); | |
414 | |
415 { | |
416 JobsRegistry::RunningJob job1(registry, 0); | |
417 JobsRegistry::RunningJob job2(registry, 0); | |
418 | |
419 ASSERT_TRUE(job1.IsValid()); | |
420 ASSERT_TRUE(job2.IsValid()); | |
421 | |
422 job1.MarkFailure(); | |
423 job2.MarkSuccess(); | |
424 | |
425 ASSERT_TRUE(CheckState(registry, i1, JobState_Running)); | |
426 ASSERT_TRUE(CheckState(registry, i2, JobState_Running)); | |
427 } | |
428 | |
429 ASSERT_TRUE(CheckState(registry, i1, JobState_Failure)); | |
430 ASSERT_TRUE(CheckState(registry, i2, JobState_Success)); | |
431 } | |
432 | |
433 | |
434 TEST(JobsRegistry, Resubmit) | |
435 { | |
436 JobsRegistry registry(10); | |
437 | |
438 std::string id; | |
439 registry.Submit(id, new DummyJob(), 10); | |
440 | |
441 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
442 | |
443 registry.Resubmit(id); | |
444 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
445 | |
446 { | |
447 JobsRegistry::RunningJob job(registry, 0); | |
448 ASSERT_TRUE(job.IsValid()); | |
449 job.MarkFailure(); | |
450 | |
451 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
452 | |
453 registry.Resubmit(id); | |
454 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
455 } | |
456 | |
457 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
458 | |
459 registry.Resubmit(id); | |
460 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
461 | |
462 { | |
463 JobsRegistry::RunningJob job(registry, 0); | |
464 ASSERT_TRUE(job.IsValid()); | |
465 ASSERT_EQ(id, job.GetId()); | |
466 | |
467 job.MarkSuccess(); | |
468 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
469 } | |
470 | |
471 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
472 | |
473 registry.Resubmit(id); | |
474 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
475 } | |
476 | |
477 | |
478 TEST(JobsRegistry, Retry) | |
479 { | |
480 JobsRegistry registry(10); | |
481 | |
482 std::string id; | |
483 registry.Submit(id, new DummyJob(), 10); | |
484 | |
485 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
486 | |
487 { | |
488 JobsRegistry::RunningJob job(registry, 0); | |
489 ASSERT_TRUE(job.IsValid()); | |
490 job.MarkRetry(0); | |
491 | |
492 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
493 } | |
494 | |
495 ASSERT_TRUE(CheckState(registry, id, JobState_Retry)); | |
496 | |
497 registry.Resubmit(id); | |
498 ASSERT_TRUE(CheckState(registry, id, JobState_Retry)); | |
499 | |
500 registry.ScheduleRetries(); | |
501 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
502 | |
503 { | |
504 JobsRegistry::RunningJob job(registry, 0); | |
505 ASSERT_TRUE(job.IsValid()); | |
506 job.MarkSuccess(); | |
507 | |
508 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
509 } | |
510 | |
511 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
512 } | |
513 | |
514 | |
515 TEST(JobsRegistry, PausePending) | |
516 { | |
517 JobsRegistry registry(10); | |
518 | |
519 std::string id; | |
520 registry.Submit(id, new DummyJob(), 10); | |
521 | |
522 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
523 | |
524 registry.Pause(id); | |
525 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
526 | |
527 registry.Pause(id); | |
528 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
529 | |
530 registry.Resubmit(id); | |
531 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
532 | |
533 registry.Resume(id); | |
534 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
535 } | |
536 | |
537 | |
538 TEST(JobsRegistry, PauseRunning) | |
539 { | |
540 JobsRegistry registry(10); | |
541 | |
542 std::string id; | |
543 registry.Submit(id, new DummyJob(), 10); | |
544 | |
545 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
546 | |
547 { | |
548 JobsRegistry::RunningJob job(registry, 0); | |
549 ASSERT_TRUE(job.IsValid()); | |
550 | |
551 registry.Resubmit(id); | |
552 job.MarkPause(); | |
553 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
554 } | |
555 | |
556 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
557 | |
558 registry.Resubmit(id); | |
559 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
560 | |
561 registry.Resume(id); | |
562 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
563 | |
564 { | |
565 JobsRegistry::RunningJob job(registry, 0); | |
566 ASSERT_TRUE(job.IsValid()); | |
567 | |
568 job.MarkSuccess(); | |
569 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
570 } | |
571 | |
572 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
573 } | |
574 | |
575 | |
576 TEST(JobsRegistry, PauseRetry) | |
577 { | |
578 JobsRegistry registry(10); | |
579 | |
580 std::string id; | |
581 registry.Submit(id, new DummyJob(), 10); | |
582 | |
583 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
584 | |
585 { | |
586 JobsRegistry::RunningJob job(registry, 0); | |
587 ASSERT_TRUE(job.IsValid()); | |
588 | |
589 job.MarkRetry(0); | |
590 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
591 } | |
592 | |
593 ASSERT_TRUE(CheckState(registry, id, JobState_Retry)); | |
594 | |
595 registry.Pause(id); | |
596 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
597 | |
598 registry.Resume(id); | |
599 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
600 | |
601 { | |
602 JobsRegistry::RunningJob job(registry, 0); | |
603 ASSERT_TRUE(job.IsValid()); | |
604 | |
605 job.MarkSuccess(); | |
606 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
607 } | |
608 | |
609 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
610 } | |
611 | |
612 | |
613 TEST(JobsRegistry, Cancel) | |
614 { | |
615 JobsRegistry registry(10); | |
616 | |
617 std::string id; | |
618 registry.Submit(id, new DummyJob(), 10); | |
619 | |
620 ASSERT_FALSE(registry.Cancel("nope")); | |
621 | |
622 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
623 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
624 | |
625 ASSERT_TRUE(registry.Cancel(id)); | |
626 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
627 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
628 | |
629 ASSERT_TRUE(registry.Cancel(id)); | |
630 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
631 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
632 | |
633 ASSERT_TRUE(registry.Resubmit(id)); | |
634 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
635 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
636 | |
637 { | |
638 JobsRegistry::RunningJob job(registry, 0); | |
639 ASSERT_TRUE(job.IsValid()); | |
640 | |
641 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
642 | |
643 job.MarkSuccess(); | |
644 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
645 } | |
646 | |
647 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
648 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
649 | |
650 ASSERT_TRUE(registry.Cancel(id)); | |
651 ASSERT_TRUE(CheckState(registry, id, JobState_Success)); | |
652 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
653 | |
654 registry.Submit(id, new DummyJob(), 10); | |
655 | |
656 { | |
657 JobsRegistry::RunningJob job(registry, 0); | |
658 ASSERT_TRUE(job.IsValid()); | |
659 ASSERT_EQ(id, job.GetId()); | |
660 | |
661 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
662 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
663 | |
664 job.MarkCanceled(); | |
665 } | |
666 | |
667 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
668 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
669 | |
670 ASSERT_TRUE(registry.Resubmit(id)); | |
671 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
672 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
673 | |
674 ASSERT_TRUE(registry.Pause(id)); | |
675 ASSERT_TRUE(CheckState(registry, id, JobState_Paused)); | |
676 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
677 | |
678 ASSERT_TRUE(registry.Cancel(id)); | |
679 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
680 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
681 | |
682 ASSERT_TRUE(registry.Resubmit(id)); | |
683 ASSERT_TRUE(CheckState(registry, id, JobState_Pending)); | |
684 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
685 | |
686 { | |
687 JobsRegistry::RunningJob job(registry, 0); | |
688 ASSERT_TRUE(job.IsValid()); | |
689 ASSERT_EQ(id, job.GetId()); | |
690 | |
691 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
692 ASSERT_TRUE(CheckState(registry, id, JobState_Running)); | |
693 | |
694 job.MarkRetry(500); | |
695 } | |
696 | |
697 ASSERT_TRUE(CheckState(registry, id, JobState_Retry)); | |
698 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_Success)); | |
699 | |
700 ASSERT_TRUE(registry.Cancel(id)); | |
701 ASSERT_TRUE(CheckState(registry, id, JobState_Failure)); | |
702 ASSERT_TRUE(CheckErrorCode(registry, id, ErrorCode_CanceledJob)); | |
703 } | |
704 | |
705 | |
706 | |
707 TEST(JobsEngine, SubmitAndWait) | |
708 { | |
709 JobsEngine engine(10); | |
710 engine.SetThreadSleep(10); | |
711 engine.SetWorkersCount(3); | |
712 engine.Start(); | |
713 | |
714 Json::Value content = Json::nullValue; | |
715 engine.GetRegistry().SubmitAndWait(content, new DummyJob(), rand() % 10); | |
716 ASSERT_EQ(Json::objectValue, content.type()); | |
717 ASSERT_EQ("world", content["hello"].asString()); | |
718 | |
719 content = Json::nullValue; | |
720 ASSERT_THROW(engine.GetRegistry().SubmitAndWait(content, new DummyJob(true), rand() % 10), OrthancException); | |
721 ASSERT_EQ(Json::nullValue, content.type()); | |
722 | |
723 engine.Stop(); | |
724 } | |
725 | |
726 | |
727 TEST(JobsEngine, DISABLED_SequenceOfOperationsJob) | |
728 { | |
729 JobsEngine engine(10); | |
730 engine.SetThreadSleep(10); | |
731 engine.SetWorkersCount(3); | |
732 engine.Start(); | |
733 | |
734 std::string id; | |
735 SequenceOfOperationsJob* job = NULL; | |
736 | |
737 { | |
738 std::unique_ptr<SequenceOfOperationsJob> a(new SequenceOfOperationsJob); | |
739 job = a.get(); | |
740 engine.GetRegistry().Submit(id, a.release(), 0); | |
741 } | |
742 | |
743 boost::this_thread::sleep(boost::posix_time::milliseconds(500)); | |
744 | |
745 { | |
746 SequenceOfOperationsJob::Lock lock(*job); | |
747 size_t i = lock.AddOperation(new LogJobOperation); | |
748 size_t j = lock.AddOperation(new LogJobOperation); | |
749 size_t k = lock.AddOperation(new LogJobOperation); | |
750 | |
751 StringOperationValue a("Hello"); | |
752 StringOperationValue b("World"); | |
753 lock.AddInput(i, a); | |
754 lock.AddInput(i, b); | |
755 | |
756 lock.Connect(i, j); | |
757 lock.Connect(j, k); | |
758 } | |
759 | |
760 boost::this_thread::sleep(boost::posix_time::milliseconds(2000)); | |
761 | |
762 engine.Stop(); | |
763 | |
764 } | |
765 | |
766 | |
767 static bool CheckSameJson(const Json::Value& a, | |
768 const Json::Value& b) | |
769 { | |
770 std::string s = a.toStyledString(); | |
771 std::string t = b.toStyledString(); | |
772 | |
773 if (s == t) | |
774 { | |
775 return true; | |
776 } | |
777 else | |
778 { | |
779 LOG(ERROR) << "Expected serialization: " << s; | |
780 LOG(ERROR) << "Actual serialization: " << t; | |
781 return false; | |
782 } | |
783 } | |
784 | |
785 | |
786 static bool CheckIdempotentSerialization(IJobUnserializer& unserializer, | |
787 IJob& job) | |
788 { | |
789 Json::Value a = 42; | |
790 | |
791 if (!job.Serialize(a)) | |
792 { | |
793 return false; | |
794 } | |
795 else | |
796 { | |
797 std::unique_ptr<IJob> unserialized(unserializer.UnserializeJob(a)); | |
798 | |
799 Json::Value b = 43; | |
800 if (unserialized->Serialize(b)) | |
801 { | |
802 return (CheckSameJson(a, b)); | |
803 } | |
804 else | |
805 { | |
806 return false; | |
807 } | |
808 } | |
809 } | |
810 | |
811 | |
812 static bool CheckIdempotentSetOfInstances(IJobUnserializer& unserializer, | |
813 SetOfInstancesJob& job) | |
814 { | |
815 Json::Value a = 42; | |
816 | |
817 if (!job.Serialize(a)) | |
818 { | |
819 return false; | |
820 } | |
821 else | |
822 { | |
823 std::unique_ptr<SetOfInstancesJob> unserialized | |
824 (dynamic_cast<SetOfInstancesJob*>(unserializer.UnserializeJob(a))); | |
825 | |
826 Json::Value b = 43; | |
827 if (unserialized->Serialize(b)) | |
828 { | |
829 return (CheckSameJson(a, b) && | |
830 job.HasTrailingStep() == unserialized->HasTrailingStep() && | |
831 job.GetPosition() == unserialized->GetPosition() && | |
832 job.GetInstancesCount() == unserialized->GetInstancesCount() && | |
833 job.GetCommandsCount() == unserialized->GetCommandsCount()); | |
834 } | |
835 else | |
836 { | |
837 return false; | |
838 } | |
839 } | |
840 } | |
841 | |
842 | |
843 static bool CheckIdempotentSerialization(IJobUnserializer& unserializer, | |
844 JobOperationValue& value) | |
845 { | |
846 Json::Value a = 42; | |
847 value.Serialize(a); | |
848 | |
849 std::unique_ptr<JobOperationValue> unserialized(unserializer.UnserializeValue(a)); | |
850 | |
851 Json::Value b = 43; | |
852 unserialized->Serialize(b); | |
853 | |
854 return CheckSameJson(a, b); | |
855 } | |
856 | |
857 | |
858 TEST(JobsSerialization, BadFileFormat) | |
859 { | |
860 GenericJobUnserializer unserializer; | |
861 | |
862 Json::Value s; | |
863 | |
864 s = Json::objectValue; | |
865 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
866 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
867 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
868 | |
869 s = Json::arrayValue; | |
870 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
871 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
872 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
873 | |
874 s = "hello"; | |
875 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
876 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
877 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
878 | |
879 s = 42; | |
880 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
881 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
882 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
883 } | |
884 | |
885 | |
886 TEST(JobsSerialization, JobOperationValues) | |
887 { | |
888 Json::Value s; | |
889 | |
890 { | |
891 JobOperationValues values; | |
892 values.Append(new NullOperationValue); | |
893 values.Append(new StringOperationValue("hello")); | |
894 values.Append(new StringOperationValue("world")); | |
895 | |
896 s = 42; | |
897 values.Serialize(s); | |
898 } | |
899 | |
900 { | |
901 GenericJobUnserializer unserializer; | |
902 std::unique_ptr<JobOperationValues> values(JobOperationValues::Unserialize(unserializer, s)); | |
903 ASSERT_EQ(3u, values->GetSize()); | |
904 ASSERT_EQ(JobOperationValue::Type_Null, values->GetValue(0).GetType()); | |
905 ASSERT_EQ(JobOperationValue::Type_String, values->GetValue(1).GetType()); | |
906 ASSERT_EQ(JobOperationValue::Type_String, values->GetValue(2).GetType()); | |
907 | |
908 ASSERT_EQ("hello", dynamic_cast<const StringOperationValue&>(values->GetValue(1)).GetContent()); | |
909 ASSERT_EQ("world", dynamic_cast<const StringOperationValue&>(values->GetValue(2)).GetContent()); | |
910 } | |
911 } | |
912 | |
913 | |
914 TEST(JobsSerialization, GenericValues) | |
915 { | |
916 GenericJobUnserializer unserializer; | |
917 Json::Value s; | |
918 | |
919 { | |
920 NullOperationValue null; | |
921 | |
922 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, null)); | |
923 null.Serialize(s); | |
924 } | |
925 | |
926 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
927 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
928 | |
929 std::unique_ptr<JobOperationValue> value; | |
930 value.reset(unserializer.UnserializeValue(s)); | |
931 | |
932 ASSERT_EQ(JobOperationValue::Type_Null, value->GetType()); | |
933 | |
934 { | |
935 StringOperationValue str("Hello"); | |
936 | |
937 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, str)); | |
938 str.Serialize(s); | |
939 } | |
940 | |
941 ASSERT_THROW(unserializer.UnserializeJob(s), OrthancException); | |
942 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
943 value.reset(unserializer.UnserializeValue(s)); | |
944 | |
945 ASSERT_EQ(JobOperationValue::Type_String, value->GetType()); | |
946 ASSERT_EQ("Hello", dynamic_cast<StringOperationValue&>(*value).GetContent()); | |
947 } | |
948 | |
949 | |
950 TEST(JobsSerialization, GenericJobs) | |
951 { | |
952 Json::Value s; | |
953 | |
954 // This tests SetOfInstancesJob | |
955 | |
956 { | |
957 DummyInstancesJob job; | |
958 job.SetDescription("description"); | |
959 job.AddInstance("hello"); | |
960 job.AddInstance("nope"); | |
961 job.AddInstance("world"); | |
962 job.SetPermissive(true); | |
963 ASSERT_THROW(job.Step("jobId"), OrthancException); // Not started yet | |
964 ASSERT_FALSE(job.HasTrailingStep()); | |
965 ASSERT_FALSE(job.IsTrailingStepDone()); | |
966 job.Start(); | |
967 ASSERT_EQ(JobStepCode_Continue, job.Step("jobId").GetCode()); | |
968 ASSERT_EQ(JobStepCode_Continue, job.Step("jobId").GetCode()); | |
969 | |
970 { | |
971 DummyUnserializer unserializer; | |
972 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
973 } | |
974 | |
975 ASSERT_TRUE(job.Serialize(s)); | |
976 } | |
977 | |
978 { | |
979 DummyUnserializer unserializer; | |
980 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
981 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
982 | |
983 std::unique_ptr<IJob> job; | |
984 job.reset(unserializer.UnserializeJob(s)); | |
985 | |
986 const DummyInstancesJob& tmp = dynamic_cast<const DummyInstancesJob&>(*job); | |
987 ASSERT_FALSE(tmp.IsStarted()); | |
988 ASSERT_TRUE(tmp.IsPermissive()); | |
989 ASSERT_EQ("description", tmp.GetDescription()); | |
990 ASSERT_EQ(3u, tmp.GetInstancesCount()); | |
991 ASSERT_EQ(2u, tmp.GetPosition()); | |
992 ASSERT_EQ(1u, tmp.GetFailedInstances().size()); | |
993 ASSERT_EQ("hello", tmp.GetInstance(0)); | |
994 ASSERT_EQ("nope", tmp.GetInstance(1)); | |
995 ASSERT_EQ("world", tmp.GetInstance(2)); | |
996 ASSERT_TRUE(tmp.IsFailedInstance("nope")); | |
997 } | |
998 | |
999 // SequenceOfOperationsJob | |
1000 | |
1001 { | |
1002 SequenceOfOperationsJob job; | |
1003 job.SetDescription("hello"); | |
1004 | |
1005 { | |
1006 SequenceOfOperationsJob::Lock lock(job); | |
1007 size_t a = lock.AddOperation(new LogJobOperation); | |
1008 size_t b = lock.AddOperation(new LogJobOperation); | |
1009 lock.Connect(a, b); | |
1010 | |
1011 StringOperationValue s1("hello"); | |
1012 StringOperationValue s2("world"); | |
1013 lock.AddInput(a, s1); | |
1014 lock.AddInput(a, s2); | |
1015 lock.SetTrailingOperationTimeout(300); | |
1016 } | |
1017 | |
1018 ASSERT_EQ(JobStepCode_Continue, job.Step("jobId").GetCode()); | |
1019 | |
1020 { | |
1021 GenericJobUnserializer unserializer; | |
1022 ASSERT_TRUE(CheckIdempotentSerialization(unserializer, job)); | |
1023 } | |
1024 | |
1025 ASSERT_TRUE(job.Serialize(s)); | |
1026 } | |
1027 | |
1028 { | |
1029 GenericJobUnserializer unserializer; | |
1030 ASSERT_THROW(unserializer.UnserializeValue(s), OrthancException); | |
1031 ASSERT_THROW(unserializer.UnserializeOperation(s), OrthancException); | |
1032 | |
1033 std::unique_ptr<IJob> job; | |
1034 job.reset(unserializer.UnserializeJob(s)); | |
1035 | |
1036 std::string tmp; | |
1037 dynamic_cast<SequenceOfOperationsJob&>(*job).GetDescription(tmp); | |
1038 ASSERT_EQ("hello", tmp); | |
1039 } | |
1040 } | |
1041 | |
1042 | |
1043 static bool IsSameTagValue(ParsedDicomFile& dicom1, | |
1044 ParsedDicomFile& dicom2, | |
1045 DicomTag tag) | |
1046 { | |
1047 std::string a, b; | |
1048 return (dicom1.GetTagValue(a, tag) && | |
1049 dicom2.GetTagValue(b, tag) && | |
1050 (a == b)); | |
1051 } | |
1052 | |
1053 | |
1054 | |
1055 TEST(JobsSerialization, DicomModification) | |
1056 { | |
1057 Json::Value s; | |
1058 | |
1059 ParsedDicomFile source(true); | |
1060 source.Insert(DICOM_TAG_STUDY_DESCRIPTION, "Test 1", false, ""); | |
1061 source.Insert(DICOM_TAG_SERIES_DESCRIPTION, "Test 2", false, ""); | |
1062 source.Insert(DICOM_TAG_PATIENT_NAME, "Test 3", false, ""); | |
1063 | |
1064 std::unique_ptr<ParsedDicomFile> modified(source.Clone(true)); | |
1065 | |
1066 { | |
1067 DicomModification modification; | |
1068 modification.SetLevel(ResourceType_Series); | |
1069 modification.Clear(DICOM_TAG_STUDY_DESCRIPTION); | |
1070 modification.Remove(DICOM_TAG_SERIES_DESCRIPTION); | |
1071 modification.Replace(DICOM_TAG_PATIENT_NAME, "Test 4", true); | |
1072 | |
1073 modification.Apply(*modified); | |
1074 | |
1075 s = 42; | |
1076 modification.Serialize(s); | |
1077 } | |
1078 | |
1079 { | |
1080 DicomModification modification(s); | |
1081 ASSERT_EQ(ResourceType_Series, modification.GetLevel()); | |
1082 | |
1083 std::unique_ptr<ParsedDicomFile> second(source.Clone(true)); | |
1084 modification.Apply(*second); | |
1085 | |
1086 std::string s; | |
1087 ASSERT_TRUE(second->GetTagValue(s, DICOM_TAG_STUDY_DESCRIPTION)); | |
1088 ASSERT_TRUE(s.empty()); | |
1089 ASSERT_FALSE(second->GetTagValue(s, DICOM_TAG_SERIES_DESCRIPTION)); | |
1090 ASSERT_TRUE(second->GetTagValue(s, DICOM_TAG_PATIENT_NAME)); | |
1091 ASSERT_EQ("Test 4", s); | |
1092 | |
1093 ASSERT_TRUE(IsSameTagValue(source, *modified, DICOM_TAG_STUDY_INSTANCE_UID)); | |
1094 ASSERT_TRUE(IsSameTagValue(source, *second, DICOM_TAG_STUDY_INSTANCE_UID)); | |
1095 | |
1096 ASSERT_FALSE(IsSameTagValue(source, *second, DICOM_TAG_SERIES_INSTANCE_UID)); | |
1097 ASSERT_TRUE(IsSameTagValue(*modified, *second, DICOM_TAG_SERIES_INSTANCE_UID)); | |
1098 } | |
1099 } | |
1100 | |
1101 | |
1102 TEST(JobsSerialization, Registry) | |
1103 { | |
1104 Json::Value s; | |
1105 std::string i1, i2; | |
1106 | |
1107 { | |
1108 JobsRegistry registry(10); | |
1109 registry.Submit(i1, new DummyJob(), 10); | |
1110 registry.Submit(i2, new SequenceOfOperationsJob(), 30); | |
1111 registry.Serialize(s); | |
1112 } | |
1113 | |
1114 { | |
1115 DummyUnserializer unserializer; | |
1116 JobsRegistry registry(unserializer, s, 10); | |
1117 | |
1118 Json::Value t; | |
1119 registry.Serialize(t); | |
1120 ASSERT_TRUE(CheckSameJson(s, t)); | |
1121 } | |
1122 } | |
1123 | |
1124 | |
1125 TEST(JobsSerialization, TrailingStep) | |
1126 { | |
1127 { | |
1128 Json::Value s; | |
1129 | |
1130 DummyInstancesJob job; | |
1131 ASSERT_EQ(0u, job.GetCommandsCount()); | |
1132 ASSERT_EQ(0u, job.GetInstancesCount()); | |
1133 | |
1134 job.Start(); | |
1135 ASSERT_EQ(0u, job.GetPosition()); | |
1136 ASSERT_FALSE(job.HasTrailingStep()); | |
1137 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1138 | |
1139 { | |
1140 DummyUnserializer unserializer; | |
1141 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1142 } | |
1143 | |
1144 ASSERT_EQ(JobStepCode_Success, job.Step("jobId").GetCode()); | |
1145 ASSERT_EQ(1u, job.GetPosition()); | |
1146 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1147 | |
1148 { | |
1149 DummyUnserializer unserializer; | |
1150 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1151 } | |
1152 | |
1153 ASSERT_THROW(job.Step("jobId"), OrthancException); | |
1154 } | |
1155 | |
1156 { | |
1157 Json::Value s; | |
1158 | |
1159 DummyInstancesJob job; | |
1160 job.AddInstance("hello"); | |
1161 job.AddInstance("world"); | |
1162 ASSERT_EQ(2u, job.GetCommandsCount()); | |
1163 ASSERT_EQ(2u, job.GetInstancesCount()); | |
1164 | |
1165 job.Start(); | |
1166 ASSERT_EQ(0u, job.GetPosition()); | |
1167 ASSERT_FALSE(job.HasTrailingStep()); | |
1168 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1169 | |
1170 { | |
1171 DummyUnserializer unserializer; | |
1172 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1173 } | |
1174 | |
1175 ASSERT_EQ(JobStepCode_Continue, job.Step("jobId").GetCode()); | |
1176 ASSERT_EQ(1u, job.GetPosition()); | |
1177 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1178 | |
1179 { | |
1180 DummyUnserializer unserializer; | |
1181 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1182 } | |
1183 | |
1184 ASSERT_EQ(JobStepCode_Success, job.Step("jobId").GetCode()); | |
1185 ASSERT_EQ(2u, job.GetPosition()); | |
1186 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1187 | |
1188 { | |
1189 DummyUnserializer unserializer; | |
1190 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1191 } | |
1192 | |
1193 ASSERT_THROW(job.Step("jobId"), OrthancException); | |
1194 } | |
1195 | |
1196 { | |
1197 Json::Value s; | |
1198 | |
1199 DummyInstancesJob job; | |
1200 ASSERT_EQ(0u, job.GetInstancesCount()); | |
1201 ASSERT_EQ(0u, job.GetCommandsCount()); | |
1202 job.AddTrailingStep(); | |
1203 ASSERT_EQ(0u, job.GetInstancesCount()); | |
1204 ASSERT_EQ(1u, job.GetCommandsCount()); | |
1205 | |
1206 job.Start(); // This adds the trailing step | |
1207 ASSERT_EQ(0u, job.GetPosition()); | |
1208 ASSERT_TRUE(job.HasTrailingStep()); | |
1209 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1210 | |
1211 { | |
1212 DummyUnserializer unserializer; | |
1213 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1214 } | |
1215 | |
1216 ASSERT_EQ(JobStepCode_Success, job.Step("jobId").GetCode()); | |
1217 ASSERT_EQ(1u, job.GetPosition()); | |
1218 ASSERT_TRUE(job.IsTrailingStepDone()); | |
1219 | |
1220 { | |
1221 DummyUnserializer unserializer; | |
1222 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1223 } | |
1224 | |
1225 ASSERT_THROW(job.Step("jobId"), OrthancException); | |
1226 } | |
1227 | |
1228 { | |
1229 Json::Value s; | |
1230 | |
1231 DummyInstancesJob job; | |
1232 job.AddInstance("hello"); | |
1233 ASSERT_EQ(1u, job.GetInstancesCount()); | |
1234 ASSERT_EQ(1u, job.GetCommandsCount()); | |
1235 job.AddTrailingStep(); | |
1236 ASSERT_EQ(1u, job.GetInstancesCount()); | |
1237 ASSERT_EQ(2u, job.GetCommandsCount()); | |
1238 | |
1239 job.Start(); | |
1240 ASSERT_EQ(2u, job.GetCommandsCount()); | |
1241 ASSERT_EQ(0u, job.GetPosition()); | |
1242 ASSERT_TRUE(job.HasTrailingStep()); | |
1243 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1244 | |
1245 { | |
1246 DummyUnserializer unserializer; | |
1247 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1248 } | |
1249 | |
1250 ASSERT_EQ(JobStepCode_Continue, job.Step("jobId").GetCode()); | |
1251 ASSERT_EQ(1u, job.GetPosition()); | |
1252 ASSERT_FALSE(job.IsTrailingStepDone()); | |
1253 | |
1254 { | |
1255 DummyUnserializer unserializer; | |
1256 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1257 } | |
1258 | |
1259 ASSERT_EQ(JobStepCode_Success, job.Step("jobId").GetCode()); | |
1260 ASSERT_EQ(2u, job.GetPosition()); | |
1261 ASSERT_TRUE(job.IsTrailingStepDone()); | |
1262 | |
1263 { | |
1264 DummyUnserializer unserializer; | |
1265 ASSERT_TRUE(CheckIdempotentSetOfInstances(unserializer, job)); | |
1266 } | |
1267 | |
1268 ASSERT_THROW(job.Step("jobId"), OrthancException); | |
1269 } | |
1270 } | |
1271 | |
1272 | |
1273 TEST(JobsSerialization, RemoteModalityParameters) | |
1274 { | |
1275 Json::Value s; | |
1276 | |
1277 { | |
1278 RemoteModalityParameters modality; | |
1279 ASSERT_FALSE(modality.IsAdvancedFormatNeeded()); | |
1280 modality.Serialize(s, false); | |
1281 ASSERT_EQ(Json::arrayValue, s.type()); | |
1282 } | |
1283 | |
1284 { | |
1285 RemoteModalityParameters modality(s); | |
1286 ASSERT_EQ("ORTHANC", modality.GetApplicationEntityTitle()); | |
1287 ASSERT_EQ("127.0.0.1", modality.GetHost()); | |
1288 ASSERT_EQ(104u, modality.GetPortNumber()); | |
1289 ASSERT_EQ(ModalityManufacturer_Generic, modality.GetManufacturer()); | |
1290 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Echo)); | |
1291 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Find)); | |
1292 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Get)); | |
1293 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Store)); | |
1294 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Move)); | |
1295 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_NAction)); | |
1296 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_NEventReport)); | |
1297 ASSERT_TRUE(modality.IsTranscodingAllowed()); | |
1298 } | |
1299 | |
1300 s = Json::nullValue; | |
1301 | |
1302 { | |
1303 RemoteModalityParameters modality; | |
1304 ASSERT_FALSE(modality.IsAdvancedFormatNeeded()); | |
1305 ASSERT_THROW(modality.SetPortNumber(0), OrthancException); | |
1306 ASSERT_THROW(modality.SetPortNumber(65535), OrthancException); | |
1307 modality.SetApplicationEntityTitle("HELLO"); | |
1308 modality.SetHost("world"); | |
1309 modality.SetPortNumber(45); | |
1310 modality.SetManufacturer(ModalityManufacturer_GenericNoWildcardInDates); | |
1311 modality.Serialize(s, true); | |
1312 ASSERT_EQ(Json::objectValue, s.type()); | |
1313 } | |
1314 | |
1315 { | |
1316 RemoteModalityParameters modality(s); | |
1317 ASSERT_EQ("HELLO", modality.GetApplicationEntityTitle()); | |
1318 ASSERT_EQ("world", modality.GetHost()); | |
1319 ASSERT_EQ(45u, modality.GetPortNumber()); | |
1320 ASSERT_EQ(ModalityManufacturer_GenericNoWildcardInDates, modality.GetManufacturer()); | |
1321 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Echo)); | |
1322 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Find)); | |
1323 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Get)); | |
1324 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Store)); | |
1325 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_Move)); | |
1326 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_NAction)); | |
1327 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_NEventReport)); | |
1328 ASSERT_TRUE(modality.IsTranscodingAllowed()); | |
1329 } | |
1330 | |
1331 s["Port"] = "46"; | |
1332 | |
1333 { | |
1334 RemoteModalityParameters modality(s); | |
1335 ASSERT_EQ(46u, modality.GetPortNumber()); | |
1336 } | |
1337 | |
1338 s["Port"] = -1; ASSERT_THROW(RemoteModalityParameters m(s), OrthancException); | |
1339 s["Port"] = 65535; ASSERT_THROW(RemoteModalityParameters m(s), OrthancException); | |
1340 s["Port"] = "nope"; ASSERT_THROW(RemoteModalityParameters m(s), OrthancException); | |
1341 | |
1342 std::set<DicomRequestType> operations; | |
1343 operations.insert(DicomRequestType_Echo); | |
1344 operations.insert(DicomRequestType_Find); | |
1345 operations.insert(DicomRequestType_Get); | |
1346 operations.insert(DicomRequestType_Move); | |
1347 operations.insert(DicomRequestType_Store); | |
1348 operations.insert(DicomRequestType_NAction); | |
1349 operations.insert(DicomRequestType_NEventReport); | |
1350 | |
1351 ASSERT_EQ(7u, operations.size()); | |
1352 | |
1353 for (std::set<DicomRequestType>::const_iterator | |
1354 it = operations.begin(); it != operations.end(); ++it) | |
1355 { | |
1356 { | |
1357 RemoteModalityParameters modality; | |
1358 modality.SetRequestAllowed(*it, false); | |
1359 ASSERT_TRUE(modality.IsAdvancedFormatNeeded()); | |
1360 | |
1361 modality.Serialize(s, false); | |
1362 ASSERT_EQ(Json::objectValue, s.type()); | |
1363 } | |
1364 | |
1365 { | |
1366 RemoteModalityParameters modality(s); | |
1367 | |
1368 ASSERT_FALSE(modality.IsRequestAllowed(*it)); | |
1369 | |
1370 for (std::set<DicomRequestType>::const_iterator | |
1371 it2 = operations.begin(); it2 != operations.end(); ++it2) | |
1372 { | |
1373 if (*it2 != *it) | |
1374 { | |
1375 ASSERT_TRUE(modality.IsRequestAllowed(*it2)); | |
1376 } | |
1377 } | |
1378 } | |
1379 } | |
1380 | |
1381 { | |
1382 Json::Value s; | |
1383 s["AllowStorageCommitment"] = false; | |
1384 s["AET"] = "AET"; | |
1385 s["Host"] = "host"; | |
1386 s["Port"] = "104"; | |
1387 | |
1388 RemoteModalityParameters modality(s); | |
1389 ASSERT_TRUE(modality.IsAdvancedFormatNeeded()); | |
1390 ASSERT_EQ("AET", modality.GetApplicationEntityTitle()); | |
1391 ASSERT_EQ("host", modality.GetHost()); | |
1392 ASSERT_EQ(104u, modality.GetPortNumber()); | |
1393 ASSERT_FALSE(modality.IsRequestAllowed(DicomRequestType_NAction)); | |
1394 ASSERT_FALSE(modality.IsRequestAllowed(DicomRequestType_NEventReport)); | |
1395 ASSERT_TRUE(modality.IsTranscodingAllowed()); | |
1396 } | |
1397 | |
1398 { | |
1399 Json::Value s; | |
1400 s["AllowNAction"] = false; | |
1401 s["AllowNEventReport"] = true; | |
1402 s["AET"] = "AET"; | |
1403 s["Host"] = "host"; | |
1404 s["Port"] = "104"; | |
1405 s["AllowTranscoding"] = false; | |
1406 | |
1407 RemoteModalityParameters modality(s); | |
1408 ASSERT_TRUE(modality.IsAdvancedFormatNeeded()); | |
1409 ASSERT_EQ("AET", modality.GetApplicationEntityTitle()); | |
1410 ASSERT_EQ("host", modality.GetHost()); | |
1411 ASSERT_EQ(104u, modality.GetPortNumber()); | |
1412 ASSERT_FALSE(modality.IsRequestAllowed(DicomRequestType_NAction)); | |
1413 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_NEventReport)); | |
1414 ASSERT_FALSE(modality.IsTranscodingAllowed()); | |
1415 } | |
1416 | |
1417 { | |
1418 Json::Value s; | |
1419 s["AllowNAction"] = true; | |
1420 s["AllowNEventReport"] = true; | |
1421 s["AET"] = "AET"; | |
1422 s["Host"] = "host"; | |
1423 s["Port"] = "104"; | |
1424 | |
1425 RemoteModalityParameters modality(s); | |
1426 ASSERT_FALSE(modality.IsAdvancedFormatNeeded()); | |
1427 ASSERT_EQ("AET", modality.GetApplicationEntityTitle()); | |
1428 ASSERT_EQ("host", modality.GetHost()); | |
1429 ASSERT_EQ(104u, modality.GetPortNumber()); | |
1430 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_NAction)); | |
1431 ASSERT_TRUE(modality.IsRequestAllowed(DicomRequestType_NEventReport)); | |
1432 ASSERT_TRUE(modality.IsTranscodingAllowed()); | |
1433 } | |
1434 } |