diff 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
line wrap: on
line diff
--- a/UnitTestsSources/RestApiTests.cpp	Thu Oct 29 11:25:45 2015 +0100
+++ b/UnitTestsSources/RestApiTests.cpp	Fri Oct 12 15:18:10 2018 +0200
@@ -1,7 +1,8 @@
 /**
  * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
  * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2018 Osimis S.A., Belgium
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -34,15 +35,18 @@
 #include "gtest/gtest.h"
 
 #include <ctype.h>
+#include <boost/lexical_cast.hpp>
+#include <algorithm>
 
 #include "../Core/ChunkedBuffer.h"
 #include "../Core/HttpClient.h"
 #include "../Core/Logging.h"
+#include "../Core/SystemToolbox.h"
 #include "../Core/RestApi/RestApi.h"
-#include "../Core/Uuid.h"
 #include "../Core/OrthancException.h"
 #include "../Core/Compression/ZlibCompressor.h"
 #include "../Core/RestApi/RestApiHierarchy.h"
+#include "../Core/HttpServer/HttpContentNegociation.h"
 
 using namespace Orthanc;
 
@@ -62,15 +66,22 @@
   ASSERT_FALSE(c.IsVerbose());
 
 #if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1
+  // The "http://www.orthanc-server.com/downloads/third-party/" does
+  // not automatically redirect to HTTPS, so we cas use it even if the
+  // OpenSSL/HTTPS support is disabled in curl
+  const std::string BASE = "http://www.orthanc-server.com/downloads/third-party/";
+
   Json::Value v;
-  c.SetUrl("http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/Configuration.json");
+  c.SetUrl(BASE + "Product.json");
+
   c.Apply(v);
-  ASSERT_TRUE(v.isMember("StorageDirectory"));
+  ASSERT_TRUE(v.type() == Json::objectValue);
+  ASSERT_TRUE(v.isMember("Description"));
 #endif
 }
 
 
-#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_SSL_ENABLED == 1
+#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_ENABLE_SSL == 1
 
 /**
    The HTTPS CA certificates for BitBucket were extracted as follows:
@@ -97,12 +108,12 @@
 
 TEST(HttpClient, Ssl)
 {
-  Toolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert");
+  SystemToolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert");
 
   /*{
     std::string s;
-    Toolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt");
-    Toolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert");
+    SystemToolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt");
+    SystemToolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert");
     }*/
 
   HttpClient c;
@@ -277,7 +288,7 @@
                        const IHttpHandler::Arguments& components,
                        const UriComponents& trailing)
     {
-      return resource.Handle(*reinterpret_cast<RestApiGetCall*>(NULL));
+      return resource.Handle(*(RestApiGetCall*) NULL);
     }
   };
 }
@@ -335,3 +346,300 @@
   ASSERT_TRUE(HandleGet(root, "/hello2/a/b"));
   ASSERT_EQ(testValue, 4);
 }
+
+
+
+
+
+namespace
+{
+  class AcceptHandler : public Orthanc::HttpContentNegociation::IHandler
+  {
+  private:
+    std::string type_;
+    std::string subtype_;
+
+  public:
+    AcceptHandler()
+    {
+      Reset();
+    }
+
+    void Reset()
+    {
+      Handle("nope", "nope");
+    }
+
+    const std::string& GetType() const
+    {
+      return type_;
+    }
+
+    const std::string& GetSubType() const
+    {
+      return subtype_;
+    }
+
+    virtual void Handle(const std::string& type,
+                        const std::string& subtype)
+    {
+      type_ = type;
+      subtype_ = subtype;
+    }
+  };
+}
+
+
+TEST(RestApi, HttpContentNegociation)
+{
+  // Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
+
+  AcceptHandler h;
+
+  {
+    Orthanc::HttpContentNegociation d;
+    d.Register("audio/mp3", h);
+    d.Register("audio/basic", h);
+
+    ASSERT_TRUE(d.Apply("audio/*; q=0.2, audio/basic"));
+    ASSERT_EQ("audio", h.GetType());
+    ASSERT_EQ("basic", h.GetSubType());
+
+    ASSERT_TRUE(d.Apply("audio/*; q=0.2, audio/nope"));
+    ASSERT_EQ("audio", h.GetType());
+    ASSERT_EQ("mp3", h.GetSubType());
+    
+    ASSERT_FALSE(d.Apply("application/*; q=0.2, application/pdf"));
+    
+    ASSERT_TRUE(d.Apply("*/*; application/*; q=0.2, application/pdf"));
+    ASSERT_EQ("audio", h.GetType());
+  }
+
+  // "This would be interpreted as "text/html and text/x-c are the
+  // preferred media types, but if they do not exist, then send the
+  // text/x-dvi entity, and if that does not exist, send the
+  // text/plain entity.""
+  const std::string T1 = "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c";
+  
+  {
+    Orthanc::HttpContentNegociation d;
+    d.Register("text/plain", h);
+    d.Register("text/html", h);
+    d.Register("text/x-dvi", h);
+    ASSERT_TRUE(d.Apply(T1));
+    ASSERT_EQ("text", h.GetType());
+    ASSERT_EQ("html", h.GetSubType());
+  }
+  
+  {
+    Orthanc::HttpContentNegociation d;
+    d.Register("text/plain", h);
+    d.Register("text/x-dvi", h);
+    d.Register("text/x-c", h);
+    ASSERT_TRUE(d.Apply(T1));
+    ASSERT_EQ("text", h.GetType());
+    ASSERT_EQ("x-c", h.GetSubType());
+  }
+  
+  {
+    Orthanc::HttpContentNegociation d;
+    d.Register("text/plain", h);
+    d.Register("text/x-dvi", h);
+    d.Register("text/x-c", h);
+    d.Register("text/html", h);
+    ASSERT_TRUE(d.Apply(T1));
+    ASSERT_EQ("text", h.GetType());
+    ASSERT_TRUE(h.GetSubType() == "x-c" || h.GetSubType() == "html");
+  }
+  
+  {
+    Orthanc::HttpContentNegociation d;
+    d.Register("text/plain", h);
+    d.Register("text/x-dvi", h);
+    ASSERT_TRUE(d.Apply(T1));
+    ASSERT_EQ("text", h.GetType());
+    ASSERT_EQ("x-dvi", h.GetSubType());
+  }
+  
+  {
+    Orthanc::HttpContentNegociation d;
+    d.Register("text/plain", h);
+    ASSERT_TRUE(d.Apply(T1));
+    ASSERT_EQ("text", h.GetType());
+    ASSERT_EQ("plain", h.GetSubType());
+  }
+}
+
+
+TEST(WebServiceParameters, Serialization)
+{
+  {
+    Json::Value v = Json::arrayValue;
+    v.append("http://localhost:8042/");
+
+    WebServiceParameters p(v);
+    ASSERT_FALSE(p.IsAdvancedFormatNeeded());
+
+    Json::Value v2;
+    p.Serialize(v2, false, true);
+    ASSERT_EQ(v, v2);
+
+    WebServiceParameters p2(v2);
+    ASSERT_EQ("http://localhost:8042/", p2.GetUrl());
+    ASSERT_TRUE(p2.GetUsername().empty());
+    ASSERT_TRUE(p2.GetPassword().empty());
+    ASSERT_TRUE(p2.GetCertificateFile().empty());
+    ASSERT_TRUE(p2.GetCertificateKeyFile().empty());
+    ASSERT_TRUE(p2.GetCertificateKeyPassword().empty());
+    ASSERT_FALSE(p2.IsPkcs11Enabled());
+  }
+
+  {
+    Json::Value v = Json::arrayValue;
+    v.append("http://localhost:8042/");
+    v.append("user");
+    v.append("pass");
+
+    WebServiceParameters p(v);
+    ASSERT_FALSE(p.IsAdvancedFormatNeeded());
+    ASSERT_EQ("http://localhost:8042/", p.GetUrl());
+    ASSERT_EQ("user", p.GetUsername());
+    ASSERT_EQ("pass", p.GetPassword());
+    ASSERT_TRUE(p.GetCertificateFile().empty());
+    ASSERT_TRUE(p.GetCertificateKeyFile().empty());
+    ASSERT_TRUE(p.GetCertificateKeyPassword().empty());
+    ASSERT_FALSE(p.IsPkcs11Enabled());
+
+    Json::Value v2;
+    p.Serialize(v2, false, true);
+    ASSERT_EQ(v, v2);
+
+    p.Serialize(v2, false, false /* no password */);
+    WebServiceParameters p2(v2);
+    ASSERT_EQ(Json::arrayValue, v2.type());
+    ASSERT_EQ(3u, v2.size());
+    ASSERT_EQ("http://localhost:8042/", v2[0u].asString());
+    ASSERT_EQ("user", v2[1u].asString());
+    ASSERT_TRUE(v2[2u].asString().empty());
+  }
+
+  {
+    Json::Value v = Json::arrayValue;
+    v.append("http://localhost:8042/");
+
+    WebServiceParameters p(v);
+    ASSERT_FALSE(p.IsAdvancedFormatNeeded());
+    p.SetPkcs11Enabled(true);
+    ASSERT_TRUE(p.IsAdvancedFormatNeeded());
+
+    Json::Value v2;
+    p.Serialize(v2, false, true);
+    WebServiceParameters p2(v2);
+
+    ASSERT_EQ(Json::objectValue, v2.type());
+    ASSERT_EQ(3u, v2.size());
+    ASSERT_EQ("http://localhost:8042/", v2["Url"].asString());
+    ASSERT_TRUE(v2["Pkcs11"].asBool());
+    ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type());
+    ASSERT_EQ(0u, v2["HttpHeaders"].size());
+  }
+
+  {
+    Json::Value v = Json::arrayValue;
+    v.append("http://localhost:8042/");
+
+    WebServiceParameters p(v);
+    ASSERT_FALSE(p.IsAdvancedFormatNeeded());
+    p.SetClientCertificate("a", "b", "c");
+    ASSERT_TRUE(p.IsAdvancedFormatNeeded());
+
+    Json::Value v2;
+    p.Serialize(v2, false, true);
+    WebServiceParameters p2(v2);
+
+    ASSERT_EQ(Json::objectValue, v2.type());
+    ASSERT_EQ(6u, v2.size());
+    ASSERT_EQ("http://localhost:8042/", v2["Url"].asString());
+    ASSERT_EQ("a", v2["CertificateFile"].asString());
+    ASSERT_EQ("b", v2["CertificateKeyFile"].asString());
+    ASSERT_EQ("c", v2["CertificateKeyPassword"].asString());
+    ASSERT_FALSE(v2["Pkcs11"].asBool());
+    ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type());
+    ASSERT_EQ(0u, v2["HttpHeaders"].size());
+  }
+
+  {
+    Json::Value v = Json::arrayValue;
+    v.append("http://localhost:8042/");
+
+    WebServiceParameters p(v);
+    ASSERT_FALSE(p.IsAdvancedFormatNeeded());
+    p.AddHttpHeader("a", "b");
+    p.AddHttpHeader("c", "d");
+    ASSERT_TRUE(p.IsAdvancedFormatNeeded());
+
+    Json::Value v2;
+    p.Serialize(v2, false, true);
+    WebServiceParameters p2(v2);
+
+    ASSERT_EQ(Json::objectValue, v2.type());
+    ASSERT_EQ(3u, v2.size());
+    ASSERT_EQ("http://localhost:8042/", v2["Url"].asString());
+    ASSERT_FALSE(v2["Pkcs11"].asBool());
+    ASSERT_EQ(Json::objectValue, v2["HttpHeaders"].type());
+    ASSERT_EQ(2u, v2["HttpHeaders"].size());
+    ASSERT_EQ("b", v2["HttpHeaders"]["a"].asString());
+    ASSERT_EQ("d", v2["HttpHeaders"]["c"].asString());
+
+    std::set<std::string> a;
+    p2.ListHttpHeaders(a);
+    ASSERT_EQ(2u, a.size());
+    ASSERT_TRUE(a.find("a") != a.end());
+    ASSERT_TRUE(a.find("c") != a.end());
+
+    std::string s;
+    ASSERT_TRUE(p2.LookupHttpHeader(s, "a")); ASSERT_EQ("b", s);
+    ASSERT_TRUE(p2.LookupHttpHeader(s, "c")); ASSERT_EQ("d", s);
+    ASSERT_FALSE(p2.LookupHttpHeader(s, "nope"));
+  }
+}
+
+
+TEST(WebServiceParameters, UserProperties)
+{
+  Json::Value v = Json::nullValue;
+
+  {
+    WebServiceParameters p;
+    p.SetUrl("http://localhost:8042/");
+    ASSERT_FALSE(p.IsAdvancedFormatNeeded());
+
+    ASSERT_THROW(p.AddUserProperty("Url", "nope"), OrthancException);
+    p.AddUserProperty("Hello", "world");
+    p.AddUserProperty("a", "b");
+    ASSERT_TRUE(p.IsAdvancedFormatNeeded());
+
+    p.Serialize(v, false, true);
+
+    p.ClearUserProperties();
+    ASSERT_FALSE(p.IsAdvancedFormatNeeded());
+  }
+
+  {
+    WebServiceParameters p(v);
+    ASSERT_TRUE(p.IsAdvancedFormatNeeded());
+    ASSERT_TRUE(p.GetHttpHeaders().empty());
+
+    std::set<std::string> tmp;
+    p.ListUserProperties(tmp);
+    ASSERT_EQ(2u, tmp.size());
+    ASSERT_TRUE(tmp.find("a")     != tmp.end());
+    ASSERT_TRUE(tmp.find("Hello") != tmp.end());
+    ASSERT_TRUE(tmp.find("hello") == tmp.end());
+
+    std::string s;
+    ASSERT_TRUE(p.LookupUserProperty(s, "a"));      ASSERT_TRUE(s == "b");
+    ASSERT_TRUE(p.LookupUserProperty(s, "Hello"));  ASSERT_TRUE(s == "world");
+    ASSERT_FALSE(p.LookupUserProperty(s, "hello"));
+  }
+}