diff --git a/client/grpc/Ns.cc b/client/grpc/Ns.cc index be02d1492d3162431d6f501951b012a788e9f849..7bd4e7549482f1a11fd9b45e69ff8939cf60fde4 100644 --- a/client/grpc/Ns.cc +++ b/client/grpc/Ns.cc @@ -10,7 +10,7 @@ int usage(const char* prog) fprintf(stderr, "usage: %s [--key <ssl-key-file> " "--cert <ssl-cert-file> " "--ca <ca-cert-file>] " - "[--endpoint <host:port>] [--token <auth-token>] [--xattr <key:val>] [--mode <mode>] [--username <username>] [ [--groupname <groupname>] [--uid <uid>] [--gid <gid>] [--owner-uid <uid>] [--owner-gid <gid>] [--acl <acl>] [--sysacl] [--norecycle] [-r] [--max-version <max-version>] [--target <target>] [--year <year>] [--month <month>] [--day <day>] [--inodes <#>] [--volume <#>] [--quota volume|inode] -p <path> <command>\n", prog); + "[--endpoint <host:port>] [--token <auth-token>] [--xattr <key:val>] [--mode <mode>] [--username <username>] [ [--groupname <groupname>] [--uid <uid>] [--gid <gid>] [--owner-uid <uid>] [--owner-gid <gid>] [--acl <acl>] [--sysacl] [--norecycle] [-r] [--max-version <max-version>] [--target <target>] [--year <year>] [--month <month>] [--day <day>] [--inodes <#>] [--volume <#>] [--quota volume|inode] [--position <position>] [--front] -p <path> <command>\n", prog); fprintf(stderr, " -p <path> mkdir \n" @@ -23,7 +23,7 @@ int usage(const char* prog) " --xattr <!key=> -p <path> setxattr # deletes key\n" " --owner-uid <uid> --owner-gid <gid> -p <path> chown \n" " --mode <mode> -p <path> chmod \n" - " [--sysacl] [-r] [--acl <acl>] -p <path> acl \n" + " [--sysacl] [-r] [--acl <acl>] [--position <pos>] [--front] -p <path> acl \n" " --ztoken <token> | [--acl] [-r] -p <path> token\n" " [--max-version <max> -p <path> create-version \n" " -p <path> list-version \n" @@ -77,6 +77,7 @@ int main(int argc, const char* argv[]) bool recursive = false; bool norecycle = false; bool sysacl = false; + uint32_t position = 0; std::string eostoken = ""; for (auto i = 1; i < argc; ++i) { @@ -282,6 +283,34 @@ int main(int argc, const char* argv[]) } } + if (option == "--position") { + if (position) { + std::cout << "Please specify only one of --front or --position" << std::endl; + return usage(argv[0]); + } + if (argc > i + 1) { + try { + position = std::stoi(argv[i+1]); + ++i; + } catch (std::exception& e) { + return usage(argv[0]); + } + continue; + } else { + return usage(argv[0]); + } + + } + + if (option == "--front") { + if (position) { + std::cout << "Please specify only one of --front or --position" << std::endl; + return usage(argv[0]); + } + position = 1; + continue; + } + if (option == "--mode") { if (argc > i + 1) { mode = strtol(argv[i+1],0,8); @@ -483,6 +512,10 @@ int main(int argc, const char* argv[]) } else { request.mutable_acl()->set_type(eos::rpc::NSRequest::AclRequest::USER_ACL); } + + if (position) { + request.mutable_acl()->set_position(position); + } } else if (cmd == "token") { request.mutable_token()->mutable_token()->mutable_token()->set_expires(time(NULL) + 300); if (!path.empty()) { diff --git a/common/grpc-proto b/common/grpc-proto index d5b42da35097e8ff5f1e878b9ccc9c1daa292ca5..ae3ce89ff4cee18faed9f4bcd176f3a48d45f2de 160000 --- a/common/grpc-proto +++ b/common/grpc-proto @@ -1 +1 @@ -Subproject commit d5b42da35097e8ff5f1e878b9ccc9c1daa292ca5 +Subproject commit ae3ce89ff4cee18faed9f4bcd176f3a48d45f2de diff --git a/console/commands/com_proto_acl.cc b/console/commands/com_proto_acl.cc index 3c0a9e87f488a4dbd4ca300708536494c059f5d0..84a4f2c96526f1b5dceba509857b8d266916ba89 100644 --- a/console/commands/com_proto_acl.cc +++ b/console/commands/com_proto_acl.cc @@ -60,13 +60,16 @@ void com_acl_help() { std::ostringstream oss; oss - << "Usage: eos acl [-l|--list] [-R|--recursive] " + << "Usage: eos acl [-l|--list] [-R|--recursive]" + << " [-p | --position <pos>] [-f | --front] " << "[--sys|--user] [<rule>] <path>" << std::endl << " atomically set and modify ACLs for the given directory path" << std::endl << std::endl << " -h, --help : print help message" << std::endl << " -R, --recursive : apply to directories recursively" << std::endl << " -l, --list : list ACL rules" << std::endl + << " -p, --position : add the acl rule at specified position" << std::endl + << " -f, --front : add the acl rule at the front position" << std::endl << " --user : handle/list user.acl rules on directory. " << std::endl << " Regular users can modify these." << std::endl << " --sys : handle/list sys.acl rules on directory." << std::endl @@ -81,6 +84,10 @@ void com_acl_help() << " When modifying permissions every ACL flag can be added with" << std::endl << " \"+\" or removed with \"-\"." << std::endl + << " By default rules are appended at the end of acls" << std::endl + << " This ordering can be changed via --position flag" << std::endl + << " which will add the new rule at a given position starting at 1 or" << std::endl + << " the --front flag which adds the rule at the front instead" << std::endl << std::endl << "Examples:" << std::endl << " acl --user u:1001=rwx /eos/dev/" << std::endl @@ -90,6 +97,8 @@ void com_acl_help() << " acl --user u:1001:+m /eos/dev" << std::endl << " Add change mode permission flag for user id 1001" << std::endl << " acl --user u:1010= /eos/dev" << std::endl - << " Remove all ACls for user id 1001" << std::endl; + << " Remove all ACls for user id 1001" << std::endl + << " acl --front --user u:1001:rwx /eos/dev" << std::endl + << " Add the user id 1001 rule to the front of ACL rules" << std::endl; std::cerr << oss.str() << std::endl; } diff --git a/console/commands/helpers/AclHelper.cc b/console/commands/helpers/AclHelper.cc index 21e0ab4ed2146700c2ec46908ec67a672e874487..52f899a6e82b93b97a3d843719382d7a8d76f201 100644 --- a/console/commands/helpers/AclHelper.cc +++ b/console/commands/helpers/AclHelper.cc @@ -146,7 +146,6 @@ AclHelper::ParseCommand(const char* arg) eos::common::StringTokenizer tokenizer(arg); tokenizer.GetLine(); bool type_set = false; - // Get opts while ((temp = tokenizer.GetToken(false)) != 0) { // Trimming @@ -167,6 +166,36 @@ AclHelper::ParseCommand(const char* arg) acl->set_recursive(true); continue; } + if ((token == "-f") || (token == "--front")) { + if (acl->position()) { + std::cerr << "error: set only one of position or front argument" << std::endl; + return false; + } + acl->set_position(1); + continue; + } + + if ((token == "-p") || (token == "--position")) { + if (acl->position()) { + std::cerr << "error: set only one of position or front argument" << std::endl; + return false; + } + + std::string spos; + if (!tokenizer.NextToken(spos)) { + std::cerr << "error: position needs an argument!" << std::endl; + return false; + } + try { + int pos = std::stoi(spos); + if (pos > 0) + acl->set_position(pos); + } catch (const std::exception& e) { + std::cerr << "error: position needs to be integer" << std::endl; + return false; + } + continue; + } if ((token == "-l") || (token == "--list")) { acl->set_op(AclProto::LIST); diff --git a/doc/clicommands/acl.rst b/doc/clicommands/acl.rst index e219d1b6e7665d4777d1438b228e696a4fd16ce9..8e0846b2e221a56b646ab70290273f989cd7bf1d 100644 --- a/doc/clicommands/acl.rst +++ b/doc/clicommands/acl.rst @@ -3,21 +3,28 @@ acl .. code-block:: text - eos acl [-l|--list] [-R|--recursive] [--sys|--user] [<rule>] <path> + eos acl [-l|--list] [-R|--recursive] [-p | --position <pos>] [-f | --front] [--sys|--user] [<rule>] <path> atomically set and modify ACLs for the given directory path .. code-block:: text -h, --help : print help message -R, --recursive : apply to directories recursively -l, --list : list ACL rules - --user : handle/list user.acl rules on directory - --sys : handle/list sys.acl rules on directory + -p, --position : add the acl rule at specified position + -f, --front : add the acl rule at the front position + --user : handle/list user.acl rules on directory + --sys : handle/list sys.acl rules on directory <rule> is created similarly to chmod rules. Every rule begins with [u|g|egroup] followed by ":" or "=" and an identifier. ":" is used to for modifying permissions while "=" is used for setting/overwriting permissions. When modifying permissions every ACL flag can be added with - "+" or removed with "-". + "+" or removed with "- + By default rules are appended at the end of acls + This ordering can be changed via --position flag + which will add the new rule at a given position starting at 1 or + the --front flag which adds the rule at the front instead + Examples: acl --user u:1001=rwx /eos/dev/ Set ACLs for user id 1001 to rwx diff --git a/mgm/grpc/GrpcNsInterface.cc b/mgm/grpc/GrpcNsInterface.cc index f9b5a8e350c75e0d9ba600c80cc657beedebdc88..ae83401185b8fe7e4cd2ab2cd5ec7c951b6243c0 100644 --- a/mgm/grpc/GrpcNsInterface.cc +++ b/mgm/grpc/GrpcNsInterface.cc @@ -2236,6 +2236,11 @@ GrpcNsInterface::Acl(eos::common::VirtualIdentity& vid, req.mutable_acl()->set_op(eos::console::AclProto::LIST); } + uint32_t position = request->position(); + if (position) { + req.mutable_acl()->set_position(position); + } + req.mutable_acl()->set_rule(request->rule()); eos::mgm::AclCmd aclcmd(std::move(req), vid); eos::console::ReplyProto preply = aclcmd.ProcessRequest(); diff --git a/mgm/proc/user/AclCmd.cc b/mgm/proc/user/AclCmd.cc index 56cb5fb63441614e0bf563c2da04122cfbf4431f..f14968d8e59c8d623cde225815b6043e95fdc1e0 100644 --- a/mgm/proc/user/AclCmd.cc +++ b/mgm/proc/user/AclCmd.cc @@ -146,7 +146,14 @@ AclCmd::ModifyAcls(const eos::console::AclProto& acl) for (const auto& elem : paths) { GetAcls(elem, dir_acls, acl.sys_acl(), false); GenerateRuleMap(dir_acls, rule_map); - ApplyRule(rule_map); + // ACL position is 1-indexed as 0 is the default numeric protobuf val + auto [err, acl_pos] = GetRulePosition(rule_map.size(), acl.position()); + if (err) { + mErr = "error: rule position cannot be met!"; + return err; + } + + ApplyRule(rule_map,acl_pos); new_acl_val = GenerateAclString(rule_map); // Set xattr without taking the namespace lock @@ -268,8 +275,7 @@ AclCmd::GenerateRuleMap(const std::string& acl_string, RuleMap& rmap) std::string single_acl = std::string(acl_string.begin() + curr_pos, acl_string.begin() + pos); - Rule elem = GetRuleFromString(single_acl); - rmap.insert(elem); + insert_or_assign(rmap, GetRuleFromString(single_acl)); curr_pos = pos + 1; if (curr_pos > acl_string.length()) { @@ -515,12 +521,19 @@ AclCmd::CheckCorrectId(const std::string& id) const //------------------------------------------------------------------------------ // Apply client modification rule(s) to the acls of the current entry //------------------------------------------------------------------------------ -void AclCmd::ApplyRule(RuleMap& rules) +void AclCmd::ApplyRule(RuleMap& rules, size_t pos) { unsigned short temp_rule = 0; - if (!mSet && rules.find(mId) != rules.end()) { - temp_rule = rules[mId]; + if (!mSet) { + auto it = std::find_if(rules.begin(), + rules.end(), + [&](const Rule& rule) -> bool { + return rule.first == mId; + }); + if (it != rules.end()) { + temp_rule = it->second; + } } if (mAddRule != 0) { @@ -531,7 +544,16 @@ void AclCmd::ApplyRule(RuleMap& rules) temp_rule = temp_rule & (~mRmRule); } - rules[mId] = temp_rule; + if (pos != 0) { + auto [it, err] = get_iterator(rules, pos); + if (err != 0) { + mErr = "Invalid position of rule, errc=" + std::to_string(err); + } + insert_or_assign(rules, mId, temp_rule, it, true); + return; + } + + insert_or_assign(rules, mId, temp_rule); } //------------------------------------------------------------------------------ @@ -615,4 +637,34 @@ AclCmd::AclBitmaskToString(const unsigned short int in) return ret; } +std::pair<int, size_t> +AclCmd::GetRulePosition(size_t rule_map_sz, size_t rule_pos) +{ + + std::pair<int,size_t> result {0,0}; + + // Trivial case, nothing is set + if (!rule_map_sz && !rule_pos) { + return result; + } + + if (!rule_map_sz) { + // Only valid case here is that the client asks the first position! + if (rule_pos != 1) { + result.first = EINVAL; + } + } + + if (rule_map_sz && rule_pos) { + if (rule_pos > rule_map_sz) { + result.first = EINVAL; + } + + result.second = rule_pos; + } + + return result; +} + + EOSMGMNAMESPACE_END diff --git a/mgm/proc/user/AclCmd.hh b/mgm/proc/user/AclCmd.hh index 0643f24a6bc49a0b2d3226712731da89f5d336b7..24fed5fcabe354117d17377d2ae49fc7f3e8a7b0 100644 --- a/mgm/proc/user/AclCmd.hh +++ b/mgm/proc/user/AclCmd.hh @@ -24,12 +24,85 @@ #include "mgm/Namespace.hh" #include "mgm/proc/ProcCommand.hh" #include "proto/Acl.pb.h" -#include <unordered_map> +#include <list> EOSMGMNAMESPACE_BEGIN typedef std::pair<std::string, unsigned short> Rule; -typedef std::unordered_map<std::string, unsigned short> RuleMap; +//typedef std::unordered_map<std::string, unsigned short> RuleMap; +// We use a list as we need to be able to insert at any position +typedef std::list<Rule> RuleMap; + +template <typename C, typename K> +typename C::iterator key_position(C& c, const K& k) +{ + return std::find_if(c.begin(), + c.end(), + [&k](const typename C::value_type& val)->bool { + return k == val.first; + }); +} + +template <typename C, typename K, typename V> +void insert_or_assign(C& c, K&& k, V&& v) +{ + auto it = key_position(c,k); + if (it != c.end()) { + it->second = v; + return; + } + c.emplace_back(std::make_pair(std::forward<K>(k), + std::forward<V>(v))); +} + +template <typename C, typename K, typename V, + typename It = typename C::iterator> +void insert_or_assign(C& c, K&& k, V&& v, It&& pos, bool move_existing=false) +{ + auto it = key_position(c,k); + if (it != c.end()) { + if (!move_existing || it == pos) { + it->second = v; + return; + } + // This function currently moves an existing key to a given position too, if + // this is not needed, we could skip the following erase! Since Iterator is at a + // different position, erase this, we'll readd the key back at the last step + auto next_it = c.erase(it); + // In case we're demoting an element the erase would've dropped an element + // so the index position should be incremented! + if (pos != c.end() && + (std::distance(c.begin(), next_it) <= std::distance(c.begin(), pos))) { + ++pos; + } + } + c.insert(pos, std::make_pair(std::forward<K>(k), + std::forward<V>(v))); +} + +template <typename C> +void insert_or_assign(C& c, typename C::value_type&& value) +{ + using first_type = typename C::value_type::first_type; + using second_type = typename C::value_type::second_type; + insert_or_assign(c, + std::forward<first_type>(value.first), + std::forward<second_type>(value.second)); +} + +template <typename C> +std::pair<typename C::iterator, int> +get_iterator(C& c, size_t pos) +{ + if (pos == 0 || pos > c.size()) { + return std::make_pair(c.end(),EINVAL); + } + + auto it = c.begin(); + std::advance(it, pos - 1); + + return std::make_pair(it,0); +} //------------------------------------------------------------------------------ //! Class AclCmd - class handling acl command from a client @@ -102,6 +175,16 @@ public: //---------------------------------------------------------------------------- bool GetRuleBitmask(const std::string& input, bool set = false); + //---------------------------------------------------------------------------- + //! Generate the position to place the rule + //! + //! @param input rule_map size of the current rule_map + //! @param input rule_pos position to be inserted + //! + //! @return a pair of error, insert position + //---------------------------------------------------------------------------- + static std::pair<int, size_t> GetRulePosition(size_t rule_map_sz, size_t rule_pos); + //---------------------------------------------------------------------------- //! Return mAddRule result after GetRuleBitmask call. //---------------------------------------------------------------------------- @@ -184,7 +267,7 @@ private: //! //! @param rules map of acl rules for the current entry (directory) //---------------------------------------------------------------------------- - void ApplyRule(RuleMap& rules); + void ApplyRule(RuleMap& rules, size_t pos=0); //---------------------------------------------------------------------------- //! Convert ACL bitmask to string representation diff --git a/proto/common/cli_proto/Acl.proto b/proto/common/cli_proto/Acl.proto index bdba4d1a59c7687cb31be6af94a5cb1e76a2ac7e..1ca90262413bd7be9e5e7ac807b183bd8d17901d 100644 --- a/proto/common/cli_proto/Acl.proto +++ b/proto/common/cli_proto/Acl.proto @@ -13,4 +13,5 @@ message AclProto { bool sys_acl = 3; string rule = 5; string path = 6; + uint32 position = 7; } diff --git a/test/eos-grpc-test b/test/eos-grpc-test index a220617e9f67adecc56ad80562fe43bf4a0b2792..7269e4a171e08bac6443c30d64ce912cf251b6be 100755 --- a/test/eos-grpc-test +++ b/test/eos-grpc-test @@ -105,8 +105,15 @@ eos-grpc-ns --token $authkey -p $prefix/t_grpc/file unlink || exit -10 #acls eos-grpc-ns --token $authkey -p $prefix/t_grpc --sysacl --acl u:adm=rwx acl || exit -11 eos-grpc-ns --token $authkey -p $prefix/t_grpc --acl u:nobody=rwx acl || exit -11 -eos-grpc-ns --token $authkey -p $prefix/t_grpc --sysacl acl || grep "u:adm=rwx" || exit -11 -eos-grpc-ns --token $authkey -p $prefix/t_grpc acl || grep "u:nobody:rwx" || exit -11 +eos-grpc-ns --token $authkey -p $prefix/t_grpc --sysacl acl | grep "u:adm:rwx" || exit -11 +eos-grpc-ns --token $authkey -p $prefix/t_grpc acl | grep "u:nobody:rwx" || exit -11 +eos-grpc-ns --token $authkey -p $prefix/t_grpc --acl u:adm=rwx --front acl || exit -11 +eos-grpc-ns --token $authkey -p $prefix/t_grpc acl | grep "\"rule\": \"u:adm:rwx," || exit -11 +eos-grpc-ns --token $authkey -p $prefix/t_grpc --acl u:nobody=r --position 2 acl || exit -11 +eos-grpc-ns --token $authkey -p $prefix/t_grpc acl | grep "\"rule\": \"u:adm:rwx,u:nobody:r" || exit -11 +eos-grpc-ns --token $authkey -p $prefix/t_grpc --acl u:1003=r --position 5 acl | grep "position cannot be met" || exit -11 + + eos rmdir $prefix/t_grpc/ #quota diff --git a/unit_tests/mgm/AclCmdTests.cc b/unit_tests/mgm/AclCmdTests.cc index 16fbc11eb8a346f507aa03264616d4e3a03104f1..56e90ff86e6bfd8730648ac9332105a53b2ac36c 100644 --- a/unit_tests/mgm/AclCmdTests.cc +++ b/unit_tests/mgm/AclCmdTests.cc @@ -24,11 +24,10 @@ #include "gtest/gtest.h" #include "mgm/proc/user/AclCmd.hh" -EOSMGMNAMESPACE_BEGIN +using namespace eos::mgm; TEST(AclCmd, RuleMap) { - using namespace eos::mgm; RuleMap expect_map = { { "u:99", 0b011111111111}, { "u:0", 0b01010101010} }; @@ -36,10 +35,262 @@ TEST(AclCmd, RuleMap) const std::string acl = "u:99:rwxm!m!d+d!u+uqc,u:0:wm!d!uq"; AclCmd::GenerateRuleMap(acl, result_map); ASSERT_EQ(result_map.size(), expect_map.size()); + ASSERT_EQ(result_map, expect_map); +} + +TEST(AclCmd, key_position) +{ + RuleMap input_map { + {"u:99", 0b011111111111}, + {"u:1001",0b01}, + {"g:123",0b101}, + {"u:100",0b11} + }; + + auto begin_it = input_map.begin(); + auto end_it = input_map.end(); + EXPECT_EQ(key_position(input_map, "u:123"),end_it); + EXPECT_EQ(key_position(input_map, "g:123"),std::next(begin_it,2)); +} + +TEST(AclCmd, insert_or_assign_simple) +{ + RuleMap input_map { + {"u:99", 0b011111111111}, + {"u:1001",0b01}, + {"g:123",0b101}, + {"u:100",0b11} + }; + + RuleMap expected_map { + {"u:99", 0b011111111111}, + {"u:1001",0b01}, + {"g:123",0b101}, + {"u:100",0b11}, + {"u:123",0b100} + }; + + insert_or_assign(input_map, "u:123", 0b100); + EXPECT_EQ(input_map, expected_map); + + insert_or_assign(input_map, "u:1001", 0b1001); + + expected_map = {{"u:99", 0b011111111111}, + {"u:1001",0b1001}, + {"g:123",0b101}, + {"u:100",0b11}, + {"u:123",0b100} + }; + + EXPECT_EQ(input_map, expected_map); + + { + std::string key1 = "u:9001"; + unsigned short i = 100; + insert_or_assign(input_map, key1, i); + // Check that the values haven't moved + std::string key2 = "u:9001"; + EXPECT_EQ(key1,key2); + expected_map.emplace_back(key1,i); + EXPECT_EQ(input_map, expected_map); + } + + { + std::string key1 = "u:9002"; + unsigned short val = 101; + insert_or_assign(input_map, std::move(key1), std::move(val)); + // key was moved + EXPECT_EQ(key1,std::string()); + EXPECT_EQ(val, 101); + + expected_map.emplace_back("u:9002",val); + EXPECT_EQ(input_map, expected_map); + } + + { + std::string key1 = "u:9002"; + unsigned short val = 102; + insert_or_assign(input_map, std::move(key1), std::move(val)); + // key will not be moved as it already exists + EXPECT_EQ(key1, "u:9002"); + EXPECT_EQ(val, 102); + + // There is no easy way to do this than one of our functions again ;) + expected_map.pop_back(); + expected_map.emplace_back(key1, val); + EXPECT_EQ(input_map, expected_map); + } +} + +TEST(AclCmd, get_iterator) +{ + RuleMap input_map = {{"u:99", 0b011111111111}, + {"u:1001",0b1001}, + {"g:123",0b101}, + {"u:100",0b11}, + {"u:123",0b100} + }; + + { + auto [it, err] = get_iterator(input_map, 1); + EXPECT_EQ(it, input_map.begin()); + } + + { + auto [it, err] = get_iterator(input_map, 6); + EXPECT_EQ(err, EINVAL); + } + + { + auto [it, err] = get_iterator(input_map, 5); + ASSERT_EQ(err, 0); + EXPECT_EQ(it->first,"u:123"); + } +} + +TEST(AclCmd, insert_or_assign_iter) +{ + RuleMap input_map = {{"u:99", 0b011111111111}, + {"u:1001",0b1001}, + {"g:123",0b101}, + {"u:100",0b11}, + {"u:123",0b100} + }; + + { + auto [it, _] = get_iterator(input_map, 1); + insert_or_assign(input_map, "u:9001",0b1010, it); + + RuleMap expected_map = {{"u:9001",0b1010}, + {"u:99", 0b011111111111}, + {"u:1001",0b1001}, + {"g:123",0b101}, + {"u:100",0b11}, + {"u:123",0b100} + }; + + EXPECT_EQ(expected_map, input_map); + } + + { + // No movement of keys as we dont override move_existing + auto [it, _] = get_iterator(input_map, 3); + insert_or_assign(input_map, "u:9001",0b1011, it); + + RuleMap expected_map = {{"u:9001",0b1011}, + {"u:99", 0b011111111111}, + {"u:1001",0b1001}, + {"g:123",0b101}, + {"u:100",0b11}, + {"u:123",0b100} + }; + + EXPECT_EQ(expected_map, input_map); + } + + { + // In this case we move the keys as we are passing true, so we're promoting + // this val up one place + auto [it, _] = get_iterator(input_map, 4); + insert_or_assign(input_map, "u:100",0b11011, it, true); + + RuleMap expected_map = {{"u:9001",0b1011}, + {"u:99", 0b011111111111}, + {"u:1001",0b1001}, + {"u:100",0b11011}, + {"g:123",0b101}, + {"u:123",0b100} + }; + + EXPECT_EQ(expected_map, input_map); + } + { + // we are demoting an element + auto [it, _] = get_iterator(input_map, 5); + insert_or_assign(input_map, "u:99",0b11011, it, true); + + RuleMap expected_map = {{"u:9001",0b1011}, + {"u:1001",0b1001}, + {"u:100",0b11011}, + {"g:123",0b101}, + {"u:99", 0b11011}, + {"u:123",0b100} + }; + + EXPECT_EQ(expected_map, input_map); + + } + { + // we are demoting the first element to the last + auto [it, _] = get_iterator(input_map, 6); + insert_or_assign(input_map, "u:9001",0b10011, it, true); + + RuleMap expected_map = {{"u:1001",0b1001}, + {"u:100",0b11011}, + {"g:123",0b101}, + {"u:99", 0b11011}, + {"u:123",0b100}, + {"u:9001",0b10011} + }; + + EXPECT_EQ(expected_map, input_map); + + } + + { + // we are demoting a middle element to the last + auto [it, _] = get_iterator(input_map, 6); + insert_or_assign(input_map, "u:99",0b11011, it, true); + + RuleMap expected_map = {{"u:1001",0b1001}, + {"u:100",0b11011}, + {"g:123",0b101}, + {"u:123",0b100}, + {"u:9001",0b10011}, + {"u:99", 0b11011} + }; + + EXPECT_EQ(expected_map, input_map); + + } + + { + // we are demoting the penultimate element to the last + auto [it, _] = get_iterator(input_map, 6); + insert_or_assign(input_map, "u:9001",0b10011, it, true); + + RuleMap expected_map = {{"u:1001",0b1001}, + {"u:100",0b11011}, + {"g:123",0b101}, + {"u:123",0b100}, + {"u:99", 0b11011}, + {"u:9001",0b10011} + }; + + EXPECT_EQ(expected_map, input_map); - for (auto const& elem : result_map) { - ASSERT_EQ(elem.second, expect_map[elem.first]); } + } -EOSMGMNAMESPACE_END +TEST(AclCmd, GetRulePosition) +{ + // first arg rule_map_sz, second_arg position + EXPECT_EQ(AclCmd::GetRulePosition(0,0), std::pair(0,0UL)); + EXPECT_EQ(AclCmd::GetRulePosition(0,1), std::pair(0,0UL)); + EXPECT_EQ(AclCmd::GetRulePosition(0,2), std::pair(EINVAL,0UL)); + //no position argument was passed, so position should be 0 + // regardless of map size + + EXPECT_EQ(AclCmd::GetRulePosition(1,0), std::pair(0,0UL)); + EXPECT_EQ(AclCmd::GetRulePosition(10,0), std::pair(0,0UL)); + + // For all the cases where there are acls and we're within boundaries + // we should return the second arg + EXPECT_EQ(AclCmd::GetRulePosition(2,2), std::pair(0,2UL)); + EXPECT_EQ(AclCmd::GetRulePosition(2,1), std::pair(0,1UL)); + EXPECT_EQ(AclCmd::GetRulePosition(8,4), std::pair(0,4UL)); + + // except in case of error + EXPECT_EQ(AclCmd::GetRulePosition(2,3), std::pair(EINVAL,3UL)); +}