Scripting Vugen 12.57 – Datapool MySQL pour Vugen
L’utilisation d’un moteur de base de données comme Mysql pour gérer le jeu de données Vugen n’est pas qu’un exercice de style. En effet, dans des cas où le nombre d’informations à utiliser est très important (supérieur à 500 000), Vugen présente quelques problèmes lors de l’exécution d’un Tir de performance. La procédure décrite ci-dessous détaille un exemple opérationnel complet tout à fait adaptable et réalisé dans un environnement réel.
Concernant la version de la bibliothèque de lien dynamique utilisée du Connecteur C (libmysql.dll v6.1.9.0 et non la dernière version disponible), il faut savoir que les développeurs y ont implémenté depuis la version 6.1.10 le package Microsoft Visual C++. Conséquence, les dépendances de bibliothèques sont plus importantes alors que ces mêmes bibliothèques n’ont aucune utilité dans le cas présent.
La méthode employée ici consiste à adapter les librairies .h de la version Mysql 8.0 pour être utilisable avec le langage C et avec Vugen.
L’API complète des fonctions de Mysql 8.0 est disponible à :
http://dev.mysql.com/doc/refman/8.0/en/c-api-functions.html
1 – Téléchargement
mysql-installer-community-8.0.12.0.msi :
https://dev.mysql.com/downloads/installer/
MySQL Connector/C (mysql-connector-c-6.1.11-winx64.zip) :
https://downloads.mysql.com/archives/c-c/
2 – Installer MySQL
N’Installer que Mysql server 8.0
3 – Configuration Mysql
Connexion à Mysql : C:\Program Files\MySQL\MySQL Server 8.0\bin>mysql -u root -p Enter password: ********* Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 30 Server version: 8.0.12 MySQL Community Server - GPL Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
Afin d’autoriser l’insertion des données en base par un fichier externe (Authentication plugin ‘caching_sha2_password’) :
mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '********'; Query OK, 0 rows affected (0.02 sec) mysql> SET GLOBAL local_infile=1; Query OK, 0 rows affected (0.00 sec) mysql> show variables like 'local_infile'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | local_infile | ON | +---------------+-------+ 1 row in set, 1 warning (0.00 sec)
4 – Exécuter les commandes de création de la base
mysql> create database loadrunner; Query OK, 1 row affected (0.11 sec) mysql> use loadrunner; Database changed mysql> mysql> CREATE TABLE LRdata ( ID_valeur MEDIUMINT NOT NULL AUTO_INCREMENT, valeur varchar(255) NOT NULL, CREATION_TIMESTAMP varchar(29) NOT NULL, PRIMARY KEY (ID_valeur) ) ENGINE=InnoDB; Query OK, 0 rows affected (0.13 sec)
Visualiser la base :
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | loadrunner | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.01 sec)
Si besoin : Supprimer la table:
Mysql>drop table LRdata;
5 – Ajouter des enregistrements
Pour créer des enregistrements dans un fichier csv, utiliser le script vugen ci-dessous :
Sortir de Mysql et se reconnecter : C:\Program Files\MySQL\MySQL Server 8.0\bin>mysql -u root -p --local-infile loadrunner mysql> LOAD DATA LOCAL INFILE 'C:\\JDD\\import1.csv' INTO TABLE LRdata FIELDS terminated by ';' LINES TERMINATED BY '\n' (valeur,CREATION_TIMESTAMP); Query OK, 1000000 rows affected, 65535 warnings (25.35 sec) Records: 1000000 Deleted: 0 Skipped: 0 Warnings: 899531
6 – Préparation des fichiers pour scripting Vugen
Copier les fichiers de Mysql dans un nouveau répertoire C:\Mysql8Lib
C:\Program Files\MySQL\MySQL Server 8.0\include :
C:\Mysql8Lib :
Comme le type booléen n’existe pas en C, il faut changer toutes les déclarations de variables bool en un nouveau type entier “my_bool” (déclaration dans global.h du script Vugen, ci-dessous).
Exemple :
typedef struct UDF_INIT {
my_bool maybe_null; /** 1 if function can return NULL */
Ce changement est à faire pour les fichiers
udf_registration_types.h
mysql.h
mysql_com.h
mysql_time.h
Remplacer dans les fichiers :
mysql.h
mysql_com.h
udf_registration_types.h
#include <stdbool.h>
Par
//#include <stdbool.h>
Remplacer dans le fichier mysql.h
#include <sys/types.h>
#include “mysql/client_plugin.h”
#include “errmsg.h”
Par
//#include <sys/types.h>
#include “client_plugin.h”
//#include “errmsg.h”
Remplacer dans le fichier mysql_com.h
#include <mysql/udf_registration_types.h>
Par
#include <udf_registration_types.h>
Remplacer toutes les références aux autres fichiers .h en suffixant par le repertoire C:\\Mysql8Lib\\ dans les fichiers :
client_plugin.h
mysqlx_ername.h
plugin_auth_common.h
udf_registration_types.h
mysql.h
Exemple :
#include “plugin_auth_common.h”
Par
#include ” C:\\Mysql8Lib\\plugin_auth_common.h”
Librairies modifiées comme expliqué ci-dessus:
7 – Script Mysql
Récupérer libmysql.dll de mysql-connector-c-6.1.9-win32\lib
Renommer libmysql.dll en libmysql-6.1.9.0.dll et l’inclure dans les extra files d’un nouveau script vugen Web http/html
Script MysqlV3: vuser_init() { // La documentation MySQL 8.0 C API est disponible à: // http://dev.mysql.com/doc/refman/8.0/en/c-api-functions.html lr_load_dll("libmysql-6.1.9.0.dll"); lr_start_transaction("001_Init_Cnx"); //initialise la connexion mySQL mySQL = mysql_init(NULL); if (mySQL == NULL) { lr_error_message("Mémoire Insuffisante"); lr_abort(); } // Connect to the database if (!mysql_real_connect(mySQL,MySQLServer, MySQLuser, MySQLpassword, MySQLdatabase, MySQLport,NULL,0)) { lr_error_message("%s", mysql_error(mySQL)); mysql_close(mySQL); lr_abort(); } //save SQL statement into variable into sqlQuery //This stamentement returns result that matches UserName = {Vuser} parameter lr_param_sprintf("sqlQuery", "SELECT %s FROM LRData", MySQLChamps); //Execute SQL statement MyRC = mysql_query(mySQL, lr_eval_string ("{sqlQuery}")); if (MyRC != 0) { lr_error_message("%s", mysql_error(mySQL)); mysql_close(mySQL); lr_abort(); } //result of the sql statement is placed into MYSQL_RES result structure result = mysql_use_result(mySQL); if (result == NULL) { lr_error_message("%s", mysql_error(mySQL)); mysql_free_result(result); mysql_close(mySQL); lr_abort(); } lr_end_transaction("001_Init_Cnx", LR_AUTO); return 0; } Action() { double dRes; lr_start_transaction("002_make_Data"); row=mysql_fetch_row(result); // Si plus de données, on reviens au 1er enregistrement if(row==NULL) { mysql_data_seek(result,0); row=mysql_fetch_row(result); } lr_output_message("res = %.3f", atof(row[0])); dRes=atof(row[0]); lr_user_data_point("valeur", dRes); lr_end_transaction("002_make_Data", LR_AUTO); lr_think_time(1); return 0; } vuser_end() { lr_start_transaction("003_decnx"); mysql_free_result(result); mysql_close(mySQL); lr_end_transaction("003_decnx", LR_AUTO); return 0; } Global.h : #ifndef _GLOBALS_H #define _GLOBALS_H typedef int my_bool; //-------------------------------------------------------------------- // Include Files #include "lrun.h" #include "web_api.h" #include "lrw_custom_body.h" #include "C:\\Mysql8Lib\\binary_log_types.h" #include "C:\\Mysql8Lib\\client_plugin.h" #include "C:\\Mysql8Lib\\my_command.h" #include "C:\\Mysql8Lib\\my_list.h" #include "C:\\Mysql8Lib\\mysql.h" #include "C:\\Mysql8Lib\\mysql_com.h" #include "C:\\Mysql8Lib\\mysql_time.h" #include "C:\\Mysql8Lib\\mysql_version.h" #include "C:\\Mysql8Lib\\mysqld_error.h" #include "C:\\Mysql8Lib\\mysqlx_error.h" #include "C:\\Mysql8Lib\\mysqlx_version.h" #include "C:\\Mysql8Lib\\plugin_auth_common.h" #include "C:\\Mysql8Lib\\udf_registration_types.h" //-------------------------------------------------------------------- // Global Variables MYSQL *mySQL; MYSQL_ROW row; MYSQL_RES *result; int i=0, MyRC, num_fields; char *MySQLServer = "localhost"; char *MySQLuser = "root"; char *MySQLpassword = "********"; char *MySQLdatabase = "loadrunner"; char *MySQLChamps = "valeur"; int MySQLport = 3306; #endif // _GLOBALS_H
Script complet :
8 – Résultat Log Vugen
Première exécution du script:
Si erreur suivante (car serveur Mysql distant):
vuser_init.c(20): Error: Host ‘150.62.9.226’ is not allowed to connect to this MySQL server
Dans ce cas, lancer les 4 commandes ci-dessous :
mysql> use Loadrunner; Database changed mysql> CREATE USER 'root'@'150.62.9.226' IDENTIFIED BY 'root'; Query OK, 0 rows affected (0.12 sec) mysql> GRANT ALL PRIVILEGES ON *.* TO 'root'@'150.62.9.226' WITH GRANT OPTION; Query OK, 0 rows affected (0.07 sec) mysql> ALTER USER 'root'@'150.62.9.226' IDENTIFIED WITH mysql_native_password BY '********'; Query OK, 0 rows affected (0.02 sec)
Log Vugen:
Virtual User Script started at: 31/08/2018 15:29:06 Starting action vuser_init. Web Turbo Replay of LoadRunner 12.57.0 for Windows 7; build 281 (mai 06 2018 20:03:54) [MsgId: MMSG-26983] Run mode: HTML [MsgId: MMSG-26993] Replay user agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT) [MsgId: MMSG-26988] Runtime Settings file: "D:\DATA\ESPDEV\ScriptsVugen\Datapool Mysql\MysqlV3\\default.cfg" [MsgId: MMSG-27141] vuser_init.c(9): Notify: Transaction "001_Init_Cnx" started. vuser_init.c(46): Notify: Transaction "001_Init_Cnx" ended with a "Pass" status (Duration: 4,1010). Ending action vuser_init. Running Vuser... Starting iteration 1. Starting action Action. Action.c(5): Notify: Transaction "002_make_Data" started. Action.c(16): res = 0,700 Action.c(18): Notify: Data Point "valeur" value = 0,7000. Action.c(20): Notify: Transaction "002_make_Data" ended with a "Pass" status (Duration: 0,1318). Ending action Action. Ending iteration 1. Ending Vuser... Starting action vuser_end. vuser_end.c(3): Notify: Transaction "003_decnx" started. vuser_end.c(8): Notify: Transaction "003_decnx" ended with a "Pass" status (Duration: 0,1171). Ending action vuser_end. Vuser Terminated.
9 – Résultat Tir
Le million de lignes de la table LRdata a été lu lors de ce tir.
200 Vu en charge
Valeurs des données issues de Mysql
Consommation système du serveur Mysql
Temps de lecture très faible via Mysql
400 lectures/s sans erreur
Consultant Testing Senior en poste chez Sogeti