From 83b327dd46b85cb2e4bcf4d1a8a4fc5040e9152d Mon Sep 17 00:00:00 2001 From: Aleksander Zdyb Date: Mon, 15 Dec 2014 13:49:46 +0100 Subject: [PATCH] Implement --set-bucket and --delete-bucket in Cyad Change-Id: I61065bb8364d8cb33821c8a7be20a4b756522b43 --- .../CommandlineParser/CyadCommandlineParser.cpp | 133 +++++++++++++++++++-- src/cyad/CommandlineParser/CyadCommandlineParser.h | 22 ++++ .../CommandlineParser/PolicyParsingException.h | 46 +++++++ test/cyad/commandline.cpp | 67 +++++++++++ test/cyad/commandline_errors.cpp | 42 +++++++ 5 files changed, 299 insertions(+), 11 deletions(-) create mode 100644 src/cyad/CommandlineParser/PolicyParsingException.h diff --git a/src/cyad/CommandlineParser/CyadCommandlineParser.cpp b/src/cyad/CommandlineParser/CyadCommandlineParser.cpp index 845f1ef..713b506 100644 --- a/src/cyad/CommandlineParser/CyadCommandlineParser.cpp +++ b/src/cyad/CommandlineParser/CyadCommandlineParser.cpp @@ -24,6 +24,9 @@ #include #include #include +#include + +#include #include "CyadCommandlineParser.h" @@ -32,12 +35,29 @@ namespace Cynara { namespace CyadCmdlineArgs { const char HELP = 'h'; const char * const HELP_LONG = "help"; + + const char SET_BUCKET = 'b'; + const char * const SET_BUCKET_LONG = "set-bucket"; + + const char DELETE_BUCKET = 'd'; + const char * const DELETE_BUCKET_LONG = "delete-bucket"; + + const char POLICY = 'p'; + const char * const POLICY_LONG = "policy"; + + const char METADATA = 'm'; + const char * const METADATA_LONG = "metadata"; } namespace CyadCmdlineErrors { const char * const UNKNOWN_ERROR = "Unknown error"; const char * const NO_OPTION = "No option specified"; const char * const UNKNOWN_OPTION = "Unknown option"; + const char * const UNKNOWN_OPTION_SET_BUCKET = "Unknown option in --set-bucket"; + const char * const UNKNOWN_OPTION_DELETE_BUCKET = "Unknown option in --delete-bucket"; + const char * const NO_POLICY = "No --policy specified"; + const char * const NO_BUCKET = "No bucket specified"; + const char * const INVALID_POLICY = "Invalid --policy option"; } CyadCommandlineParser::CyadCommandlineParser(int argc, char * const *argv) @@ -49,33 +69,124 @@ std::shared_ptr CyadCommandlineParser::parseMain(void) { namespace Args = CyadCmdlineArgs; const struct option long_options[] = { - { Args::HELP_LONG, no_argument, nullptr, Args::HELP }, + { Args::HELP_LONG, no_argument, nullptr, Args::HELP }, + { Args::SET_BUCKET_LONG, required_argument, nullptr, Args::SET_BUCKET }, + { Args::DELETE_BUCKET_LONG, required_argument, nullptr, Args::DELETE_BUCKET }, { nullptr, 0, nullptr, 0 } }; optind = 0; // On entry to `getopt', zero means this is the first call; initialize. int opt; std::stringstream optstr; - optstr << ":" << Args::HELP; + optstr << ":" << Args::HELP + << Args::SET_BUCKET << ":" + << Args::DELETE_BUCKET << ":"; while ((opt = getopt_long(m_argc, m_argv, optstr.str().c_str(), long_options, nullptr)) != -1) { switch (opt) { - case Args::HELP: - return std::make_shared(); + case Args::HELP: + return std::make_shared(); - case '?': // Unknown option - return std::make_shared(CyadCmdlineErrors::UNKNOWN_OPTION); + case Args::SET_BUCKET: + return parseSetBucket(optarg); - case ':': // Missing argument - // Shall never happen, but let's just make compiler happy. - return std::make_shared(CyadCmdlineErrors::UNKNOWN_ERROR); + case Args::DELETE_BUCKET: + return parseDeleteBucket(optarg); - default: - return std::make_shared(CyadCmdlineErrors::UNKNOWN_OPTION); + case '?': // Unknown option + return std::make_shared(CyadCmdlineErrors::UNKNOWN_OPTION); + + case ':': // Missing argument + switch (optopt) { + case Args::SET_BUCKET: + case Args::DELETE_BUCKET: + return std::make_shared(CyadCmdlineErrors::NO_BUCKET); + } + // Shall never happen, but let's just make compiler happy. + return std::make_shared(CyadCmdlineErrors::UNKNOWN_ERROR); + + default: + return std::make_shared(CyadCmdlineErrors::UNKNOWN_OPTION); } } return std::make_shared(CyadCmdlineErrors::NO_OPTION); } +std::shared_ptr CyadCommandlineParser::parseSetBucket(const std::string &bucketId) { + namespace Args = CyadCmdlineArgs; + namespace Errors = CyadCmdlineErrors; + + const struct option long_options[] = { + { Args::POLICY_LONG, required_argument, nullptr, Args::POLICY }, + { Args::METADATA_LONG, required_argument, nullptr, Args::METADATA }, + { nullptr, 0, nullptr, 0 } + }; + + std::string policy; + std::string metadata; + + int opt; + std::stringstream optstr; + optstr << ":" + << Args::POLICY << ":" + << Args::METADATA << ":"; + + while ((opt = getopt_long(m_argc, m_argv, optstr.str().c_str(), long_options, nullptr)) != -1) { + switch(opt) { + case Args::POLICY: + policy = optarg; + break; + case Args::METADATA: + metadata = optarg; + break; + default: + return std::make_shared(Errors::UNKNOWN_OPTION_SET_BUCKET); + } + } + + if (policy.empty()) + return std::make_shared(Errors::NO_POLICY); + + try { + auto policyType = parsePolicyType(policy); + return std::make_shared(bucketId, PolicyResult(policyType, metadata)); + } catch (const PolicyParsingException &) { + return std::make_shared(Errors::INVALID_POLICY); + } +} + +std::shared_ptr CyadCommandlineParser::parseDeleteBucket(const std::string &bucketId) { + namespace Errors = CyadCmdlineErrors; + + // Expect no additional options + const struct option long_options[] = { + { nullptr, 0, nullptr, 0 } + }; + + if (getopt_long(m_argc, m_argv, ":", long_options, nullptr) == -1) { + return std::make_shared(bucketId); + } else { + return std::make_shared(Errors::UNKNOWN_OPTION_DELETE_BUCKET); + } +} + +PolicyType CyadCommandlineParser::parsePolicyType(const std::string &rawPolicy) { + if (rawPolicy == "DENY") + return CYNARA_ADMIN_DENY; + if (rawPolicy == "NONE") + return CYNARA_ADMIN_NONE; + if (rawPolicy == "BUCKET") + return CYNARA_ADMIN_BUCKET; + if (rawPolicy == "ALLOW") + return CYNARA_ADMIN_ALLOW; + + // If base for std::stoi is set to 0, it detects base by itself from the format of the sequence + try { + return std::stoi(rawPolicy, nullptr, 0); + } catch (const std::logic_error &) { + throw PolicyParsingException(); + } +} + } /* namespace Cynara */ diff --git a/src/cyad/CommandlineParser/CyadCommandlineParser.h b/src/cyad/CommandlineParser/CyadCommandlineParser.h index 7b30348..4b629c4 100644 --- a/src/cyad/CommandlineParser/CyadCommandlineParser.h +++ b/src/cyad/CommandlineParser/CyadCommandlineParser.h @@ -32,12 +32,29 @@ namespace Cynara { namespace CyadCmdlineArgs { extern const char HELP; extern const char * const HELP_LONG; + + extern const char SET_BUCKET; + extern const char * const SET_BUCKET_LONG; + + extern const char DELETE_BUCKET; + extern const char * const DELETE_BUCKET_LONG; + + extern const char POLICY; + extern const char * const POLICY_LONG; + + extern const char METADATA; + extern const char * const METADATA_LONG; } namespace CyadCmdlineErrors { extern const char * const UNKNOWN_ERROR; extern const char * const NO_OPTION; extern const char * const UNKNOWN_OPTION; + extern const char * const UNKNOWN_OPTION_SET_BUCKET; + extern const char * const UNKNOWN_OPTION_DELETE_BUCKET; + extern const char * const NO_POLICY; + extern const char * const NO_BUCKET; + extern const char * const INVALID_POLICY; } class CyadCommandlineParser { @@ -46,6 +63,11 @@ public: virtual ~CyadCommandlineParser(); std::shared_ptr parseMain(void); + static PolicyType parsePolicyType(const std::string &rawPolicy); + +protected: + std::shared_ptr parseSetBucket(const std::string &bucketId); + std::shared_ptr parseDeleteBucket(const std::string &bucketId); private: int m_argc; diff --git a/src/cyad/CommandlineParser/PolicyParsingException.h b/src/cyad/CommandlineParser/PolicyParsingException.h new file mode 100644 index 0000000..958d44e --- /dev/null +++ b/src/cyad/CommandlineParser/PolicyParsingException.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd 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. + */ +/** + * @file src/cyad/CommandlineParser/PolicyParsingException.h + * @author Aleksander Zdyb + * @version 1.0 + * @brief PolicyParsingException + */ + +#ifndef SRC_CYAD_COMMANDLINEPARSER_POLICYPARSINGEXCEPTION_H_ +#define SRC_CYAD_COMMANDLINEPARSER_POLICYPARSINGEXCEPTION_H_ + +#include + +namespace Cynara { + +class PolicyParsingException : public Exception { +public: + PolicyParsingException() { + m_message = "Invalid policy"; + } + + virtual const std::string &message(void) const { + return m_message; + } + +private: + std::string m_message; +}; + +} /* namespace Cynara */ + +#endif /* SRC_CYAD_COMMANDLINEPARSER_POLICYPARSINGEXCEPTION_H_ */ diff --git a/test/cyad/commandline.cpp b/test/cyad/commandline.cpp index 620cf28..31b0771 100644 --- a/test/cyad/commandline.cpp +++ b/test/cyad/commandline.cpp @@ -38,3 +38,70 @@ TEST_F(CyadCommandlineTest, help) { auto result = std::dynamic_pointer_cast(parser.parseMain()); ASSERT_NE(nullptr, result); } + +TEST_F(CyadCommandlineTest, deleteBucket) { + prepare_argv({ "./cyad", "--delete-bucket=bucket" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("bucket", result->bucketId()); +} + +TEST_F(CyadCommandlineTest, setBucket) { + prepare_argv({ "./cyad", "--set-bucket=bucket", "--policy=42" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("bucket", result->bucketId()); + ASSERT_EQ(42, result->policyResult().policyType()); + ASSERT_TRUE(result->policyResult().metadata().empty()); +} + +TEST_F(CyadCommandlineTest, setBucketWithMetadata) { + const std::string ultimateAnswer = "Answer to The Ultimate Question of Life," + " the Universe, and Everything"; + + prepare_argv({ "./cyad", "--set-bucket=adams", "--policy=42", "--metadata=" + ultimateAnswer }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + + auto result = std::dynamic_pointer_cast(parser.parseMain()); + ASSERT_NE(nullptr, result); + ASSERT_EQ("adams", result->bucketId()); + ASSERT_EQ(42, result->policyResult().policyType()); + ASSERT_EQ(ultimateAnswer, result->policyResult().metadata()); +} + +TEST_F(CyadCommandlineTest, parsePolicyTypeBase10) { + auto parsePolicyType = [] (const char *rawPolicy) -> Cynara::PolicyType { + return Cynara::CyadCommandlineParser::parsePolicyType(rawPolicy); + }; + + ASSERT_EQ(CYNARA_ADMIN_DENY, parsePolicyType("0")); + ASSERT_EQ(CYNARA_ADMIN_NONE, parsePolicyType("1")); + ASSERT_EQ(CYNARA_ADMIN_BUCKET, parsePolicyType("65534")); + ASSERT_EQ(CYNARA_ADMIN_ALLOW, parsePolicyType("65535")); +} + +TEST_F(CyadCommandlineTest, parsePolicyTypeBase16) { + auto parsePolicyType = [] (const char *rawPolicy) -> Cynara::PolicyType { + return Cynara::CyadCommandlineParser::parsePolicyType(rawPolicy); + }; + + ASSERT_EQ(CYNARA_ADMIN_DENY, parsePolicyType("0x0")); + ASSERT_EQ(CYNARA_ADMIN_NONE, parsePolicyType("0x1")); + ASSERT_EQ(CYNARA_ADMIN_BUCKET, parsePolicyType("0xFFFE")); + ASSERT_EQ(CYNARA_ADMIN_ALLOW, parsePolicyType("0xFFFF")); +} + +TEST_F(CyadCommandlineTest, parsePolicyTypeHuman) { + auto parsePolicyType = [] (const char *rawPolicy) -> Cynara::PolicyType { + return Cynara::CyadCommandlineParser::parsePolicyType(rawPolicy); + }; + + ASSERT_EQ(CYNARA_ADMIN_DENY, parsePolicyType("DENY")); + ASSERT_EQ(CYNARA_ADMIN_NONE, parsePolicyType("NONE")); + ASSERT_EQ(CYNARA_ADMIN_BUCKET, parsePolicyType("BUCKET")); + ASSERT_EQ(CYNARA_ADMIN_ALLOW, parsePolicyType("ALLOW")); +} diff --git a/test/cyad/commandline_errors.cpp b/test/cyad/commandline_errors.cpp index 5326119..5aa358f 100644 --- a/test/cyad/commandline_errors.cpp +++ b/test/cyad/commandline_errors.cpp @@ -48,3 +48,45 @@ TEST_F(CyadCommandlineTest, unknownOption) { Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::UNKNOWN_OPTION, parser.parseMain()); } + +TEST_F(CyadCommandlineTest, deleteBucketNoBucket) { + prepare_argv({ "./cyad", "--delete-bucket" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::NO_BUCKET, parser.parseMain()); +} + +TEST_F(CyadCommandlineTest, deleteBucketUnknownOption) { + prepare_argv({ "./cyad", "--delete-bucket=bucket", "--unknown" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::UNKNOWN_OPTION_DELETE_BUCKET, parser.parseMain()); +} + +TEST_F(CyadCommandlineTest, setBucketNoBucket) { + prepare_argv({ "./cyad", "--set-bucket" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::NO_BUCKET, parser.parseMain()); +} + +TEST_F(CyadCommandlineTest, setBucketNoPolicy) { + prepare_argv({ "./cyad", "--set-bucket=bucket" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::NO_POLICY, parser.parseMain()); +} + +TEST_F(CyadCommandlineTest, setBucketInvalidPolicy) { + prepare_argv({ "./cyad", "--set-bucket=bucket", "--policy=NaN" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::INVALID_POLICY, parser.parseMain()); +} + +TEST_F(CyadCommandlineTest, setBucketUnknownOption) { + prepare_argv({ "./cyad", "--set-bucket=bucket", "--unknown", "--policy=42" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::UNKNOWN_OPTION_SET_BUCKET, parser.parseMain()); +} + +TEST_F(CyadCommandlineTest, setBucketMetadataNoPolicy) { + prepare_argv({ "./cyad", "--set-bucket=bucket", "--metadata=some-meta" }); + Cynara::CyadCommandlineParser parser(this->argc(), this->argv()); + ASSERT_ERROR_MSG(Cynara::CyadCmdlineErrors::NO_POLICY, parser.parseMain()); +} -- 2.7.4