| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "garnet/bin/run_test_component/test_metadata.h" |
| |
| #include <unordered_set> |
| |
| #include "garnet/lib/cmx/cmx.h" |
| #include "lib/fxl/strings/substitute.h" |
| |
| #include <fuchsia/net/cpp/fidl.h> |
| #include <fuchsia/net/stack/cpp/fidl.h> |
| #include <fuchsia/netstack/cpp/fidl.h> |
| |
| namespace run { |
| namespace { |
| |
| using fxl::Substitute; |
| |
| constexpr char kInjectedServices[] = "injected-services"; |
| constexpr char kSystemServices[] = "system-services"; |
| |
| const std::unordered_set<std::string> kAllowedSystemServices = { |
| fuchsia::net::Connectivity::Name_, |
| fuchsia::net::SocketProvider::Name_, |
| fuchsia::net::stack::Stack::Name_, |
| fuchsia::netstack::Netstack::Name_, |
| }; |
| } // namespace |
| |
| TestMetadata::TestMetadata() {} |
| TestMetadata::~TestMetadata() {} |
| |
| fuchsia::sys::LaunchInfo TestMetadata::GetLaunchInfo( |
| const rapidjson::Document::ValueType& value, const std::string& name) { |
| fuchsia::sys::LaunchInfo launch_info; |
| if (value.IsString()) { |
| launch_info.url = value.GetString(); |
| return launch_info; |
| } |
| |
| if (value.IsArray()) { |
| const auto& array = value.GetArray(); |
| // If the element is an array, ensure it is non-empty and all values are |
| // strings. |
| if (!array.Empty() && std::all_of(array.begin(), array.end(), |
| [](const rapidjson::Value& val) { |
| return val.IsString(); |
| })) { |
| launch_info.url = array[0].GetString(); |
| for (size_t i = 1; i < array.Size(); ++i) { |
| launch_info.arguments.push_back(array[i].GetString()); |
| } |
| return launch_info; |
| } |
| } |
| |
| json_parser_.ReportError(Substitute( |
| "'$0' must be a string or a non-empty array of strings.", name)); |
| return launch_info; |
| } |
| |
| bool TestMetadata::ParseFromFile(const std::string& cmx_file_path) { |
| component::CmxMetadata cmx; |
| cmx.ParseFromFileAt(-1, cmx_file_path, &json_parser_); |
| if (json_parser_.HasError()) { |
| return false; |
| } |
| auto& fuchisa_test = cmx.GetFacet(kFuchsiaTest); |
| if (!fuchisa_test.IsNull()) { |
| null_ = false; |
| if (!fuchisa_test.IsObject()) { |
| json_parser_.ReportError( |
| Substitute("'$0' in 'facets' should be an object.", kFuchsiaTest)); |
| return false; |
| } |
| auto allow_network_services = fuchisa_test.FindMember(kSystemServices); |
| if (allow_network_services != fuchisa_test.MemberEnd()) { |
| if (!allow_network_services->value.IsArray()) { |
| json_parser_.ReportError( |
| Substitute("'$0' in '$1' should be a string array.", |
| kSystemServices, kFuchsiaTest)); |
| } else { |
| const auto& array = allow_network_services->value.GetArray(); |
| std::all_of( |
| array.begin(), array.end(), [&](const rapidjson::Value& val) { |
| if (!val.IsString()) { |
| json_parser_.ReportError( |
| Substitute("'$0' in '$1' should be a string array.", |
| kSystemServices, kFuchsiaTest)); |
| return false; |
| } |
| std::string service = val.GetString(); |
| if (kAllowedSystemServices.count(service) == 0) { |
| json_parser_.ReportError(fxl::Substitute( |
| "'$0' cannot contain '$1'.", kSystemServices, service)); |
| return false; |
| } |
| system_services_.push_back(service); |
| return true; |
| }); |
| } |
| } |
| auto services = fuchisa_test.FindMember(kInjectedServices); |
| if (services != fuchisa_test.MemberEnd()) { |
| if (!services->value.IsObject()) { |
| json_parser_.ReportError(Substitute("'$0' in '$1' should be an object.", |
| kInjectedServices, kFuchsiaTest)); |
| return false; |
| } |
| for (auto itr = services->value.MemberBegin(); |
| itr != services->value.MemberEnd(); ++itr) { |
| if (!itr->name.IsString()) { |
| json_parser_.ReportError( |
| Substitute("'$0' in '$1' should define string service names.", |
| kInjectedServices, kFuchsiaTest)); |
| return false; |
| } |
| auto name = itr->name.GetString(); |
| auto launch_info = GetLaunchInfo(itr->value, name); |
| service_url_pair_.push_back( |
| std::make_pair(name, std::move(launch_info))); |
| } |
| } |
| } |
| return !HasError(); |
| } |
| |
| } // namespace run |