blob: 0f6ae86d34c78e02c2bdeeda1217083bc7c5ee75 [file] [log] [blame]
// Copyright 2016 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/lib/cmx/cmx.h"
#include <fcntl.h>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "lib/fxl/files/path.h"
#include "lib/fxl/files/scoped_temp_dir.h"
#include "lib/fxl/strings/substitute.h"
#include "third_party/rapidjson/rapidjson/document.h"
namespace component {
namespace {
class CmxMetadataTest : public ::testing::Test {
protected:
// ExpectFailedParse() will replace '$0' with the JSON filename, if present.
void ExpectFailedParse(const std::string& json, std::string expected_error) {
std::string error;
CmxMetadata cmx;
std::string json_basename;
EXPECT_FALSE(ParseFrom(&cmx, json, &json_basename));
EXPECT_TRUE(cmx.HasError());
EXPECT_EQ(cmx.error_str(), fxl::Substitute(expected_error, json_basename));
}
bool ParseFrom(CmxMetadata* cmx, const std::string& json,
std::string* json_basename) {
std::string json_path;
if (!tmp_dir_.NewTempFileWithData(json, &json_path)) {
return false;
}
*json_basename = files::GetBaseName(json_path);
const int dirfd = open(tmp_dir_.path().c_str(), O_RDONLY);
return cmx->ParseFromFileAt(dirfd, *json_basename);
}
bool ParseFromDeprecatedRuntime(CmxMetadata* cmx, const std::string& json,
std::string* json_basename) {
std::string json_path;
if (!tmp_dir_.NewTempFileWithData(json, &json_path)) {
return false;
}
*json_basename = files::GetBaseName(json_path);
const int dirfd = open(tmp_dir_.path().c_str(), O_RDONLY);
return cmx->ParseFromDeprecatedRuntimeFileAt(dirfd, *json_basename);
}
private:
files::ScopedTempDir tmp_dir_;
};
TEST_F(CmxMetadataTest, ParseMetadata) {
CmxMetadata cmx;
const std::string json = R"JSON({
"sandbox": {
"dev": [ "class/input" ],
"features": [ "feature_a" ],
"services": []
},
"runner": "dart_runner",
"other": "stuff"
})JSON";
std::string file_unused;
EXPECT_TRUE(ParseFrom(&cmx, json, &file_unused)) << cmx.error_str();
EXPECT_FALSE(cmx.HasError());
const auto& sandbox = cmx.sandbox_meta();
EXPECT_FALSE(sandbox.IsNull());
EXPECT_THAT(sandbox.dev(), ::testing::ElementsAre("class/input"));
EXPECT_TRUE(sandbox.HasFeature("feature_a"));
EXPECT_FALSE(sandbox.HasFeature("feature_b"));
EXPECT_FALSE(cmx.runtime_meta().IsNull());
EXPECT_EQ(cmx.runtime_meta().runner(), "dart_runner");
}
TEST_F(CmxMetadataTest, ParseEmpty) {
// No 'program' or 'runner'. Valid syntax, but empty.
rapidjson::Value sandbox;
std::string error;
const std::string json = R"JSON(
{
"sandwich": { "ingredients": [ "bacon", "lettuce", "tomato" ] },
"sandbox": { "services": [] }
}
)JSON";
CmxMetadata cmx;
std::string file_unused;
EXPECT_TRUE(ParseFrom(&cmx, json, &file_unused)) << cmx.error_str();
EXPECT_FALSE(cmx.sandbox_meta().IsNull());
EXPECT_TRUE(cmx.runtime_meta().IsNull());
EXPECT_TRUE(cmx.program_meta().IsNull());
}
TEST_F(CmxMetadataTest, ParseFromDeprecatedRuntime) {
rapidjson::Value sandbox;
std::string error;
const std::string json = R"JSON(
{ "runner": "dart_runner" }
)JSON";
CmxMetadata cmx;
std::string file_unused;
EXPECT_TRUE(ParseFromDeprecatedRuntime(&cmx, json, &file_unused))
<< cmx.error_str();
EXPECT_TRUE(cmx.sandbox_meta().IsNull());
EXPECT_FALSE(cmx.runtime_meta().IsNull());
EXPECT_EQ("dart_runner", cmx.runtime_meta().runner());
EXPECT_TRUE(cmx.program_meta().IsNull());
}
#define NO_SERVICES \
"$0: Sandbox must include either 'services' or 'deprecated-all-services'."
TEST_F(CmxMetadataTest, ParseWithErrors) {
rapidjson::Value sandbox;
std::string error;
ExpectFailedParse(R"JSON({ ,,, })JSON",
"$0:1:3: Missing a name for object member.");
ExpectFailedParse(R"JSON(3)JSON", "$0: File is not a JSON object.");
ExpectFailedParse(R"JSON({ "sandbox" : 3})JSON",
"$0: 'sandbox' is not an object.");
ExpectFailedParse(R"JSON({ "sandbox" : {"dev": "notarray"} })JSON",
"$0: 'dev' in sandbox is not an array.\n" NO_SERVICES);
ExpectFailedParse(R"JSON({ "runner" : 3 })JSON",
NO_SERVICES "\n$0: 'runner' is not a string.");
ExpectFailedParse(R"JSON({ "program" : { "binary": 3 } })JSON",
NO_SERVICES "\n$0: 'binary' in program is not a string.");
}
TEST_F(CmxMetadataTest, GetDefaultComponentCmxPath) {
EXPECT_EQ("meta/sysmgr.cmx", CmxMetadata::GetDefaultComponentCmxPath(
"file:///pkgfs/packages/sysmgr/0"));
EXPECT_EQ(
"", CmxMetadata::GetDefaultComponentCmxPath("/pkgfs/packages/sysmgr/0"));
EXPECT_EQ("", CmxMetadata::GetDefaultComponentCmxPath(
"file:///pkgfs/nothing/sysmgr/0"));
EXPECT_EQ("", CmxMetadata::GetDefaultComponentCmxPath(""));
}
} // namespace
} // namespace component