Adds new redfish unit testing for serviceroot

This type of testing can validate bmcwebs generated redfish. The ability
to validate the output of bmcweb is extremely useful because it will
guarantee correctness in certain cases.

This is an example of redfish unit testing. The long term goal is to
apply this type of testing to several other redfish responses.

To make this change many previous changes were needed
* Break serviceroot callback into the free function.
* Change ownership of the request and response objects.
* Change setCompleteRequestHandler logic

Signed-off-by: John Edward Broadbent <jebr@google.com>
Change-Id: I560cbb0309c25670cacd81c32bccae3445ccca7b
diff --git a/meson.build b/meson.build
index bdfa36e..747d5b3 100644
--- a/meson.build
+++ b/meson.build
@@ -405,7 +405,8 @@
   'redfish-core/ut/time_utils_test.cpp',
   'redfish-core/ut/stl_utils_test.cpp',
   'redfish-core/ut/hex_utils_test.cpp',
-  'http/ut/utility_test.cpp'
+  'http/ut/utility_test.cpp',
+  'redfish-core/lib/ut/service_root_test.cpp',
 ]
 
 if(get_option('tests').enabled())
diff --git a/redfish-core/lib/ut/service_root_test.cpp b/redfish-core/lib/ut/service_root_test.cpp
new file mode 100644
index 0000000..b02cfbc
--- /dev/null
+++ b/redfish-core/lib/ut/service_root_test.cpp
@@ -0,0 +1,63 @@
+#include "app.hpp"
+#include "http_request.hpp"
+#include "include/async_resp.hpp"
+#include "nlohmann/json.hpp"
+#include "redfish-core/lib/service_root.hpp"
+
+#include <boost/shared_ptr.hpp>
+
+#include <sstream>
+#include <string>
+
+#include "gmock/gmock.h"
+
+void assertServiceRootGet(crow::Response& res)
+{
+    nlohmann::json& json = res.jsonValue;
+    EXPECT_EQ(json["@odata.id"], "/redfish/v1");
+    EXPECT_EQ(json["@odata.type"], "#ServiceRoot.v1_5_0.ServiceRoot");
+
+    EXPECT_EQ(json["AccountService"]["@odata.id"],
+              "/redfish/v1/AccountService");
+    EXPECT_EQ(json["CertificateService"]["@odata.id"],
+              "/redfish/v1/CertificateService");
+    EXPECT_EQ(json["Chassis"]["@odata.id"], "/redfish/v1/Chassis");
+    EXPECT_EQ(json["EventService"]["@odata.id"], "/redfish/v1/EventService");
+    EXPECT_EQ(json["Id"], "RootService");
+    EXPECT_EQ(json["Links"]["Sessions"]["@odata.id"],
+              "/redfish/v1/SessionService/Sessions");
+    EXPECT_EQ(json["Managers"]["@odata.id"], "/redfish/v1/Managers");
+    EXPECT_EQ(json["Name"], "Root Service");
+    EXPECT_EQ(json["RedfishVersion"], "1.9.0");
+    EXPECT_EQ(json["Name"], "Root Service");
+    EXPECT_EQ(json["Registries"]["@odata.id"], "/redfish/v1/Registries");
+    EXPECT_EQ(json["SessionService"]["@odata.id"],
+              "/redfish/v1/SessionService");
+    EXPECT_EQ(json["Systems"]["@odata.id"], "/redfish/v1/Systems");
+    EXPECT_EQ(json["Tasks"]["@odata.id"], "/redfish/v1/TaskService");
+
+    EXPECT_EQ(json["TelemetryService"]["@odata.id"],
+              "/redfish/v1/TelemetryService");
+
+    EXPECT_THAT(
+        json["UUID"],
+        testing::MatchesRegex("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-"
+                              "9a-fA-F]{4}-[0-9a-fA-F]{12}"));
+
+    EXPECT_EQ(json["UpdateService"]["@odata.id"], "/redfish/v1/UpdateService");
+    EXPECT_EQ(19, json.size());
+}
+
+TEST(ServiceRootTest, ServiceRootConstructor)
+{
+
+    boost::beast::http::request<boost::beast::http::string_body> in;
+    std::error_code ec;
+    crow::Request req(in, ec);
+    const std::shared_ptr<bmcweb::AsyncResp> shareAsyncResp =
+        std::make_shared<bmcweb::AsyncResp>();
+
+    shareAsyncResp->res.setCompleteRequestHandler(assertServiceRootGet);
+
+    redfish::handleServiceRootGet(req, shareAsyncResp);
+}