// 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 <fuchsia/boot/cpp/fidl.h>
#include <fuchsia/camera2/cpp/fidl.h>
#include <fuchsia/device/cpp/fidl.h>
#include <fuchsia/diagnostics/cpp/fidl.h>
#include <fuchsia/hardware/pty/cpp/fidl.h>
#include <fuchsia/kernel/cpp/fidl.h>
#include <fuchsia/media/cpp/fidl.h>
#include <fuchsia/net/cpp/fidl.h>
#include <fuchsia/posix/socket/cpp/fidl.h>
#include <fuchsia/scheduler/cpp/fidl.h>
#include <fuchsia/sys/internal/cpp/fidl.h>
#include <fuchsia/sys/test/cpp/fidl.h>
#include <fuchsia/sysinfo/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>
#include <fuchsia/time/cpp/fidl.h>
#include <fuchsia/tracing/kernel/cpp/fidl.h>
#include <fuchsia/tracing/provider/cpp/fidl.h>
#include <fuchsia/vulkan/loader/cpp/fidl.h>

#include <filesystem>
#include <unordered_set>

#include "src/lib/cmx/cmx.h"
#include "src/lib/fxl/strings/substitute.h"

namespace run {
namespace {

using fxl::Substitute;

constexpr char kInjectedServices[] = "injected-services";
constexpr char kSystemServices[] = "system-services";

// Services below were reported by their owners to be impractical to fake in a test environment
// because they depend on devices. Appmgr's test support does not offer the ability to fake the
// device namespace.
//
// Component Manager is able to route and fake devices and early boot capabilities.
//
// At this time the body of tests largely depends on appmgr, so we maintain this list as a necessary
// compromise.
//
// Please add items to this list only if you believe that no other pragmatic alternative is
// currently present.
//
// Please document the rationale for each entry added.  See also:
// docs/concepts/testing/test_component.md
const std::unordered_set<std::string> kAllowedSystemServices = {
    fuchsia::boot::FactoryItems::Name_,
    fuchsia::boot::Items::Name_,
    fuchsia::boot::ReadOnlyLog::Name_,
    fuchsia::boot::RootResource::Name_,
    fuchsia::boot::WriteOnlyLog::Name_,
    fuchsia::camera2::Manager::Name_,
    fuchsia::device::NameProvider::Name_,
    fuchsia::diagnostics::ArchiveAccessor::Name_,
    fuchsia::hardware::pty::Device::Name_,
    fuchsia::kernel::Counter::Name_,
    fuchsia::kernel::HypervisorResource::Name_,
    fuchsia::kernel::IoportResource::Name_,
    fuchsia::kernel::IrqResource::Name_,
    fuchsia::kernel::MmioResource::Name_,
    fuchsia::kernel::RootJob::Name_,
    fuchsia::kernel::RootJobForInspect::Name_,
    fuchsia::kernel::SmcResource::Name_,
    fuchsia::kernel::Stats::Name_,
    fuchsia::kernel::VmexResource::Name_,
    fuchsia::media::Audio::Name_,
    fuchsia::media::AudioCore::Name_,
    fuchsia::media::ProfileProvider::Name_,
    fuchsia::scheduler::ProfileProvider::Name_,
    fuchsia::sys::internal::CrashIntrospect::Name_,
    fuchsia::sys::test::CacheControl::Name_,
    fuchsia::sysinfo::SysInfo::Name_,
    fuchsia::sysmem::Allocator::Name_,
    fuchsia::time::Utc::Name_,
    fuchsia::tracing::provider::Registry::Name_,
    fuchsia::tracing::kernel::Controller::Name_,
    fuchsia::tracing::kernel::Reader::Name_,
    fuchsia::ui::policy::Presenter::Name_,
    fuchsia::ui::scenic::Scenic::Name_,
    fuchsia::vulkan::loader::Loader::Name_,
};

// These tests do not run in continuous integration because they make real network requests. Do not
// add to this list under any circumstances. If your tests require real network access, consider
// writing them as end-to-end tests. See docs/development/testing/create_a_new_end_to_end_test.md.
//
// TODO(fxbug.dev/57076): migrate these tests and remove this list.
const std::unordered_set<std::string> kNetworkUsingTestsThatShouldBeE2E = {
    "aml_widevine_test.cmx",
    "cdm_app_test",
    "cobalt_testapp_for_prober_do_not_run_manually.cmx",
    "playready_cdm_test.cmx",
};

const std::unordered_set<std::string> kRealNetworkServices = {
    fuchsia::net::NameLookup::Name_,
    fuchsia::posix::socket::Provider::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();
      launch_info.arguments.emplace();
      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::ParseFromString(const std::string& cmx_data, const std::string& filename) {
  component::CmxMetadata cmx;
  cmx.ParseFromString(cmx_data, filename, &json_parser_);
  if (json_parser_.HasError()) {
    return false;
  }
  auto& fuchsia_test = cmx.GetFacet(kFuchsiaTest);
  if (!fuchsia_test.IsNull()) {
    null_ = false;
    if (!fuchsia_test.IsObject()) {
      json_parser_.ReportError(Substitute("'$0' in 'facets' should be an object.", kFuchsiaTest));
      return false;
    }
    auto system_services = fuchsia_test.FindMember(kSystemServices);
    if (system_services != fuchsia_test.MemberEnd()) {
      if (!system_services->value.IsArray()) {
        json_parser_.ReportError(
            Substitute("'$0' in '$1' should be a string array.", kSystemServices, kFuchsiaTest));
      } else {
        for (const rapidjson::Value& val : system_services->value.GetArray()) {
          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) {
            if ((kRealNetworkServices.count(service) == 0 ||
                 kNetworkUsingTestsThatShouldBeE2E.count(
                     std::filesystem::path(filename).filename()) == 0)) {
              json_parser_.ReportError(
                  fxl::Substitute("'$0' cannot contain '$1'.", kSystemServices, service));
              return false;
            }
          }
          system_services_.push_back(service);
        };
      }
    }
    auto services = fuchsia_test.FindMember(kInjectedServices);
    if (services != fuchsia_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
