No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cbl.sh 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. #!/bin/bash
  2. #
  3. #
  4. # This file is part of Lodel 2 (https://github.com/OpenEdition)
  5. #
  6. # Copyright (C) 2015-2017 Cléo UMS-3287
  7. #
  8. # This program is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU Affero General Public License as published
  10. # by the Free Software Foundation, either version 3 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU Affero General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU Affero General Public License
  19. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. #
  21. # CBL : Curl Benchmark on Lodel
  22. #
  23. # Usage : $0 [HOSTNAME] [INSTANCE_LIST_FILE] [N_CREATE] [N_EDIT] [N_DELETE]
  24. #
  25. # Instance_list_file is expected to be a file containing instances name (1 per
  26. # line). Uses by default /tmp/lodel2_instance_list.txt
  27. #
  28. # Instances base URL are generated given the current webui implementation :
  29. # http://HOST/INSTANCE_NAME/
  30. #
  31. #
  32. # Scenario description :
  33. #
  34. # mass_creation instance_name iteration_count :
  35. # Create iteration_count time a random leobject in given instance_name
  36. # note : do note create relation between objects, only populate content
  37. #
  38. # step 1 : fetch all non abstract class name
  39. # step 2 : loop on creation (using bash function curl_opt_create_CLSNAME)
  40. # that return the POST fields (populated with random values)
  41. #
  42. # mass_get instance_name :
  43. # Create all possible get for an instance
  44. # step 1 : fetch all classes
  45. # step 2 : for each class fetch all id
  46. # step 3 : for all ids generate the gets
  47. #
  48. # mass_deletion instance_name iteration_count :
  49. # Foreach non asbtracty class delete iteration_count time an object of
  50. # current class in current instance
  51. #
  52. # step 1 : fetch all non abstract class name
  53. # step 2 : loop on non abstract class name
  54. # step 3 : loop iteration_count time on deletion
  55. #
  56. # mass_link_edit instance_name iteration_count :
  57. # Foreach non abstract class make iteration_count time edition of an
  58. # object in current class
  59. # note : only implemented for Person for the moment
  60. # note : can maybe ask for invalid modifications
  61. #
  62. # step 1 : fetch all non abstract class name
  63. # step 2 : loop on non abstract class name
  64. # step 3 : depends on curent class :
  65. # - fetch all existing id of current class
  66. # - fetch all existing id in class that can be linked with
  67. # current class
  68. # step 4 : loop iteration_count time :
  69. # - choose a random id in current class
  70. # - choose random ids from linkable classes
  71. # - trigger edition using curl (with datas from the same
  72. # bash function than creation : curl_opt_create_CLSNAME)
  73. #
  74. # Current way to run scenarios :
  75. #
  76. # using the function run_bg_with_param FUNCTION_NAME INSTANCE_LIST_FILE *ARGS
  77. #
  78. # The function name can be one of the scenario functions
  79. # INSTANCE_LIST_FILE is the file containing instances list
  80. # *ARGS are args given as it to FUNCTION_NAME after the instance_name argument
  81. #
  82. # function call : FUN_NAME INSTANCE_NAME *ARGS
  83. #
  84. # The run_bg_with_param run a scenario in background for each instance allowing
  85. # to send a lot of request at the same time
  86. #
  87. #
  88. usage() {
  89. echo "Usage : $0 [HOSTNAME] [INSTANCE_LIST_FILE] [CREATE_COUNT] [EDIT_COUNT] [DELETE_COUNT]"
  90. exit
  91. }
  92. host=$1
  93. host=${host:=localhost}
  94. instance_list=$2
  95. instance_list=${instance_list:=/tmp/lodel2_instance_list.txt}
  96. #A modifier for requests count
  97. n_create=$3
  98. n_create=${n_create:=50}
  99. n_edit=$4
  100. n_edit=${n_edit:=10}
  101. n_delete=$5
  102. n_delete=${n_delete:=10}
  103. for i in $(seq $#)
  104. do
  105. echo $1 |grep -E "^-?-h" &>/dev/null
  106. shift
  107. done
  108. #curl_options='--silent -o /dev/null -s -w %{http_code}:%{time_connect}:%{time_starttransfer}:%{time_total}\n'
  109. curl_options='--silent -o /dev/null -s -w %{url_effective};%{http_code};%{time_connect};%{time_starttransfer};%{time_total}\n'
  110. curl_debug_opt='-v -w %{url_effective};%{http_code};%{time_connect};%{time_starttransfer};%{time_total}\n'
  111. curl_cmd="curl $curl_options"
  112. curl_raw="curl --silent"
  113. curl_debug="curl $curl_debug_opt"
  114. curcurl="$curl_cmd"
  115. cmktemp="mktemp -t lodel2_cbl_XXXXXXXX"
  116. _base_uri() {
  117. echo -n "http://$host/$1"
  118. }
  119. rnd_str() {
  120. len=$1
  121. cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $len | head -n 1
  122. }
  123. rnd_str_len() {
  124. minlen=$1
  125. maxlen=$2
  126. cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $(shuf -i${minlen}-${maxlen} -n1) | head -n 1
  127. }
  128. mass_creation() {
  129. #mass creation scenario
  130. #$1 is instance name
  131. #$2 is iteration count (1 iteration is 1 creation of a random class)
  132. instance_name=$1
  133. iteration_count=$2
  134. base_uri=$(_base_uri $1)
  135. cls_list_file=$(fetch_all_classes $1)
  136. if [ -z "$(cat $cls_list_file)" ]
  137. then
  138. echo "Failed to fetch class list for instance $1. Abording..." >&2
  139. exit
  140. fi
  141. if [ "$iteration_count" -le "0" ]
  142. then
  143. return
  144. fi
  145. for i in $(seq $iteration_count)
  146. do
  147. cls=$(shuf -n1 $cls_list_file)
  148. echo "${base_uri}$(uri_create $cls) POST $(curl_opt_create_$cls)"
  149. done
  150. rm -v $cls_list_file >&2
  151. }
  152. mass_get() {
  153. #mass get scenario
  154. #$1 is instance name
  155. cls_list_file=$(fetch_all_classes $1)
  156. base_uri=$(_base_uri $1)
  157. #Get the site root
  158. echo "$base_uri/"
  159. #Get the site class list
  160. echo "$base_uri/list_classes"
  161. for clsname in $(cat $cls_list_file)
  162. do
  163. #Get instances list for a class
  164. echo "$base_uri/show_class?classname=$clsname"
  165. ids_file=$(fetch_all_ids $1 $clsname)
  166. for id in $(cat $ids_file)
  167. do
  168. #Get details on an instance
  169. echo "$base_uri/show_object_detailled?classname=${clsname}&lodel_id=$id"
  170. #Get base informations on an instance
  171. echo "$base_uri/show_object?classname=${clsname}&lodel_id=$id"
  172. done
  173. done
  174. }
  175. mass_link_edit() {
  176. #mass linking & edition scenarion
  177. #$1 is instance name
  178. #$2 is iteration count
  179. instance_name=$1
  180. iteration_count=$2
  181. base_uri=$(_base_uri $1)
  182. cls_list_file=$(fetch_all_classes $1)
  183. for cls in $(cat $cls_list_file)
  184. do
  185. case $cls in
  186. Person)
  187. person_ids=$(fetch_all_ids $1 Person)
  188. section_ids=$(fetch_all_ids $1 Section)
  189. subsection_ids=$(fetch_all_ids $1 Subsection)
  190. text_ids=$($cmktemp)
  191. cat $section_ids $subsection_ids | shuf > $text_ids
  192. for i in $(seq $iteration_count)
  193. do
  194. cur_id=$(shuf -n1 $person_ids)
  195. alias_count=$(shuf -i1-5 -n1)
  196. ltext_count=$(shuf -i1-5 -n1)
  197. alias_param=$(head -n $(expr $alias_count \* $i) $person_ids| tail -n$alias_count|tr -s "\n" "," | sed 's/,$//')
  198. txt_param=$(head -n $(expr $ltext_count \* $i) $text_ids | tail -n$ltext_count|tr -s "\n" "," | sed 's/,$//')
  199. echo "$base_uri/admin/update?classname=$cls&lodel_id=$cur_id POST $(curl_opt_create_$cls $alias_param $txt_param)&uid=$cur_id"
  200. done
  201. rm -v $text_ids $person_ids $section_ids $subsection_ids >&2
  202. ;;
  203. Collection)
  204. collections_ids=$(fetch_all_ids $1 Collection)
  205. publication_ids=$(fetch_all_ids $1 Publication)
  206. for i in $(seq $iteration_count)
  207. do
  208. cur_id=$(shuf -n1 $collections_ids)
  209. publications_count=$(shuf -i1-5 -n1)
  210. publication_param=$(head -n $(expr $publications_count \* $i) $publication_ids| tail -n$publications_count|tr -s "\n" ",")
  211. echo "$base_uri/admin/update?classname=$cls&lodel_id=$cur_id POST $(curl_opt_create_$cls $publication_param)&uid=$cur_id"
  212. done
  213. rm -v $collections_ids $publication_ids >&2
  214. ;;
  215. Publication)
  216. publication_ids=$(fetch_all_ids $1 Publication)
  217. collection_ids=$(fetch_all_ids $1 Collection)
  218. for i in $(seq $iteration_count)
  219. do
  220. cur_id=$(shuf -n1 $publication_ids)
  221. collections_count=$(shuf -i1-5 -n1)
  222. collection_param=$(head -n $(expr $collections_count \* $i) $collection_ids| tail -n$collections_count|tr -s "\n" ",")
  223. echo "$base_uri/admin.update?classname=$cls&lodel_id=$cur_id POST $(curl_opt_create_$cls $collection_param)&uid=$cur_id"
  224. done
  225. rm -v $publication_ids $collection_ids >&2
  226. ;;
  227. Section)
  228. section_ids=$(fetch_all_ids $1 Section)
  229. child_ids=$(fetch_all_ids $1 Subsection)
  230. person_ids=$(fetch_all_ids $1 Person)
  231. for i in $(seq $iteration_count)
  232. do
  233. cur_id=$(shuf -n1 $section_ids)
  234. child_count=$(shuf -i1-5 -n1)
  235. person_count=$(shuf -i1-5 -n1)
  236. child_param=$(head -n $(expr $child_count \* $i) $child_ids| tail -n$child_count|tr -s "\n" ",")
  237. person_param=$(head -n $(expr $person_count \* $i) $person_ids| tail -n$person_count|tr -s "\n" ",")
  238. echo "$base_uri/admin/update?classname=$cls&lodel_id=$cur_id POST $(curl_opt_create_$cls $child_param $person_param)&uid=$cur_id"
  239. done
  240. rm -v $section_ids $child_ids $person_ids >&2
  241. ;;
  242. Subsection)
  243. subsection_ids=$(fetch_all_ids $1 Subsection)
  244. section_ids=$(fetch_all_ids $1 Section)
  245. persons_ids=$(fetch_all_ids $1 Person)
  246. parent_ids=$($cmktemp)
  247. cat $section_ids $subsection_ids | shuf > $parent_ids
  248. child_ids=$subsection_ids
  249. for i in $(seq $iteration_count)
  250. do
  251. cur_id=$(shuf -n1 $subsection_ids)
  252. child_count=$(shuf -i1-5 -n1)
  253. parent_count=$(shuf -i1-5 -n1)
  254. person_count=$(shuf -i1-5 -n1)
  255. child_param=$(head -n $(expr $child_count \* $i) $child_ids| tail -n$child_count|tr -s "\n" ",")
  256. parent_param=$(head -n $(expr $parent_count \* $i) $parent_ids| tail -n$parent_count|tr -s "\n" ",")
  257. person_param=$(head -n $(expr $person_count \* $i) $persons_ids| tail -n$person_count|tr -s "\n" ",")
  258. echo "$base_uri/admin/update?classname=$cls&lodel_id=$cur_id POST $(curl_opt_create_$cls $child_param $person_param $parent_param)&uid=$cur_id"
  259. done
  260. rm -v $subsection_ids $parent_ids $section_ids $persons_ids >&2
  261. ;;
  262. *)
  263. ;;
  264. esac
  265. done
  266. rm -v $cls_list_file >&2
  267. }
  268. mass_deletion() {
  269. #mass deletion scenario
  270. #$1 is instance name
  271. #$2 number of deletion per classes !
  272. instance_name=$1
  273. iteration_count=$2
  274. base_uri=$(_base_uri $1)
  275. cls_list_file=$(fetch_all_classes $1)
  276. for cls in $(cat $cls_list_file)
  277. do
  278. id_list_file=$(fetch_all_ids $1 $cls)
  279. if [ "$iteration_count" -gt "$(wc -l $id_list_file | cut -d " " -f1)" ]
  280. then
  281. max_iter=$(wc -l $id_list_file | cut -d " " -f1)
  282. else
  283. max_iter="$iteration_count"
  284. fi
  285. for i in $(seq $max_iter)
  286. do
  287. id=$(tail -n $i $id_list_file | head -n1)
  288. echo "${base_uri}/admin/delete?classname=$cls&lodel_id=$id"
  289. done
  290. rm -v $id_list_file >&2
  291. done
  292. rm -v $cls_list_file >&2
  293. }
  294. fetch_all_classes() {
  295. #$1 is intance name
  296. cls_list_file=$($cmktemp)
  297. $curl_raw "$(_base_uri $1)/list_classes" | grep -v Abstract |sed -nE 's/^ *<li> +<a href="show_class([^"]+)".*$/\1/p'|cut -d"=" -f2 > $cls_list_file
  298. if [ -z "$(cat $cls_list_file)" ]
  299. then
  300. echo "Unable to fetch class list for $1" >&2
  301. echo "Request was : $curl_raw '$(_base_uri $1)/list_classes'" >&2
  302. rm $cls_list_file >&2
  303. exit 1
  304. fi
  305. echo $cls_list_file
  306. }
  307. fetch_all_ids() {
  308. # Fetch all ids of a class in an instance and shuffle them
  309. instance_name=$1
  310. classname=$2
  311. idfile=$($cmktemp)
  312. $curl_raw "$(_base_uri $1)/show_class?classname=$2" | sed -nE 's/^.*<li><a href="[^=]+=[^=]+=([0-9]+)".*$/\1/p' |shuf > $idfile
  313. echo $idfile
  314. }
  315. uri_create() {
  316. clsname=$1
  317. echo -n "/admin/create?classname=$1"
  318. }
  319. curl_opt_create_Person() {
  320. #$1 is alias id
  321. #$2 is linked_texts id (comma separated)
  322. echo "field_input_lastname=$(rnd_str_len 10 20)&field_input_firstname=$(rnd_str_len 10 20)&field_input_alias=$1&field_input_linked_texts=$2&classname=Person"
  323. }
  324. curl_opt_create_User() {
  325. echo "field_input_lastname=$(rnd_str_len 10 20)&field_input_firstname=$(rnd_str_len 10 20)&field_input_password=$(rnd_str 50)&field_input_login=$(rnd_str_len 5 20)&classname=User"
  326. }
  327. curl_opt_create_Collection() {
  328. #$1 is publications id (comma separated)
  329. echo "field_input_title=$(rnd_str_len 20 50)&field_input_publications=$1&classname=Collection"
  330. }
  331. curl_opt_create_Publication() {
  332. #$1 collections id comma separated
  333. echo "field_input_collection=$1&classname=Publication"
  334. }
  335. curl_opt_create_Section() {
  336. #$1 childs id (comma separated)
  337. #$2 linked_persons id (comma separated)
  338. echo "field_input_title=$(rnd_str_len 20 50)&field_input_subtitle=$(rnd_str_len 20 50)&field_input_childs=$1&field_input_linked_persons=$2&classname=Section"
  339. }
  340. curl_opt_create_Subsection() {
  341. #$1 childs id (comma separated)
  342. #$2 linked_persons id (comma separated)
  343. #$3 parants id (comma separated)
  344. echo "field_input_title=$(rnd_str_len 20 50)&field_input_subtitle=$(rnd_str_len 20 50)&field_input_childs=$1&field_input_linked_persons=$2&field_input_parent=$3&classname=Subsection"
  345. }
  346. run_bg_with_param() {
  347. #$1 is the function name to run
  348. #$2 is the instance_list filename
  349. #other parameters are given to the function
  350. fun=$1
  351. instance_list=$2
  352. shift;shift
  353. pidlist=$($cmktemp)
  354. for iname in $(cat $instance_list)
  355. do
  356. $fun $iname $@ &
  357. echo $! >> $pidlist
  358. sleep 1
  359. done
  360. for pid in $(cat $pidlist)
  361. do
  362. wait $pid
  363. done
  364. rm -v $pidlist >&2
  365. }
  366. get_queries_with_params() {
  367. #$1 is the function name to run
  368. #$2 is the instance_list filename
  369. #other parameters are given to the function
  370. fun=$1
  371. instance_list=$2
  372. shift;shift
  373. counter=0
  374. for iname in $(cat $instance_list| sort)
  375. do
  376. echo "Running $fun $iname $@" >&2
  377. beg=$(date "+%s")
  378. $fun $iname $@
  379. tsecs=$(expr $(date "+%s") - $beg)
  380. left=$(expr $(cat $instance_list |wc -l) - $counter)
  381. counter=$(expr $counter + 1)
  382. tleft=$(expr $left \* $tsecs)
  383. percent_done=$(echo "2k ${counter}.0 100.0 * $(cat $instance_list |wc -l).0 2k/ f" | dc)
  384. echo -e "Done in ${tsecs}s\t$fun ${percent_done}% done ~$tleft secs" >&2
  385. done | shuf
  386. }
  387. get_queries_with_params "mass_get" $instance_list
  388. [ "$n_create" -gt 0 ] && get_queries_with_params "mass_creation" $instance_list $n_create
  389. [ "$n_edit" -gt 0 ] && get_queries_with_params "mass_link_edit" $instance_list $n_edit
  390. [ "$n_delete" -gt 0 ] && get_queries_with_params "mass_deletion" $instance_list $n_delete