PageRenderTime 29ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/PerformanceTests/stress-test-data-imports.js

https://gitlab.com/Jbfortest/dotstatsuite-quality-assurance
JavaScript | 273 lines | 206 code | 38 blank | 29 comment | 34 complexity | dd4c1a59db655736539482ed428d931f MD5 | raw file
  1. /******************
  2. This test provies scenario for stress testing data imports to the transfer-service:
  3. 1.- Determine how your system will behave under extreme conditions.
  4. 2.- Determine what is the maximum capacity of your system in terms of users or throughput.
  5. 3.- Determine the breaking point of your system and its failure mode.
  6. 4.- Determine if your system will recover without manual intervention after the stress test is over.
  7. *******************/
  8. import http from 'k6/http';
  9. import { check, sleep, group, fail } from 'k6';
  10. import { Rate, Trend } from 'k6/metrics';
  11. import { TryToGetNewAccessToken } from './Resources/authenticate.js';
  12. //Default transfer-service host url
  13. let BASE_URL = "http://127.0.0.1:93";
  14. if(typeof __ENV.TRANSFER_SERVICE_HOSTNAME !== 'undefined'){
  15. BASE_URL = __ENV.TRANSFER_SERVICE_HOSTNAME;
  16. }
  17. let PID = 3497348;
  18. if(typeof __ENV.K6_PID !== 'undefined'){
  19. PID = __ENV.K6_PID;
  20. }
  21. //K6 cloud test name
  22. let TEST_NAME = "stress-test-data-imports";
  23. if(typeof __ENV.TEST_NAME !== 'undefined'){
  24. TEST_NAME = __ENV.TEST_NAME;
  25. }
  26. let DATASPACE="stable";
  27. if(typeof __ENV.DATASPACE !== 'undefined'){
  28. DATASPACE = __ENV.DATASPACE;
  29. }
  30. //Keycloak parameters
  31. let ACCESS_TOKEN_URL= "https://keycloak.siscc.org/auth/realms/OECD/protocol/openid-connect/token";
  32. if(typeof __ENV.KEYCLOAK_AT_URL !== 'undefined'){
  33. ACCESS_TOKEN_URL = __ENV.KEYCLOAK_AT_URL;
  34. }
  35. let currentAccessToken = "";
  36. let accessTokenExpiry ="";
  37. //Keycloak credentials
  38. let USERNAME="";
  39. if(typeof __ENV.USERNAME !== 'undefined'){
  40. USERNAME = __ENV.USERNAME;
  41. }
  42. let PASSWORD="";
  43. if(typeof __ENV.PASSWORD !== 'undefined'){
  44. PASSWORD = __ENV.PASSWORD;
  45. }
  46. //login to keycloak?
  47. let getToken =true;
  48. if(typeof __ENV.USERNAME === 'undefined' || typeof __ENV.PASSWORD === 'undefined'){
  49. getToken=false;
  50. }
  51. let INPUT_FILE = "./Resources/test-cases-data-imports.json";
  52. if(typeof __ENV.TEST_CASES_FILE !== 'undefined'){
  53. INPUT_FILE = __ENV.TEST_CASES_FILE;
  54. }
  55. //Load test cases from json file
  56. const TEST_CASES= JSON.parse(open(INPUT_FILE));
  57. //Open input files
  58. for(let testCase in TEST_CASES){
  59. if(TEST_CASES[testCase].format !=="sdmx")
  60. TEST_CASES[testCase].data = open(`./Resources/Data/${TEST_CASES[testCase].dataFile}`, "b");
  61. if(TEST_CASES[testCase].format ==="excel")
  62. TEST_CASES[testCase].edd = open(`./Resources/Data/${TEST_CASES[testCase].eddFile}`, "b");
  63. }
  64. let importRate = new Rate('data_import_completed');
  65. let importTrend = new Trend('data_import_time', true);
  66. export let options = {
  67. setupTimeout: "10s",
  68. ext: {
  69. loadimpact: {
  70. projectID: PID, //k6 CLOUD project id
  71. name: TEST_NAME
  72. }
  73. },
  74. //Target = number of max users to scale to
  75. stages: [
  76. { duration: '40s', target: 1 }, // below normal load
  77. { duration: '90s', target: 1 },
  78. { duration: '40s', target: 2 }, // normal load
  79. { duration: '90s', target: 2 },
  80. { duration: '40s', target: 3 }, // around the breaking point
  81. { duration: '90s', target: 3 },
  82. { duration: '40s', target: 5 }, // beyond the breaking point
  83. { duration: '90s', target: 5 },
  84. { duration: '20s', target: 1 }, // scale down. Recovery stage.
  85. { duration: '4m', target: 1 }, // continue at 1 users to collect pending imports that are still being processed
  86. ],
  87. thresholds: {
  88. "checks": ['rate>0.99'], // more than 99% success rate on import requests
  89. "data_import_completed": ['rate>0.90'], // more than 90% success rate of transactions imported
  90. "data_import_time{import_type:csv_small}": ["p(95)<20000"],//less than 20 seconds
  91. "data_import_time{import_type:csv_medium}": ["p(95)<70000"],//less than 70 seconds
  92. "data_import_time{import_type:csv_large}": ["p(95)<150000"],//less than 150 seconds
  93. "data_import_time{import_type:xml_small}": ["p(95)<20000"],//less than 20 seconds
  94. "data_import_time{import_type:xml_medium}": ["p(95)<70000"],//less than 70 seconds
  95. "data_import_time{import_type:xml_large}": ["p(95)<150000"],//less than 150 seconds
  96. "data_import_time{import_type:sdmx_small}": ["p(95)<20000"],//less than 20 seconds
  97. "data_import_time{import_type:sdmx_medium}": ["p(95)<70000"],//less than 70 seconds
  98. "data_import_time{import_type:sdmx_large}": ["p(95)<150000"],//less than 150 seconds
  99. "data_import_time{import_type:excel_extraSmall}": ["p(95)<5000"],//less than 5 seconds
  100. "data_import_time{import_type:excel_small}": ["p(95)<20000"],//less than 20 seconds
  101. "data_import_time{import_type:excel_medium}": ["p(95)<70000"],//less than 70 seconds
  102. "data_import_time{import_type:excel_large}": ["p(95)<150000"],//less than 150 seconds
  103. "data_import_time{datasetSize:extraSmall}": ["p(95)<150000"],
  104. "data_import_time{datasetSize:small}": ["p(95)<150000"],
  105. "data_import_time{datasetSize:medium}": ["p(95)<150000"],
  106. "data_import_time{datasetSize:large}": ["p(95)<150000"],
  107. "data_import_time{datasetSize:extraLarge}": ["p(95)<150000"],
  108. },
  109. //iterations: TEST_CASES.length,
  110. //vus: TEST_CASES.length,
  111. };
  112. export function setup() {
  113. // 2. setup code
  114. //check that the transfer-service hostname is available
  115. let healhCheck = http.get(`${BASE_URL}/health`);
  116. if (healhCheck.status !== 200){
  117. fail(`Error: the transfer-service {${BASE_URL}/health} is not responding.`);
  118. }
  119. console.log(`Testing the transfer-service {${BASE_URL}} version ${healhCheck.json().service.details.version}`);
  120. }
  121. export default function() {
  122. var submitedRequests = [];
  123. TryToGetNewAccessToken();
  124. let testCase = TEST_CASES[Math.floor(Math.random() * TEST_CASES.length)];
  125. //Submit data import requests
  126. let headers= {
  127. 'Accept':'application/json',
  128. 'Authorization': `Bearer ${currentAccessToken}`,
  129. };
  130. var method = "/1.2/import/sdmxFile";
  131. let data= { 'dataspace': DATASPACE };
  132. //Import from SDMX source
  133. if(testCase.format ==="sdmx" ){
  134. data.filepath= testCase.sdmxSource;
  135. //Workaround - K6 only supports multipart/from-data request if there is a file in the request.
  136. data.file= http.file("", "dummyFile.csv");
  137. console.log(`Importing from url: ${data.filepath}`);
  138. }
  139. //Import from Excel
  140. else if(testCase.format ==="excel" ){
  141. method = "/1.2/import/excel";
  142. data.eddFile = http.file(testCase.edd, testCase.eddFile);
  143. data.excelFile = http.file(testCase.data, testCase.dataFile);
  144. console.log(`Importing excel file: ${testCase.eddFile}`);
  145. }
  146. //Import from CSV and XML
  147. else{
  148. data.file = http.file(testCase.data, testCase.dataFile);
  149. console.log(`Importing from file: ${testCase.dataFile}`);
  150. }
  151. var res = http.post(
  152. `${BASE_URL}${method}`,
  153. data,
  154. {headers: headers},
  155. );
  156. sleep(1);//1s
  157. console.log(`import status:${res.status}`);
  158. check(res, {
  159. 'is status 200': (r) => r.status === 200
  160. });
  161. var date = new Date();
  162. var startTime = date.getTime();
  163. if(res.status ==200){
  164. console.log(`import message:${res.json().message}`);
  165. var transactionID = res.json().message.match(/\d+/g);
  166. //Wait for the transfer-service to process import
  167. if(testCase.size=="extraSmall")
  168. sleep(2);//2s
  169. else if(testCase.size=="small")
  170. sleep(5);//4s
  171. else if(testCase.size=="medium")
  172. sleep(40);//40s
  173. else if(testCase.size=="large")
  174. sleep(180);//3m
  175. else if(testCase.size=="extraLarge")
  176. sleep(360);//6m
  177. else
  178. sleep(10);//5s
  179. var timeOutTime = 600000;//10min
  180. do{
  181. //Get new access token if current token has expired
  182. TryToGetNewAccessToken();
  183. let data= {
  184. 'dataspace': DATASPACE,
  185. 'id': parseInt(transactionID)
  186. };
  187. let headers= {
  188. 'Accept':'application/json',
  189. 'Authorization': 'Bearer ' + currentAccessToken,
  190. };
  191. method = "/1.2/status/request";
  192. var res = http.post(
  193. `${BASE_URL}${method}`,
  194. data,
  195. {headers: headers}
  196. );
  197. sleep(1);//1s
  198. var d = new Date();
  199. if(res.status===200){
  200. if(res.json().executionStatus==="Completed"){
  201. var actualTime = Date.parse(res.json().executionEnd) - Date.parse(res.json().executionStart);
  202. importTrend.add(actualTime, { import_type: `${testCase.format}_${testCase.size}` });
  203. importTrend.add(actualTime, { datasetSize: `${testCase.datasetSize}` });
  204. //The import was completed
  205. importRate.add(true);
  206. break;
  207. }
  208. else if(res.json().executionStatus==="TimedOutAborted"){
  209. var actualTime = Date.parse(res.json().executionEnd) - Date.parse(res.json().executionStart);
  210. importTrend.add(actualTime, { import_type: `${testCase.format}_$testCase.size}` });
  211. importTrend.add(actualTime, { datasetSize: `${testCase.datasetSize}` });
  212. //The import was TimedOutAborted
  213. importRate.add(false);
  214. break;
  215. }
  216. else if(d.getTime()-startTime>=timeOutTime){
  217. var actualTime = Date.parse(res.json().executionEnd) - Date.parse(res.json().executionStart);
  218. importTrend.add(actualTime, { import_type: `${testCase.format}_${testCase.size}` });
  219. importTrend.add(actualTime, { datasetSize: `${stestCase.datasetSize}` });
  220. //The import was TimedOutAborted
  221. importRate.add(false);
  222. console.log(`timed out ${transactionID}`);
  223. break;
  224. }
  225. }
  226. sleep(10);//5s
  227. }while(true);
  228. }
  229. else{
  230. importRate.add(false);
  231. if(res.status >= 500){
  232. console.log(`import message:${res.body}`);
  233. }
  234. }
  235. }