diff --git a/src/Makefile.am b/src/Makefile.am index 0de6c18e..d1760ad4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,7 +17,8 @@ noinst_HEADERS = \ fairness/reader/data_reader_db.hpp \ fairness/writer/data_writer_base.hpp \ fairness/writer/data_writer_db.hpp \ - fairness/writer/data_writer_stdout.hpp + fairness/writer/data_writer_stdout.hpp \ + plugins/bank_info.hpp fairness_libweighted_tree_la_SOURCES = \ fairness/account/account.cpp \ @@ -46,7 +47,8 @@ fairness_libweighted_tree_la_CXXFLAGS = \ TESTS = \ weighted_tree_test01.t \ data_reader_db_test01.t \ - data_writer_db_test01.t + data_writer_db_test01.t \ + user_bank_info_test01.t check_PROGRAMS = $(TESTS) TEST_EXTENSIONS = .t @@ -93,6 +95,14 @@ data_writer_db_test01_t_LDADD = \ fairness/libweighted_tree.la \ common/libtap/libtap.la +user_bank_info_test01_t_SOURCES = \ + plugins/test/user_bank_info_test01.cpp \ + plugins/bank_info.cpp \ + plugins/bank_info.hpp +user_bank_info_test01_t_CXXFLAGS = $(AM_CXXFLAGS) -I$(top_srcdir) +user_bank_info_test01_t_LDADD = \ + common/libtap/libtap.la + noinst_PROGRAMS = \ cmd/flux-account-update-fshare \ cmd/flux-account-shares diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index f4ac138c..25789206 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -8,5 +8,6 @@ jobtapdir = \ $(fluxlibdir)/job-manager/plugins/ jobtap_LTLIBRARIES = mf_priority.la -mf_priority_la_SOURCES = mf_priority.cpp +mf_priority_la_SOURCES = mf_priority.cpp bank_info.cpp +mf_priority_la_CPPFLAGS = -I$(top_srcdir)/src/plugins mf_priority_la_LDFLAGS = $(fluxplugin_ldflags) -module diff --git a/src/plugins/bank_info.cpp b/src/plugins/bank_info.cpp new file mode 100644 index 00000000..d4dc3b8e --- /dev/null +++ b/src/plugins/bank_info.cpp @@ -0,0 +1,52 @@ +/************************************************************\ + * Copyright 2023 Lawrence Livermore National Security, LLC + * (c.f. AUTHORS, NOTICE.LLNS, COPYING) + * + * This file is part of the Flux resource manager framework. + * For details, see https://github.com/flux-framework. + * + * SPDX-License-Identifier: LGPL-3.0 +\************************************************************/ + +#include "bank_info.hpp" + +user_bank_info* get_user_info (int userid, + char *bank, + std::map> &users, + std::map &users_def_bank) +{ + std::map::iterator bank_it; + + auto it = users.find (userid); + if (it == users.end ()) + return NULL; + + if (bank != NULL) { + bank_it = it->second.find (std::string (bank)); + if (bank_it == it->second.end ()) + return NULL; + } else { + bank = const_cast (users_def_bank[userid].c_str ()); + bank_it = it->second.find (std::string (bank)); + if (bank_it == it->second.end ()) + return NULL; + } + + return &bank_it->second; +} + + +bool check_map_for_dne_only ( + std::map> &users, + std::map &users_def_bank) +{ + for (const auto& entry : users) { + auto def_bank_it = users_def_bank.find(entry.first); + if (def_bank_it != users_def_bank.end() && + def_bank_it->second != "DNE") + return false; + } + + return true; +} diff --git a/src/plugins/bank_info.hpp b/src/plugins/bank_info.hpp new file mode 100644 index 00000000..cf37314c --- /dev/null +++ b/src/plugins/bank_info.hpp @@ -0,0 +1,52 @@ +/************************************************************\ + * Copyright 2023 Lawrence Livermore National Security, LLC + * (c.f. AUTHORS, NOTICE.LLNS, COPYING) + * + * This file is part of the Flux resource manager framework. + * For details, see https://github.com/flux-framework. + * + * SPDX-License-Identifier: LGPL-3.0 +\************************************************************/ + +// header file for the bank_info class + +#ifndef BANK_INFO_H +#define BANK_INFO_H + +#include +#include +#include +#include + +// all attributes are per-user/bank +class user_bank_info { +public: + std::string bank_name; // name of bank + double fairshare; // fair share value + int max_run_jobs; // max number of running jobs + int cur_run_jobs; // current number of running jobs + int max_active_jobs; // max number of active jobs + int cur_active_jobs; // current number of active jobs + std::vector held_jobs; // list of currently held job ID's + std::vector queues; // list of accessible queues + int queue_factor; // priority factor associated with queue + int active; // active status +}; + +// get a user_bank_info object that points to user/bank +// information in users map; return NULL on failure +user_bank_info* get_user_info (int userid, + char *bank, + std::map> + &users, + std::map &users_def_bank); + +// scan the users map and look at each user's default bank to see if any one +// of them have a valid bank (i.e one that is not "DNE"; if any of the users do +// do have a valid bank, return false) +bool check_map_for_dne_only ( + std::map> &users, + std::map &users_def_bank); + +#endif // BANK_INFO_H diff --git a/src/plugins/mf_priority.cpp b/src/plugins/mf_priority.cpp index f9479bff..4b85d062 100644 --- a/src/plugins/mf_priority.cpp +++ b/src/plugins/mf_priority.cpp @@ -29,6 +29,9 @@ extern "C" { #include #include +// custom bank_info class file +#include "bank_info.hpp" + // the plugin does not know about the association who submitted a job and will // assign default values to the association until it receives information from // flux-accounting @@ -58,24 +61,12 @@ enum bank_info_codes { BANK_NO_DEFAULT }; -typedef std::pair::iterator> bank_info_result; +typedef std::pair::iterator> bank_info_result; -std::map> users; +std::map> users; std::map queues; std::map users_def_bank; -struct bank_info { - double fairshare; - int max_run_jobs; - int cur_run_jobs; - int max_active_jobs; - int cur_active_jobs; - std::vector held_jobs; - std::vector queues; - int queue_factor; - int active; -}; - // min_nodes_per_job, max_nodes_per_job, and max_time_per_job are not // currently used or enforced in this plugin, so their values have no // effect in queue limit enforcement. @@ -112,7 +103,7 @@ int64_t priority_calculation (flux_plugin_t *p, double fshare_factor = 0.0, priority = 0.0; int queue_factor = 0; int fshare_weight, queue_weight; - struct bank_info *b; + user_bank_info *b; fshare_weight = 100000; queue_weight = 10000; @@ -123,7 +114,7 @@ int64_t priority_calculation (flux_plugin_t *p, if (urgency == FLUX_JOB_URGENCY_EXPEDITE) return FLUX_JOB_PRIORITY_MAX; - b = static_cast (flux_jobtap_job_aux_get ( + b = static_cast (flux_jobtap_job_aux_get ( p, FLUX_JOBTAP_CURRENT_JOB, "mf_priority:bank_info")); @@ -149,9 +140,8 @@ int64_t priority_calculation (flux_plugin_t *p, } -static int get_queue_info ( - char *queue, - std::map::iterator bank_it) +static int get_queue_info (char *queue, + std::vector permissible_queues) { std::map::iterator q_it; @@ -168,10 +158,10 @@ static int get_queue_info ( // check #2) the queue passed in is a valid option to pass for user std::vector::iterator vect_it; - vect_it = std::find (bank_it->second.queues.begin (), - bank_it->second.queues.end (), queue); + vect_it = std::find (permissible_queues.begin (), + permissible_queues.end (), queue); - if (vect_it == bank_it->second.queues.end ()) + if (vect_it == permissible_queues.end ()) return INVALID_QUEUE; else // add priority associated with the passed in queue to bank_info @@ -183,7 +173,7 @@ static int get_queue_info ( } -static void split_string (char *queues, struct bank_info *b) +static void split_string (char *queues, user_bank_info *b) { std::stringstream s_stream; @@ -217,7 +207,7 @@ int check_queue_factor (flux_plugin_t *p, * Add held job IDs to a JSON array to be added to a bank_info JSON object. */ static json_t *add_held_jobs ( - const std::pair &b) + const std::pair &b) { json_t *held_jobs = NULL; @@ -248,7 +238,7 @@ static json_t *add_held_jobs ( * Create a JSON object for a bank that a user belongs to. */ static json_t *pack_bank_info_object ( - const std::pair &b) + const std::pair &b) { json_t *bank_info, *held_jobs = NULL; @@ -281,7 +271,7 @@ static json_t *pack_bank_info_object ( */ static json_t *banks_to_json ( flux_plugin_t *p, - std::pair> &u) + std::pair> &u) { json_t *bank_info, *banks = NULL; @@ -313,7 +303,7 @@ static json_t *banks_to_json ( */ static json_t *user_to_json ( flux_plugin_t *p, - std::pair> u) + std::pair> u) { json_t *user = json_object (); // JSON object for one user json_t *userid, *banks = NULL; @@ -346,25 +336,6 @@ static json_t *user_to_json ( } -// Scan the users map and look at each user's default bank to see if any one -// of them have a valid bank (i.e one that is not "DNE"; if any of the users do -// do have a valid bank, it will return false) -static bool check_map_for_dne_only () -{ - // the users map iterated through in this for-loop, along with the - // users_def_bank map used to look up a user's default bank, are - // both global variables - for (const auto& entry : users) { - auto def_bank_it = users_def_bank.find(entry.first); - if (def_bank_it != users_def_bank.end() && - def_bank_it->second != "DNE") - return false; - } - - return true; -} - - /* * Update the jobspec with the default bank the association used to * submit their job under. @@ -372,7 +343,7 @@ static bool check_map_for_dne_only () static int update_jobspec_bank (flux_plugin_t *p, int userid) { char *bank = NULL; - std::map>::iterator it; + std::map>::iterator it; it = users.find (userid); if (it == users.end ()) { @@ -400,8 +371,8 @@ static int update_jobspec_bank (flux_plugin_t *p, int userid) // associated with the submitted job static bank_info_result get_bank_info (int userid, char *bank) { - std::map>::iterator it; - std::map::iterator bank_it; + std::map>::iterator it; + std::map::iterator bank_it; it = users.find (userid); if (it == users.end ()) { @@ -478,7 +449,7 @@ static int query_cb (flux_plugin_t *p, * Unpack a payload from an external bulk update service and place it in the * multimap datastructure. */ -static void rec_update_cb (flux_t *h, +static void rec_update_cb(flux_t *h, flux_msg_handler_t *mh, const flux_msg_t *msg, void *arg) @@ -521,9 +492,10 @@ static void rec_update_cb (flux_t *h, "active", &active) < 0) flux_log (h, LOG_ERR, "mf_priority unpack: %s", error.text); - struct bank_info *b; + user_bank_info *b; b = &users[uid][bank]; + b->bank_name = bank; b->fairshare = fshare; b->max_run_jobs = max_running_jobs; b->max_active_jobs = max_active_jobs; @@ -631,7 +603,7 @@ static int priority_cb (flux_plugin_t *p, char *bank = NULL; char *queue = NULL; int64_t priority; - struct bank_info *b; + user_bank_info *b; flux_t *h = flux_jobtap_get_flux (p); if (flux_plugin_arg_unpack (args, @@ -648,7 +620,7 @@ static int priority_cb (flux_plugin_t *p, return -1; } - b = static_cast (flux_jobtap_job_aux_get ( + b = static_cast (flux_jobtap_job_aux_get ( p, FLUX_JOBTAP_CURRENT_JOB, "mf_priority:bank_info")); @@ -660,13 +632,14 @@ static int priority_cb (flux_plugin_t *p, return -1; } - std::map>::iterator it; - std::map::iterator bank_it; + std::map>::iterator it; + std::map::iterator bank_it; if (b->max_run_jobs == BANK_INFO_MISSING) { // try to look up user again it = users.find (userid); - if (it == users.end () || check_map_for_dne_only () == true) { + if (it == users.end () || + check_map_for_dne_only (users, users_def_bank) == true) { // the plugin could still be waiting on flux-accounting data // to be loaded in; keep the job in PRIORITY state return flux_jobtap_priority_unavail (p, args); @@ -698,7 +671,9 @@ static int priority_cb (flux_plugin_t *p, } // fetch priority associated with passed-in queue (or default queue) - bank_it->second.queue_factor = get_queue_info (queue, bank_it); + bank_it->second.queue_factor = get_queue_info ( + queue, + bank_it->second.queues); if (check_queue_factor (p, bank_it->second.queue_factor, queue) < 0) @@ -750,11 +725,12 @@ static int priority_cb (flux_plugin_t *p, static void add_missing_bank_info (flux_plugin_t *p, flux_t *h, int userid) { - struct bank_info *b; + user_bank_info *b; b = &users[userid]["DNE"]; users_def_bank[userid] = "DNE"; + b->bank_name = "DNE"; b->fairshare = 0.1; b->max_run_jobs = BANK_INFO_MISSING; b->cur_run_jobs = 0; @@ -773,9 +749,21 @@ static void add_missing_bank_info (flux_plugin_t *p, flux_t *h, int userid) /* - * Look up the userid of the submitted job in the multimap; if user is not found - * in the map, reject the job saying the user wasn't found in the - * flux-accounting database. + * Perform basic validation of a user/bank's submitted job. If a bank or + * queue is specified on submission, ensure that the user is allowed to + * submit a job under them. Check the active job limits for the user/bank + * on submission as well to make sure that they are under this limit when + * the job is submitted. + * + * This callback will also make sure that the user/bank belongs to + * the flux-accounting DB; there are two behaviors supported here: + * + * if the plugin has SOME data about users/banks and the user does not have + * an entry in the plugin, the job will be rejected. + * + * if the plugin has NO data about users/banks and the user does not have an + * entry in the plugin, the job will be held until data is received by the + * plugin. */ static int validate_cb (flux_plugin_t *p, const char *topic, @@ -786,14 +774,12 @@ static int validate_cb (flux_plugin_t *p, char *bank = NULL; char *queue = NULL; flux_job_state_t state; - int max_run_jobs, cur_active_jobs, max_active_jobs, queue_factor = 0; - double fairshare = 0.0; + int cur_active_jobs, max_active_jobs = 0; bool only_dne_data; + user_bank_info *user_bank; - std::map>::iterator it; - std::map::iterator bank_it; - std::map::iterator q_it; - + // unpack the attributes of the user/bank's submitted job when it + // enters job.validate and place them into their respective variables flux_t *h = flux_jobtap_get_flux (p); if (flux_plugin_arg_unpack (args, FLUX_PLUGIN_ARG_IN, @@ -805,67 +791,45 @@ static int validate_cb (flux_plugin_t *p, return flux_jobtap_reject_job (p, args, "unable to unpack bank arg"); } - // make sure user belongs to flux-accounting DB; there are two behaviors - // supported in this plugin: - // - // if the plugin has SOME data about users/banks and the user does not - // have an entry in the plugin, the job will be rejected. - // - // if the plugin has NO data about users/banks and the user does not have - // an entry in the plugin, the job will be held until data is received by - // the plugin. - it = users.find (userid); - if (it == users.end ()) { - // check if the map only contains DNE entries - bool only_dne_data = check_map_for_dne_only (); + // perform a lookup in the users map of the unpacked user/bank + user_bank = get_user_info (userid, bank, users, users_def_bank); + + if (user_bank == NULL) { + // the user/bank could not be found in the plugin's internal map, + // so perform a check to see if the map has any loaded + // flux-accounting data before rejecting the job + bool only_dne_data = check_map_for_dne_only (users, users_def_bank); if (users.empty () || only_dne_data) { add_missing_bank_info (p, h, userid); return 0; } else { - return flux_jobtap_reject_job (p, args, - "no bank found for user: %i", userid); + return flux_jobtap_reject_job (p, + args, + "cannot find user/bank or " + "user/default bank entry " + "for: %i", userid); } } - // make sure user belongs to bank they specified; if no bank was passed in, - // look up their default bank - if (bank != NULL) { - bank_it = it->second.find (std::string (bank)); - if (bank_it == it->second.end ()) - return flux_jobtap_reject_job (p, args, - "user does not belong to specified bank"); - } else { - bank = const_cast (users_def_bank[userid].c_str ()); - bank_it = it->second.find (std::string (bank)); - if (bank_it == it->second.end ()) - return flux_jobtap_reject_job (p, args, - "user/default bank entry does not exist"); - } - - // if user/bank entry was disabled, reject job with a message saying the - // entry has been disabled - if (bank_it->second.active == 0) + if (user_bank->active == 0) + // the user/bank entry was disabled; reject the job return flux_jobtap_reject_job (p, args, "user/bank entry has been " "disabled from flux-accounting DB"); - // validate the queue if one is passed in; if the user does not have access - // to the queue they specified, reject the job - queue_factor = get_queue_info (queue, bank_it); - - if (queue_factor == INVALID_QUEUE) + if (get_queue_info (queue, user_bank->queues) == INVALID_QUEUE) + // the user/bank specified a queue that they do not belong to; + // reject the job return flux_jobtap_reject_job (p, args, "Queue not valid for user: %s", queue); - max_run_jobs = bank_it->second.max_run_jobs; - fairshare = bank_it->second.fairshare; - cur_active_jobs = bank_it->second.cur_active_jobs; - max_active_jobs = bank_it->second.max_active_jobs; + cur_active_jobs = user_bank->cur_active_jobs; + max_active_jobs = user_bank->max_active_jobs; - // if a user/bank has reached their max_active_jobs limit, subsequently - // submitted jobs will be rejected if (state == FLUX_JOB_STATE_NEW) { if (max_active_jobs > 0 && cur_active_jobs >= max_active_jobs) + // the user/bank is already at their max_active_jobs limit; + // reject the job return flux_jobtap_reject_job (p, args, "user has max active jobs"); @@ -885,10 +849,10 @@ static int new_cb (flux_plugin_t *p, char *queue = NULL; int max_run_jobs, cur_active_jobs, max_active_jobs = 0; double fairshare = 0.0; - struct bank_info *b; + user_bank_info *b; - std::map>::iterator it; - std::map::iterator bank_it; + std::map>::iterator it; + std::map::iterator bank_it; flux_t *h = flux_jobtap_get_flux (p); if (flux_plugin_arg_unpack (args, @@ -900,7 +864,7 @@ static int new_cb (flux_plugin_t *p, return flux_jobtap_reject_job (p, args, "unable to unpack bank arg"); } - b = static_cast (flux_jobtap_job_aux_get ( + b = static_cast (flux_jobtap_job_aux_get ( p, FLUX_JOBTAP_CURRENT_JOB, "mf_priority:bank_info")); @@ -961,7 +925,7 @@ static int new_cb (flux_plugin_t *p, // assign priority associated with validated queue to bank_info struct // associated with job - b->queue_factor = get_queue_info (queue, bank_it); + b->queue_factor = get_queue_info (queue, b->queues); // if a user/bank has reached their max_active_jobs limit, subsequently // submitted jobs will be rejected @@ -1002,7 +966,7 @@ static int depend_cb (flux_plugin_t *p, { int userid; long int id; - struct bank_info *b; + user_bank_info *b; flux_t *h = flux_jobtap_get_flux (p); if (flux_plugin_arg_unpack (args, @@ -1016,7 +980,7 @@ static int depend_cb (flux_plugin_t *p, return -1; } - b = static_cast (flux_jobtap_job_aux_get ( + b = static_cast (flux_jobtap_job_aux_get ( p, FLUX_JOBTAP_CURRENT_JOB, "mf_priority:bank_info")); @@ -1054,9 +1018,9 @@ static int run_cb (flux_plugin_t *p, void *data) { int userid; - struct bank_info *b; + user_bank_info *b; - b = static_cast + b = static_cast (flux_jobtap_job_aux_get (p, FLUX_JOBTAP_CURRENT_JOB, "mf_priority:bank_info")); @@ -1085,11 +1049,11 @@ static int job_updated (flux_plugin_t *p, flux_plugin_arg_t *args, void *data) { - std::map::iterator bank_it; + std::map::iterator bank_it; int userid; char *bank = NULL; char *queue = NULL; - struct bank_info *b; + user_bank_info *b; if (flux_plugin_arg_unpack (args, FLUX_PLUGIN_ARG_IN, @@ -1101,7 +1065,7 @@ static int job_updated (flux_plugin_t *p, return flux_jobtap_error (p, args, "unable to unpack plugin args"); // grab bank_info struct for user/bank (if any) - b = static_cast (flux_jobtap_job_aux_get ( + b = static_cast (flux_jobtap_job_aux_get ( p, FLUX_JOBTAP_CURRENT_JOB, "mf_priority:bank_info")); @@ -1138,7 +1102,7 @@ static int job_updated (flux_plugin_t *p, // if the queue for the job has been updated, fetch the priority of the // validated queue and assign it to the associated bank_info struct if (queue != NULL) { - int queue_factor = get_queue_info (queue, bank_it); + int queue_factor = get_queue_info (queue, bank_it->second.queues); b->queue_factor = queue_factor; } @@ -1156,7 +1120,7 @@ static int update_queue_cb (flux_plugin_t *p, flux_plugin_arg_t *args, void *data) { - std::map::iterator bank_it; + std::map::iterator bank_it; int userid; char *bank = NULL; char *queue = NULL; @@ -1193,7 +1157,7 @@ static int update_queue_cb (flux_plugin_t *p, // validate the updated queue and make sure the user/bank has // access to it; if not, reject the update - if (get_queue_info (queue, bank_it) == INVALID_QUEUE) + if (get_queue_info (queue, bank_it->second.queues) == INVALID_QUEUE) return flux_jobtap_error (p, args, "mf_priority: queue not valid for user: %s", @@ -1210,9 +1174,9 @@ static int inactive_cb (flux_plugin_t *p, void *data) { int userid; - struct bank_info *b; - std::map>::iterator it; - std::map::iterator bank_it; + user_bank_info *b; + std::map>::iterator it; + std::map::iterator bank_it; flux_t *h = flux_jobtap_get_flux (p); if (flux_plugin_arg_unpack (args, @@ -1226,7 +1190,7 @@ static int inactive_cb (flux_plugin_t *p, return -1; } - b = static_cast (flux_jobtap_job_aux_get ( + b = static_cast (flux_jobtap_job_aux_get ( p, FLUX_JOBTAP_CURRENT_JOB, "mf_priority:bank_info")); diff --git a/src/plugins/test/user_bank_info_test01.cpp b/src/plugins/test/user_bank_info_test01.cpp new file mode 100644 index 00000000..0306bc0c --- /dev/null +++ b/src/plugins/test/user_bank_info_test01.cpp @@ -0,0 +1,205 @@ +/************************************************************\ + * Copyright 2023 Lawrence Livermore National Security, LLC + * (c.f. AUTHORS, NOTICE.LLNS, COPYING) + * + * This file is part of the Flux resource manager framework. + * For details, see https://github.com/flux-framework. + * + * SPDX-License-Identifier: LGPL-3.0 +\************************************************************/ + +extern "C" { +#if HAVE_CONFIG_H +#include "config.h" +#endif +} + +#include +#include +#include +#include +#include + +#include "src/plugins/bank_info.hpp" +#include "src/common/libtap/tap.h" + +// define a test users map to run tests on +std::map> users; +std::map users_def_bank; + + +/* + * helper function to add a user/bank to the users map + */ +void add_user_to_map ( + std::map> &users, + int userid, + const std::string& bank, + user_bank_info user_bank) +{ + // insert user to users map + users[userid][bank] = { + user_bank.bank_name, + user_bank.fairshare, + user_bank.max_run_jobs, + user_bank.cur_run_jobs, + user_bank.max_active_jobs, + user_bank.cur_active_jobs, + user_bank.held_jobs, + user_bank.queues, + user_bank.queue_factor, + user_bank.active + }; +} + + +/* + * helper function to add a user/bank to the default bank map + */ +void add_user_to_def_bank_map (std::map &users_def_bank, + int userid, + const std::string& bank) +{ + users_def_bank[userid] = bank; +} + + +/* + * helper function to add test users to the users map + */ +void initialize_map ( + std::map> &users) +{ + user_bank_info user1 = {"bank_A", 0.5, 5, 0, 7, 0, {}, {}, 0, 1}; + user_bank_info user2 = {"bank_A", 0.5, 5, 0, 7, 0, {}, {}, 0, 1}; + + add_user_to_map (users, 1001, "bank_A", user1); + add_user_to_def_bank_map (users_def_bank, 1001, "bank_A"); + + // purposely do not add user2 to the def_bank_map + add_user_to_map (users, 1002, "bank_A", user2); +} + + +/* + * helper function to add special "does not exist" ("DNE") user/bank info to + * the plugin; this simulates a scenario where the plugin is waiting on + * user/bank information to be loaded from the flux-accounting DB + */ +void initialize_map_dne_only ( + std::map> &users) +{ + user_bank_info user1 = {"DNE", 0.5, 5, 0, 7, 0, {}, {}, 0, 1}; + user_bank_info user2 = {"DNE", 0.5, 5, 0, 7, 0, {}, {}, 0, 1}; + + add_user_to_map (users, 1001, "DNE", user1); + add_user_to_def_bank_map (users_def_bank, 1001, "DNE"); + + add_user_to_map (users, 1002, "DNE", user2); + add_user_to_def_bank_map (users_def_bank, 1001, "DNE"); +} + + +static void test_basic_string_comparison () +{ + const std::string string1 = "hello, world!"; + const std::string string2 = "hello, world!"; + + ok (string1 == string2, "i can perform a basic string comparison test"); +} + + +// ensure we can access a user/bank in the users map +static void test_direct_map_access ( + std::map> &users) +{ + ok (users[1001]["bank_A"].bank_name == "bank_A", + "a user/bank from users map can be accessed directly"); +} + + +// ensure the user_bank_info object is returned when a user/map +// exists in the map +static void test_get_user_info_success () +{ + // retrieve user_bank_info object + user_bank_info *user1 = get_user_info (1001, + const_cast ("bank_A"), + users, + users_def_bank); + ok (user1->bank_name == "bank_A", + "get_user_info () returns a pointer to a user_bank_info object " + "on success"); +} + + +// ensure NULL is returned when a user cannot be found in the map +static void test_get_user_info_user_noexist () +{ + user_bank_info *user_foo = get_user_info (9999, + const_cast ("bank_A"), + users, + users_def_bank); + ok (user_foo == NULL, + "get_user_info () returns NULL when a user/bank cannot be found"); +} + + +// ensure NULL is returned when a user does not have a default bank +static void test_get_user_info_user_no_default_bank () +{ + user_bank_info *user2 = get_user_info (1002, NULL, users, users_def_bank); + ok (user2 == NULL, + "get_user_info () returns NULL when a user does not have " + "a default bank"); +} + + +// ensure check_map_for_dne_only () will return false since both maps that +// store user/bank information have valid entries +static void test_check_map_valid_entries () +{ + bool only_dne_data = check_map_for_dne_only (users, users_def_bank); + ok (only_dne_data == false, "maps have valid user/bank data"); +} + + +// clear the map and only put temporary "does not exist" ("DNE") data in both +// maps and re-run the check +static void test_check_map_only_dne_entries () +{ + users.clear (); + users_def_bank.clear (); + + initialize_map_dne_only (users); + + bool only_dne_data = check_map_for_dne_only (users, users_def_bank); + ok (only_dne_data == true, "maps have only 'DNE' user/bank data"); +} + + +int main (int argc, char* argv[]) +{ + // declare the number of tests that we plan to run + plan (7); + + // add users to the test map + initialize_map (users); + + test_basic_string_comparison (); + test_direct_map_access (users); + test_get_user_info_success (); + test_get_user_info_user_noexist (); + test_get_user_info_user_no_default_bank (); + test_check_map_valid_entries (); + test_check_map_only_dne_entries (); + + // indicate we are done testing + done_testing (); + + return EXIT_SUCCESS; +} + +/* + * vi:tabstop=4 shiftwidth=4 expandtab + */ diff --git a/t/t1001-mf-priority-basic.t b/t/t1001-mf-priority-basic.t index 85a1f55e..aef20211 100755 --- a/t/t1001-mf-priority-basic.t +++ b/t/t1001-mf-priority-basic.t @@ -147,7 +147,7 @@ test_expect_success 'submit a job using default bank' ' test_expect_success 'submit a job using a bank the user does not belong to' ' test_must_fail flux submit --setattr=system.bank=account1 -n1 hostname > bad_bank.out 2>&1 && test_debug "cat bad_bank.out" && - grep "user does not belong to specified bank" bad_bank.out + grep "cannot find user/bank or user/default bank entry for:" bad_bank.out ' test_expect_success 'reject job when invalid bank format is passed in' ' diff --git a/t/t1022-mf-priority-issue346.t b/t/t1022-mf-priority-issue346.t index 5443c0f4..163ae4b3 100755 --- a/t/t1022-mf-priority-issue346.t +++ b/t/t1022-mf-priority-issue346.t @@ -66,7 +66,7 @@ test_expect_success 'cancel job' ' test_expect_success 'submit a job to plugin while not having an entry in the plugin' ' test_must_fail flux python ${SUBMIT_AS} 1003 hostname > no_user_entry.out 2>&1 && - grep "no bank found for user" no_user_entry.out + grep "cannot find user/bank or user/default bank entry for:" no_user_entry.out ' test_expect_success 'shut down flux-accounting service' ' diff --git a/t/t1028-mf-priority-issue385.t b/t/t1028-mf-priority-issue385.t index 6b2ccf90..1664ac96 100755 --- a/t/t1028-mf-priority-issue385.t +++ b/t/t1028-mf-priority-issue385.t @@ -54,7 +54,7 @@ test_expect_success 'check that jobs transition to RUN' ' test_expect_success 'submitting a job under invalid user while plugin has data fails' ' test_must_fail flux python ${SUBMIT_AS} 9999 hostname > invalid_user.out 2>&1 && test_debug "cat invalid_user.out" && - grep "flux-job: no bank found for user: 9999" invalid_user.out + grep "cannot find user/bank or user/default bank entry for: 9999" invalid_user.out ' test_expect_success 'cancel running jobs' '