* Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "api/cpp/src/runtime_env_parse.h"
#include <gtest/gtest.h>
#include <filesystem>
#include <fstream>
#include "src/dto/invoke_options.h"
#include "common/common.h"
namespace fs = std::filesystem;
namespace YR {
namespace test {
class RuntimeEnvParseTest : public ::testing::Test {
protected:
void SetUp() override
{
validYamlPath_ = fs::temp_directory_path() / "valid_env.yaml";
std::ofstream yamlFile(validYamlPath_);
yamlFile << "name: test_env\ndependencies:\n - python=3.8\n - pip\n - pip:\n - numpy\n";
yamlFile.close();
validNoNameYamlPath_ = fs::temp_directory_path() / "no_name_valid_env.yaml";
std::ofstream noNameYamlFile(validNoNameYamlPath_);
noNameYamlFile << "dependencies:\n - python=3.8\n - pip\n - pip:\n - numpy\n";
noNameYamlFile.close();
setenv("YR_CONDA_HOME", "/fake/conda/path", 1);
}
void TearDown() override
{
if (fs::exists(validYamlPath_)) {
fs::remove(validYamlPath_);
}
if (fs::exists(validNoNameYamlPath_)) {
fs::remove(validNoNameYamlPath_);
}
}
fs::path validYamlPath_;
fs::path validNoNameYamlPath_;
};
TEST_F(RuntimeEnvParseTest, ShouldThrowWhenCondaHomeNotSet)
{
unsetenv("YR_CONDA_HOME");
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<nlohmann::json>("conda", {{"name", "test"}});
EXPECT_THROW(YR::ParseRuntimeEnv(options, env), YR::Exception);
}
TEST_F(RuntimeEnvParseTest, ShouldProcessPipPackagesCorrectly)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::vector<std::string>>("pip", {"numpy", "pandas"});
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.createOptions["POST_START_EXEC"], "pip3 install numpy pandas");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectBothPipAndConda)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::vector<std::string>>("pip", {"numpy"});
env.Set<std::string>("conda", "env_name");
EXPECT_THROW(YR::ParseRuntimeEnv(options, env), YR::Exception);
}
TEST_F(RuntimeEnvParseTest, ShouldHandleWorkingDirCorrectly)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::string>("working_dir", "/tmp/test_dir");
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.workingDir, "/tmp/test_dir");
}
TEST_F(RuntimeEnvParseTest, ShouldMergeEnvVarsProperly)
{
YR::Libruntime::InvokeOptions options;
options.envVars["EXISTING"] = "original";
YR::RuntimeEnv env;
env.Set<std::map<std::string, std::string>>("env_vars", {{"NEW", "value"}, {"EXISTING", "new"}});
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.envVars["NEW"], "value");
EXPECT_EQ(options.envVars["EXISTING"], "original");
}
TEST_F(RuntimeEnvParseTest, ShouldProcessCondaYamlFile)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::string>("conda", validYamlPath_.string());
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.createOptions["CONDA_PREFIX"], "/fake/conda/path");
EXPECT_EQ(options.createOptions["CONDA_COMMAND"], "conda env create -f env.yaml");
EXPECT_EQ(options.createOptions["CONDA_CONFIG"], "{\"name\": \"test_env\", \"dependencies\": [\"python=3.8\", \"pip\", {\"pip\": [\"numpy\"]}]}");
}
TEST_F(RuntimeEnvParseTest, ShouldProcessCondaNoNameYamlFile)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::string>("conda", validNoNameYamlPath_.string());
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.createOptions["CONDA_PREFIX"], "/fake/conda/path");
EXPECT_EQ(options.createOptions["CONDA_COMMAND"], "conda env create -f env.yaml");
EXPECT_FALSE(options.createOptions["CONDA_DEFAULT_ENV"].empty());
}
TEST_F(RuntimeEnvParseTest, ShouldProcessCondaEnvName)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::string>("conda", "existing_env");
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.createOptions["CONDA_COMMAND"], "conda activate existing_env");
EXPECT_EQ(options.createOptions["CONDA_DEFAULT_ENV"], "existing_env");
}
TEST_F(RuntimeEnvParseTest, ShouldProcessCondaJsonConfig)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json config = {{"name", "json_env"}, {"dependencies", {"python=3.8", "numpy"}}};
env.Set<nlohmann::json>("conda", config);
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.createOptions["CONDA_COMMAND"], "conda env create -f env.yaml");
EXPECT_TRUE(options.createOptions["CONDA_DEFAULT_ENV"].find("json_env") != std::string::npos);
}
TEST_F(RuntimeEnvParseTest, ShouldRejectInvalidYamlFile)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::string>("conda", "/nonexistent/path.yaml");
EXPECT_THROW(YR::ParseRuntimeEnv(options, env), YR::Exception);
}
TEST_F(RuntimeEnvParseTest, ShouldRejectInvalidPipType)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::string>("pip", "this_should_be_array");
EXPECT_THROW(YR::ParseRuntimeEnv(options, env), YR::Exception);
}
TEST_F(RuntimeEnvParseTest, ShouldGenerateRandomNameForEmptyCondaName)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json config = {{"name", ""}, {"dependencies", {"python"}}};
env.Set<nlohmann::json>("conda", config);
YR::ParseRuntimeEnv(options, env);
EXPECT_FALSE(options.createOptions["CONDA_DEFAULT_ENV"].empty());
}
TEST_F(RuntimeEnvParseTest, ShouldAddSharedDirInCreateOpt)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json config = {{"name", "abc"}, {"TTL", 5}};
env.Set<nlohmann::json>("shared_dir", config);
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.createOptions["DELEGATE_SHARED_DIRECTORY"], "abc");
EXPECT_EQ(options.createOptions["DELEGATE_SHARED_DIRECTORY_TTL"], "5");
YR::Libruntime::InvokeOptions options2;
YR::RuntimeEnv env2;
nlohmann::json config2 = {{"name", "abc"}};
env2.Set<nlohmann::json>("shared_dir", config2);
YR::ParseRuntimeEnv(options2, env2);
EXPECT_EQ(options2.createOptions["DELEGATE_SHARED_DIRECTORY"], "abc");
EXPECT_EQ(options2.createOptions["DELEGATE_SHARED_DIRECTORY_TTL"], "0");
}
TEST_F(RuntimeEnvParseTest, ShouldThrowExceptionWhenSharedDirConfigInvaild)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json config = {{"name", ""}};
env.Set<nlohmann::json>("shared_dir", config);
EXPECT_THROW(YR::ParseRuntimeEnv(options, env), YR::Exception);
YR::Libruntime::InvokeOptions options2;
YR::RuntimeEnv env2;
env2.Set<nlohmann::json>("shared_dir", "str");
EXPECT_THROW(YR::ParseRuntimeEnv(options2, env2), YR::Exception);
}
TEST_F(RuntimeEnvParseTest, ShouldRejectBothPipAndVenv)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::vector<std::string>>("pip", {"numpy"});
nlohmann::json venvConfig = {{"name", "testVenv"}};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(
YR::ParseRuntimeEnv(options, env), 1001,
"The 'venv' field and 'pip' field of runtime_env cannot both be specified.\n");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectBothCondaAndVenv)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::string>("conda", validYamlPath_.string());
nlohmann::json venvConfig = {{"name", "testVenv"}};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(
YR::ParseRuntimeEnv(options, env), 1001,
"The 'conda' field and 'venv' field of runtime_env cannot both be specified.");
}
TEST_F(RuntimeEnvParseTest, ShouldProcessVenvWithHost)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"name", "123testVenv"},
{"path", {
{"site_package_path", "obs://mini-kernel/site-package.zip"}
}},
{"dependencies", {
{"pypi", {"matplotlib", "msgpack-python == 1.0.5"}},
{"trusted_host", "mirrors.tools.nobody.com"},
{"index_url", "http://mirrors.tools.nobody.com/pypi/simple/"},
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.createOptions["VIRTUALENV_KIND"], "venv");
EXPECT_EQ(options.createOptions["VIRTUALENV_NAME"], "123testVenv");
EXPECT_EQ(options.createOptions["VIRTUALENV_COMMAND"], "pip install \"matplotlib\" \"msgpack-python==1.0.5\" "
"-i http://mirrors.tools.nobody.com/pypi/simple/ --trusted-host mirrors.tools.nobody.com");
EXPECT_EQ(options.createOptions["VIRTUALENV_PATH"], "{\"site_package_path\":\"obs://mini-kernel/site-package.zip\"}");
}
TEST_F(RuntimeEnvParseTest, ShouldProcessVenvWithoutHost)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"name", "testVenv"},
{"path", {
{"site_package_path", "obs://mini-kernel/site-package.zip"}
}},
{"dependencies", {
{"pypi", {"matplotlib ", "msgpack-python==1.0.5"}}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
YR::ParseRuntimeEnv(options, env);
EXPECT_EQ(options.createOptions["VIRTUALENV_KIND"], "venv");
EXPECT_EQ(options.createOptions["VIRTUALENV_NAME"], "testVenv");
EXPECT_EQ(options.createOptions["VIRTUALENV_COMMAND"], "pip install \"matplotlib\" \"msgpack-python==1.0.5\"");
EXPECT_EQ(options.createOptions["VIRTUALENV_PATH"], "{\"site_package_path\":\"obs://mini-kernel/site-package.zip\"}");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvNotJson)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
env.Set<std::string>("venv", "xxx");
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv format must be json");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvKeysInvalid)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {{"key", "value"}};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv keys can only be name, dependencies, path");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvNameNotString)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {{"name", 123}};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.name format must be string");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvNameInvalid)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {{"name", "!"}};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.name is invalid");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvDependenciesNotJson)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {{"dependencies", "xxx"}};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.dependencies format must be json");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvDependenciesKeysInvalid)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"dependencies", {
{"key", "value"}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.dependencies keys can only be pypi, trusted_host, index_url");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvDependenciesPypiNotArray)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"dependencies", {
{"pypi", "xxx"}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.dependencies.pypi format must be array");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvDependenciesTrustedHostNotString) {
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"dependencies", {
{"pypi", {"matplotlib", "msgpack-python==1.0.5"}},
{"trusted_host", 123}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.dependencies.trusted_host format must be string");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvDependenciesIndexURLNotString) {
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"dependencies", {
{"pypi", {"matplotlib", "msgpack-python==1.0.5"}},
{"index_url", 123}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.dependencies.index_url format must be string");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvDependenciesPypiItemNotString)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"dependencies", {
{"pypi", {123}},
{"trusted_host", "mirrors.tools.nobody.com"}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.dependencies.pypi item format must be string");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvDependenciesPypiItemEmpty)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"dependencies", {
{"pypi", {"matplotlib", " "}},
{"trusted_host", "mirrors.tools.nobody.com"}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.dependencies.pypi item is empty");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvPathNotJson)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {{"path", "xxx"}};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.path format must be json");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvPathKeysInvalid)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"path", {
{"key", "value"}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.path keys can only be site_package_path");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvPathSitePackagePathNotString)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"path", {
{"site_package_path", 123}
}},
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.path.site_package_path format must be string");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvPypiItemContainInvalidOperator)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"dependencies", {
{"pypi", {"requests=2.28.1"}}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "venv.dependencies.pypi item contains illegal operator '='");
}
TEST_F(RuntimeEnvParseTest, ShouldProcessVenvWithPypiExtras)
{
YR::Libruntime::InvokeOptions options1;
YR::RuntimeEnv env1;
nlohmann::json venvConfig1 = {
{"dependencies", {
{"pypi", {"requests[socks]"}}
}}
};
env1.Set<nlohmann::json>("venv", venvConfig1);
YR::ParseRuntimeEnv(options1, env1);
EXPECT_EQ(options1.createOptions["VIRTUALENV_KIND"], "venv");
EXPECT_EQ(options1.createOptions["VIRTUALENV_COMMAND"], "pip install \"requests[socks]\"");
YR::Libruntime::InvokeOptions options2;
YR::RuntimeEnv env2;
nlohmann::json venvConfig2 = {
{"dependencies", {
{"pypi", {"django[argon2, bcrypt]"}}
}}
};
env2.Set<nlohmann::json>("venv", venvConfig2);
YR::ParseRuntimeEnv(options2, env2);
EXPECT_EQ(options2.createOptions["VIRTUALENV_KIND"], "venv");
EXPECT_EQ(options2.createOptions["VIRTUALENV_COMMAND"], "pip install \"django[argon2,bcrypt]\"");
}
TEST_F(RuntimeEnvParseTest, ShouldProcessVenvWithPypiVersion)
{
YR::Libruntime::InvokeOptions options1;
YR::RuntimeEnv env1;
nlohmann::json venvConfig1 = {
{"dependencies", {
{"pypi", {"requests==2.28.1"}}
}}
};
env1.Set<nlohmann::json>("venv", venvConfig1);
YR::ParseRuntimeEnv(options1, env1);
EXPECT_EQ(options1.createOptions["VIRTUALENV_KIND"], "venv");
EXPECT_EQ(options1.createOptions["VIRTUALENV_COMMAND"], "pip install \"requests==2.28.1\"");
YR::Libruntime::InvokeOptions options2;
YR::RuntimeEnv env2;
nlohmann::json venvConfig2 = {
{"dependencies", {
{"pypi", {"package===1.0.0"}}
}}
};
env2.Set<nlohmann::json>("venv", venvConfig2);
YR::ParseRuntimeEnv(options2, env2);
EXPECT_EQ(options2.createOptions["VIRTUALENV_KIND"], "venv");
EXPECT_EQ(options2.createOptions["VIRTUALENV_COMMAND"], "pip install \"package===1.0.0\"");
YR::Libruntime::InvokeOptions options3;
YR::RuntimeEnv env3;
nlohmann::json venvConfig3 = {
{"dependencies", {
{"pypi", {"requests>=2.0,<3.0"}}
}}
};
env3.Set<nlohmann::json>("venv", venvConfig3);
YR::ParseRuntimeEnv(options3, env3);
EXPECT_EQ(options3.createOptions["VIRTUALENV_KIND"], "venv");
EXPECT_EQ(options3.createOptions["VIRTUALENV_COMMAND"], "pip install \"requests>=2.0,<3.0\"");
YR::Libruntime::InvokeOptions options4;
YR::RuntimeEnv env4;
nlohmann::json venvConfig4 = {
{"dependencies", {
{"pypi", {"requests[socks]==2.28.1"}}
}}
};
env4.Set<nlohmann::json>("venv", venvConfig4);
YR::ParseRuntimeEnv(options4, env4);
EXPECT_EQ(options4.createOptions["VIRTUALENV_KIND"], "venv");
EXPECT_EQ(options4.createOptions["VIRTUALENV_COMMAND"], "pip install \"requests[socks]==2.28.1\"");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvPypiItemPkgNameInvalid)
{
YR::Libruntime::InvokeOptions options;
YR::RuntimeEnv env;
nlohmann::json venvConfig = {
{"dependencies", {
{"pypi", {"aaa123!@#-*1a"}}
}}
};
env.Set<nlohmann::json>("venv", venvConfig);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options, env), 1001, "package name of venv.dependencies.pypi item is invalid");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvPypiItemExtrasInvalid)
{
YR::Libruntime::InvokeOptions options1;
YR::RuntimeEnv env1;
nlohmann::json venvConfig1 = {
{"dependencies", {
{"pypi", {"requests[socks"}}
}}
};
env1.Set<nlohmann::json>("venv", venvConfig1);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options1, env1), 1001, "extras of venv.dependencies.pypi item is invalid, does not contain ']'");
YR::Libruntime::InvokeOptions options2;
YR::RuntimeEnv env2;
nlohmann::json venvConfig2 = {
{"dependencies", {
{"pypi", {"requests[socks!]"}}
}}
};
env2.Set<nlohmann::json>("venv", venvConfig2);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options2, env2), 1001, "extras item of venv.dependencies.pypi item is invalid");
YR::Libruntime::InvokeOptions options3;
YR::RuntimeEnv env3;
nlohmann::json venvConfig3 = {
{"dependencies", {
{"pypi", {"requests[]"}}
}}
};
env3.Set<nlohmann::json>("venv", venvConfig3);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options3, env3), 1001, "extras of venv.dependencies.pypi item is empty");
YR::Libruntime::InvokeOptions options4;
YR::RuntimeEnv env4;
nlohmann::json venvConfig4 = {
{"dependencies", {
{"pypi", {"requests[socks,,xxx]"}}
}}
};
env4.Set<nlohmann::json>("venv", venvConfig4);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options4, env4), 1001, "extras item of venv.dependencies.pypi item is invalid");
}
TEST_F(RuntimeEnvParseTest, ShouldRejectVenvPypiItemVersionEmpty)
{
YR::Libruntime::InvokeOptions options1;
YR::RuntimeEnv env1;
nlohmann::json venvConfig1 = {
{"dependencies", {
{"pypi", {"requests>=,<3.0"}}
}}
};
env1.Set<nlohmann::json>("venv", venvConfig1);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options1, env1), 1001, "version of venv.dependencies.pypi item is empty");
YR::Libruntime::InvokeOptions options2;
YR::RuntimeEnv env2;
nlohmann::json venvConfig2 = {
{"dependencies", {
{"pypi", {"requests>=2.0,<"}}
}}
};
env2.Set<nlohmann::json>("venv", venvConfig2);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options2, env2), 1001, "version of venv.dependencies.pypi item is empty");
YR::Libruntime::InvokeOptions options3;
YR::RuntimeEnv env3;
nlohmann::json venvConfig3 = {
{"dependencies", {
{"pypi", {"requests=="}}
}}
};
env3.Set<nlohmann::json>("venv", venvConfig3);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options3, env3), 1001, "version of venv.dependencies.pypi item is empty");
YR::Libruntime::InvokeOptions options4;
YR::RuntimeEnv env4;
nlohmann::json venvConfig4 = {
{"dependencies", {
{"pypi", {"requests[socks]!="}}
}}
};
env4.Set<nlohmann::json>("venv", venvConfig4);
EXPECT_THROW_WITH_CODE_AND_MSG(YR::ParseRuntimeEnv(options4, env4), 1001, "version of venv.dependencies.pypi item is empty");
}
}
}