Mercurial > hg > orthanc
comparison UnitTestsSources/RestApiTests.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 | 0e1b79bc4a2d |
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. |
32 | 33 |
33 #include "PrecompiledHeadersUnitTests.h" | 34 #include "PrecompiledHeadersUnitTests.h" |
34 #include "gtest/gtest.h" | 35 #include "gtest/gtest.h" |
35 | 36 |
36 #include <ctype.h> | 37 #include <ctype.h> |
38 #include <boost/lexical_cast.hpp> | |
39 #include <algorithm> | |
37 | 40 |
38 #include "../Core/ChunkedBuffer.h" | 41 #include "../Core/ChunkedBuffer.h" |
39 #include "../Core/HttpClient.h" | 42 #include "../Core/HttpClient.h" |
40 #include "../Core/Logging.h" | 43 #include "../Core/Logging.h" |
44 #include "../Core/SystemToolbox.h" | |
41 #include "../Core/RestApi/RestApi.h" | 45 #include "../Core/RestApi/RestApi.h" |
42 #include "../Core/Uuid.h" | |
43 #include "../Core/OrthancException.h" | 46 #include "../Core/OrthancException.h" |
44 #include "../Core/Compression/ZlibCompressor.h" | 47 #include "../Core/Compression/ZlibCompressor.h" |
45 #include "../Core/RestApi/RestApiHierarchy.h" | 48 #include "../Core/RestApi/RestApiHierarchy.h" |
49 #include "../Core/HttpServer/HttpContentNegociation.h" | |
46 | 50 |
47 using namespace Orthanc; | 51 using namespace Orthanc; |
48 | 52 |
49 #if !defined(UNIT_TESTS_WITH_HTTP_CONNEXIONS) | 53 #if !defined(UNIT_TESTS_WITH_HTTP_CONNEXIONS) |
50 #error "Please set UNIT_TESTS_WITH_HTTP_CONNEXIONS" | 54 #error "Please set UNIT_TESTS_WITH_HTTP_CONNEXIONS" |
60 ASSERT_TRUE(c.IsVerbose()); | 64 ASSERT_TRUE(c.IsVerbose()); |
61 c.SetVerbose(false); | 65 c.SetVerbose(false); |
62 ASSERT_FALSE(c.IsVerbose()); | 66 ASSERT_FALSE(c.IsVerbose()); |
63 | 67 |
64 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 | 68 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 |
69 // The "http://www.orthanc-server.com/downloads/third-party/" does | |
70 // not automatically redirect to HTTPS, so we cas use it even if the | |
71 // OpenSSL/HTTPS support is disabled in curl | |
72 const std::string BASE = "http://www.orthanc-server.com/downloads/third-party/"; | |
73 | |
65 Json::Value v; | 74 Json::Value v; |
66 c.SetUrl("http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/Configuration.json"); | 75 c.SetUrl(BASE + "Product.json"); |
76 | |
67 c.Apply(v); | 77 c.Apply(v); |
68 ASSERT_TRUE(v.isMember("StorageDirectory")); | 78 ASSERT_TRUE(v.type() == Json::objectValue); |
79 ASSERT_TRUE(v.isMember("Description")); | |
69 #endif | 80 #endif |
70 } | 81 } |
71 | 82 |
72 | 83 |
73 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_SSL_ENABLED == 1 | 84 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_ENABLE_SSL == 1 |
74 | 85 |
75 /** | 86 /** |
76 The HTTPS CA certificates for BitBucket were extracted as follows: | 87 The HTTPS CA certificates for BitBucket were extracted as follows: |
77 | 88 |
78 (1) We retrieve the certification chain of BitBucket: | 89 (1) We retrieve the certification chain of BitBucket: |
95 | 106 |
96 #include "BitbucketCACertificates.h" | 107 #include "BitbucketCACertificates.h" |
97 | 108 |
98 TEST(HttpClient, Ssl) | 109 TEST(HttpClient, Ssl) |
99 { | 110 { |
100 Toolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert"); | 111 SystemToolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert"); |
101 | 112 |
102 /*{ | 113 /*{ |
103 std::string s; | 114 std::string s; |
104 Toolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt"); | 115 SystemToolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt"); |
105 Toolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert"); | 116 SystemToolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert"); |
106 }*/ | 117 }*/ |
107 | 118 |
108 HttpClient c; | 119 HttpClient c; |
109 c.SetHttpsVerifyPeers(true); | 120 c.SetHttpsVerifyPeers(true); |
110 c.SetHttpsCACertificates("UnitTestsResults/bitbucket.cert"); | 121 c.SetHttpsCACertificates("UnitTestsResults/bitbucket.cert"); |
275 virtual bool Visit(const RestApiHierarchy::Resource& resource, | 286 virtual bool Visit(const RestApiHierarchy::Resource& resource, |
276 const UriComponents& uri, | 287 const UriComponents& uri, |
277 const IHttpHandler::Arguments& components, | 288 const IHttpHandler::Arguments& components, |
278 const UriComponents& trailing) | 289 const UriComponents& trailing) |
279 { | 290 { |
280 return resource.Handle(*reinterpret_cast<RestApiGetCall*>(NULL)); | 291 return resource.Handle(*(RestApiGetCall*) NULL); |
281 } | 292 } |
282 }; | 293 }; |
283 } | 294 } |
284 | 295 |
285 | 296 |
333 ASSERT_FALSE(HandleGet(root, "/hello/b/test3/test")); | 344 ASSERT_FALSE(HandleGet(root, "/hello/b/test3/test")); |
334 ASSERT_EQ(testValue, 3); | 345 ASSERT_EQ(testValue, 3); |
335 ASSERT_TRUE(HandleGet(root, "/hello2/a/b")); | 346 ASSERT_TRUE(HandleGet(root, "/hello2/a/b")); |
336 ASSERT_EQ(testValue, 4); | 347 ASSERT_EQ(testValue, 4); |
337 } | 348 } |
349 | |
350 | |
351 | |
352 | |
353 | |
354 namespace | |
355 { | |
356 class AcceptHandler : public Orthanc::HttpContentNegociation::IHandler | |
357 { | |
358 private: | |
359 std::string type_; | |
360 std::string subtype_; | |
361 | |
362 public: | |
363 AcceptHandler() | |
364 { | |
365 Reset(); | |
366 } | |
367 | |
368 void Reset() | |
369 { | |
370 Handle("nope", "nope"); | |
371 } | |
372 | |
373 const std::string& GetType() const | |
374 { | |
375 return type_; | |
376 } | |
377 | |
378 const std::string& GetSubType() const | |
379 { | |
380 return subtype_; | |
381 } | |
382 | |
383 virtual void Handle(const std::string& type, | |
384 const std::string& subtype) | |
385 { | |
386 type_ = type; | |
387 subtype_ = subtype; | |
388 } | |
389 }; | |
390 } | |
391 | |
392 | |
393 TEST(RestApi, HttpContentNegociation) | |
394 { | |
395 // Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1 | |
396 | |
397 AcceptHandler h; | |
398 | |
399 { | |
400 Orthanc::HttpContentNegociation d; | |
401 d.Register("audio/mp3", h); | |
402 d.Register("audio/basic", h); | |
403 | |
404 ASSERT_TRUE(d.Apply("audio/*; q=0.2, audio/basic")); | |
405 ASSERT_EQ("audio", h.GetType()); | |
406 ASSERT_EQ("basic", h.GetSubType()); | |
407 | |
408 ASSERT_TRUE(d.Apply("audio/*; q=0.2, audio/nope")); | |
409 ASSERT_EQ("audio", h.GetType()); | |
410 ASSERT_EQ("mp3", h.GetSubType()); | |
411 | |
412 ASSERT_FALSE(d.Apply("application/*; q=0.2, application/pdf")); | |
413 | |
414 ASSERT_TRUE(d.Apply("*/*; application/*; q=0.2, application/pdf")); | |
415 ASSERT_EQ("audio", h.GetType()); | |
416 } | |
417 | |
418 // "This would be interpreted as "text/html and text/x-c are the | |
419 // preferred media types, but if they do not exist, then send the | |
420 // text/x-dvi entity, and if that does not exist, send the | |
421 // text/plain entity."" | |
422 const std::string T1 = "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"; | |
423 | |
424 { | |
425 Orthanc::HttpContentNegociation d; | |
426 d.Register("text/plain", h); | |
427 d.Register("text/html", h); | |
428 d.Register("text/x-dvi", h); | |
429 ASSERT_TRUE(d.Apply(T1)); | |
430 ASSERT_EQ("text", h.GetType()); | |
431 ASSERT_EQ("html", h.GetSubType()); | |
432 } | |
433 | |
434 { | |
435 Orthanc::HttpContentNegociation d; | |
436 d.Register("text/plain", h); | |
437 d.Register("text/x-dvi", h); | |
438 d.Register("text/x-c", h); | |
439 ASSERT_TRUE(d.Apply(T1)); | |
440 ASSERT_EQ("text", h.GetType()); | |
441 ASSERT_EQ("x-c", h.GetSubType()); | |
442 } | |
443 | |
444 { | |
445 Orthanc::HttpContentNegociation d; | |
446 d.Register("text/plain", h); | |
447 d.Register("text/x-dvi", h); | |
448 d.Register("text/x-c", h); | |
449 d.Register("text/html", h); | |
450 ASSERT_TRUE(d.Apply(T1)); | |
451 ASSERT_EQ("text", h.GetType()); | |
452 ASSERT_TRUE(h.GetSubType() == "x-c" || h.GetSubType() == "html"); | |
453 } | |
454 | |
455 { | |
456 Orthanc::HttpContentNegociation d; | |
457 d.Register("text/plain", h); | |
458 d.Register("text/x-dvi", h); | |
459 ASSERT_TRUE(d.Apply(T1)); | |
460 ASSERT_EQ("text", h.GetType()); | |
461 ASSERT_EQ("x-dvi", h.GetSubType()); | |
462 } | |
463 | |
464 { | |
465 Orthanc::HttpContentNegociation d; | |
466 d.Register("text/plain", h); | |
467 ASSERT_TRUE(d.Apply(T1)); | |
468 ASSERT_EQ("text", h.GetType()); | |
469 ASSERT_EQ("plain", h.GetSubType()); | |
470 } | |
471 } | |
472 | |
473 | |
474 TEST(WebServiceParameters, Serialization) | |
475 { | |
476 { | |
477 Json::Value v = Json::arrayValue; | |
478 v.append("http://localhost:8042/"); | |
479 | |
480 WebServiceParameters p(v); | |
481 ASSERT_FALSE(p.IsAdvancedFormatNeeded()); | |
482 | |
483 Json::Value v2; | |
484 p.Serialize(v2, false, true); | |
485 ASSERT_EQ(v, v2); | |
486 | |
487 WebServiceParameters p2(v2); | |
488 ASSERT_EQ("http://localhost:8042/", p2.GetUrl()); | |
489 ASSERT_TRUE(p2.GetUsername().empty()); | |
490 ASSERT_TRUE(p2.GetPassword().empty()); | |
491 ASSERT_TRUE(p2.GetCertificateFile().empty()); | |
492 ASSERT_TRUE(p2.GetCertificateKeyFile().empty()); | |
493 ASSERT_TRUE(p2.GetCertificateKeyPassword().empty()); | |
494 ASSERT_FALSE(p2.IsPkcs11Enabled()); | |
495 } | |
496 | |
497 { | |
498 Json::Value v = Json::arrayValue; | |
499 v.append("http://localhost:8042/"); | |
500 v.append("user"); | |
501 v.append("pass"); | |
502 | |
503 WebServiceParameters p(v); | |
504 ASSERT_FALSE(p.IsAdvancedFormatNeeded()); | |
505 ASSERT_EQ("http://localhost:8042/", p.GetUrl()); | |
506 ASSERT_EQ("user", p.GetUsername()); | |
507 ASSERT_EQ("pass", p.GetPassword()); | |
508 ASSERT_TRUE(p.GetCertificateFile().empty()); | |
509 ASSERT_TRUE(p.GetCertificateKeyFile().empty()); | |
510 ASSERT_TRUE(p.GetCertificateKeyPassword().empty()); | |
511 ASSERT_FALSE(p.IsPkcs11Enabled()); | |
512 | |
513 Json::Value v2; | |
514 p.Serialize(v2, false, true); | |
515 ASSERT_EQ(v, v2); | |
516 | |
517 p.Serialize(v2, false, false /* no password */); | |
518 WebServiceParameters p2(v2); | |
519 ASSERT_EQ(Json::arrayValue, v2.type()); | |
520 ASSERT_EQ(3u, v2.size()); | |
521 ASSERT_EQ("http://localhost:8042/", v2[0u].asString()); | |
522 ASSERT_EQ("user", v2[1u].asString()); | |
523 ASSERT_TRUE(v2[2u].asString().empty()); | |
524 } | |
525 | |
526 { | |
527 Json::Value v = Json::arrayValue; | |
528 v.append("http://localhost:8042/"); | |
529 | |
530 WebServiceParameters p(v); | |
531 ASSERT_FALSE(p.IsAdvancedFormatNeeded()); | |
532 p.SetPkcs11Enabled(true); | |
533 ASSERT_TRUE(p.IsAdvancedFormatNeeded()); | |
534 | |
535 Json::Value v2; | |
536 p.Serialize(v2, false, true); | |
537 WebServiceParameters p2(v2); | |
538 | |
539 ASSERT_EQ(Json::objectValue, v2.type()); | |
540 ASSERT_EQ(3u, v2.size()); | |
541 ASSERT_EQ("http://localhost:8042/", v2["Url"].asString()); | |
542 ASSERT_TRUE(v2["Pkcs11"].asBool()); | |
543 ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type()); | |
544 ASSERT_EQ(0u, v2["HttpHeaders"].size()); | |
545 } | |
546 | |
547 { | |
548 Json::Value v = Json::arrayValue; | |
549 v.append("http://localhost:8042/"); | |
550 | |
551 WebServiceParameters p(v); | |
552 ASSERT_FALSE(p.IsAdvancedFormatNeeded()); | |
553 p.SetClientCertificate("a", "b", "c"); | |
554 ASSERT_TRUE(p.IsAdvancedFormatNeeded()); | |
555 | |
556 Json::Value v2; | |
557 p.Serialize(v2, false, true); | |
558 WebServiceParameters p2(v2); | |
559 | |
560 ASSERT_EQ(Json::objectValue, v2.type()); | |
561 ASSERT_EQ(6u, v2.size()); | |
562 ASSERT_EQ("http://localhost:8042/", v2["Url"].asString()); | |
563 ASSERT_EQ("a", v2["CertificateFile"].asString()); | |
564 ASSERT_EQ("b", v2["CertificateKeyFile"].asString()); | |
565 ASSERT_EQ("c", v2["CertificateKeyPassword"].asString()); | |
566 ASSERT_FALSE(v2["Pkcs11"].asBool()); | |
567 ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type()); | |
568 ASSERT_EQ(0u, v2["HttpHeaders"].size()); | |
569 } | |
570 | |
571 { | |
572 Json::Value v = Json::arrayValue; | |
573 v.append("http://localhost:8042/"); | |
574 | |
575 WebServiceParameters p(v); | |
576 ASSERT_FALSE(p.IsAdvancedFormatNeeded()); | |
577 p.AddHttpHeader("a", "b"); | |
578 p.AddHttpHeader("c", "d"); | |
579 ASSERT_TRUE(p.IsAdvancedFormatNeeded()); | |
580 | |
581 Json::Value v2; | |
582 p.Serialize(v2, false, true); | |
583 WebServiceParameters p2(v2); | |
584 | |
585 ASSERT_EQ(Json::objectValue, v2.type()); | |
586 ASSERT_EQ(3u, v2.size()); | |
587 ASSERT_EQ("http://localhost:8042/", v2["Url"].asString()); | |
588 ASSERT_FALSE(v2["Pkcs11"].asBool()); | |
589 ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type()); | |
590 ASSERT_EQ(2u, v2["HttpHeaders"].size()); | |
591 ASSERT_EQ("b", v2["HttpHeaders"]["a"].asString()); | |
592 ASSERT_EQ("d", v2["HttpHeaders"]["c"].asString()); | |
593 | |
594 std::set<std::string> a; | |
595 p2.ListHttpHeaders(a); | |
596 ASSERT_EQ(2u, a.size()); | |
597 ASSERT_TRUE(a.find("a") != a.end()); | |
598 ASSERT_TRUE(a.find("c") != a.end()); | |
599 | |
600 std::string s; | |
601 ASSERT_TRUE(p2.LookupHttpHeader(s, "a")); ASSERT_EQ("b", s); | |
602 ASSERT_TRUE(p2.LookupHttpHeader(s, "c")); ASSERT_EQ("d", s); | |
603 ASSERT_FALSE(p2.LookupHttpHeader(s, "nope")); | |
604 } | |
605 } | |
606 | |
607 | |
608 TEST(WebServiceParameters, UserProperties) | |
609 { | |
610 Json::Value v = Json::nullValue; | |
611 | |
612 { | |
613 WebServiceParameters p; | |
614 p.SetUrl("http://localhost:8042/"); | |
615 ASSERT_FALSE(p.IsAdvancedFormatNeeded()); | |
616 | |
617 ASSERT_THROW(p.AddUserProperty("Url", "nope"), OrthancException); | |
618 p.AddUserProperty("Hello", "world"); | |
619 p.AddUserProperty("a", "b"); | |
620 ASSERT_TRUE(p.IsAdvancedFormatNeeded()); | |
621 | |
622 p.Serialize(v, false, true); | |
623 | |
624 p.ClearUserProperties(); | |
625 ASSERT_FALSE(p.IsAdvancedFormatNeeded()); | |
626 } | |
627 | |
628 { | |
629 WebServiceParameters p(v); | |
630 ASSERT_TRUE(p.IsAdvancedFormatNeeded()); | |
631 ASSERT_TRUE(p.GetHttpHeaders().empty()); | |
632 | |
633 std::set<std::string> tmp; | |
634 p.ListUserProperties(tmp); | |
635 ASSERT_EQ(2u, tmp.size()); | |
636 ASSERT_TRUE(tmp.find("a") != tmp.end()); | |
637 ASSERT_TRUE(tmp.find("Hello") != tmp.end()); | |
638 ASSERT_TRUE(tmp.find("hello") == tmp.end()); | |
639 | |
640 std::string s; | |
641 ASSERT_TRUE(p.LookupUserProperty(s, "a")); ASSERT_TRUE(s == "b"); | |
642 ASSERT_TRUE(p.LookupUserProperty(s, "Hello")); ASSERT_TRUE(s == "world"); | |
643 ASSERT_FALSE(p.LookupUserProperty(s, "hello")); | |
644 } | |
645 } |