├── .gitignore ├── Dockerfile ├── Dockerfile.grafana ├── Dockerfile.influxdb ├── docker-compose.yml ├── grafana_dashboard.json ├── presentation-slides.pdf ├── readme.md └── tests ├── 01-simple └── test.js └── 02-stages └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM loadimpact/k6 2 | 3 | RUN k6 login cloud -t LI_TOKEN 4 | -------------------------------------------------------------------------------- /Dockerfile.grafana: -------------------------------------------------------------------------------- 1 | FROM grafana/grafana:5.2.4 2 | 3 | USER root 4 | 5 | RUN apt-get update && apt-get -y install curl 6 | 7 | 8 | # Change the default data directory (otherwise grafana.db won't persist) 9 | RUN mkdir /var/lib/grafanadb 10 | ENV GF_PATHS_DATA /var/lib/grafanadb 11 | 12 | # Init Grafana sqlite db and preconfigure our data source to be our influxdb k6 db 13 | RUN bash -c '/run.sh & sleep 15 && curl -s -H "Content-Type: application/json" -X POST \ 14 | --data '"'"'{"name": "K6", "type": "influxdb", "access": "proxy", "url": "http://influxdb:8086", "database": "k6", "isDefault": true}'"'"' \ 15 | http://admin:admin@localhost:3000/api/datasources \ 16 | && kill -SIGINT %%' 17 | 18 | 19 | CMD ["/run.sh"] 20 | -------------------------------------------------------------------------------- /Dockerfile.influxdb: -------------------------------------------------------------------------------- 1 | FROM influxdb:1.2.2 2 | 3 | # Create a k6 db 4 | RUN /bin/bash -c "influxd run & sleep 5 && influx -execute 'CREATE DATABASE k6' && kill %1 && sleep 5" 5 | 6 | CMD ["influxd"] 7 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | influxdb: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile.influxdb 7 | ports: 8 | - "8086:8086" 9 | grafana: 10 | build: 11 | context: . 12 | dockerfile: Dockerfile.grafana 13 | links: 14 | - influxdb 15 | environment: 16 | - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin 17 | - GF_AUTH_ANONYMOUS_ENABLED=true 18 | - GF_AUTH_BASIC_ENABLED=false 19 | ports: 20 | - "3000:3000" 21 | k6: 22 | build: . 23 | ports: 24 | - "6565:6565" 25 | volumes: 26 | - "./tests:/tests" 27 | environment: 28 | - K6_OUT=influxdb=http://influxdb:8086/k6 29 | command: "version" 30 | -------------------------------------------------------------------------------- /grafana_dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_K6", 5 | "label": "K6", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "influxdb", 9 | "pluginName": "InfluxDB" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "5.2.4" 18 | }, 19 | { 20 | "type": "panel", 21 | "id": "graph", 22 | "name": "Graph", 23 | "version": "5.0.0" 24 | }, 25 | { 26 | "type": "panel", 27 | "id": "heatmap", 28 | "name": "Heatmap", 29 | "version": "5.0.0" 30 | }, 31 | { 32 | "type": "datasource", 33 | "id": "influxdb", 34 | "name": "InfluxDB", 35 | "version": "5.0.0" 36 | } 37 | ], 38 | "annotations": { 39 | "list": [ 40 | { 41 | "builtIn": 1, 42 | "datasource": "-- Grafana --", 43 | "enable": true, 44 | "hide": true, 45 | "iconColor": "rgba(0, 211, 255, 1)", 46 | "name": "Annotations & Alerts", 47 | "type": "dashboard" 48 | } 49 | ] 50 | }, 51 | "editable": true, 52 | "gnetId": null, 53 | "graphTooltip": 0, 54 | "id": null, 55 | "links": [], 56 | "panels": [ 57 | { 58 | "aliasColors": {}, 59 | "bars": true, 60 | "dashLength": 10, 61 | "dashes": false, 62 | "datasource": "K6", 63 | "fill": 1, 64 | "gridPos": { 65 | "h": 7, 66 | "w": 8, 67 | "x": 0, 68 | "y": 0 69 | }, 70 | "id": 1, 71 | "interval": ">1s", 72 | "legend": { 73 | "alignAsTable": true, 74 | "avg": false, 75 | "current": false, 76 | "max": true, 77 | "min": true, 78 | "show": true, 79 | "total": false, 80 | "values": true 81 | }, 82 | "lines": false, 83 | "linewidth": 1, 84 | "links": [], 85 | "nullPointMode": "null", 86 | "percentage": false, 87 | "pointradius": 5, 88 | "points": false, 89 | "renderer": "flot", 90 | "seriesOverrides": [], 91 | "spaceLength": 10, 92 | "stack": false, 93 | "steppedLine": false, 94 | "targets": [ 95 | { 96 | "alias": "Active VUs", 97 | "dsType": "influxdb", 98 | "groupBy": [ 99 | { 100 | "params": [ 101 | "$__interval" 102 | ], 103 | "type": "time" 104 | }, 105 | { 106 | "params": [ 107 | "none" 108 | ], 109 | "type": "fill" 110 | } 111 | ], 112 | "measurement": "vus", 113 | "orderByTime": "ASC", 114 | "policy": "default", 115 | "refId": "A", 116 | "resultFormat": "time_series", 117 | "select": [ 118 | [ 119 | { 120 | "params": [ 121 | "value" 122 | ], 123 | "type": "field" 124 | }, 125 | { 126 | "params": [], 127 | "type": "mean" 128 | } 129 | ] 130 | ], 131 | "tags": [] 132 | } 133 | ], 134 | "thresholds": [], 135 | "timeFrom": null, 136 | "timeShift": null, 137 | "title": "Virtual Users", 138 | "tooltip": { 139 | "shared": true, 140 | "sort": 0, 141 | "value_type": "individual" 142 | }, 143 | "type": "graph", 144 | "xaxis": { 145 | "buckets": null, 146 | "mode": "time", 147 | "name": null, 148 | "show": true, 149 | "values": [] 150 | }, 151 | "yaxes": [ 152 | { 153 | "format": "short", 154 | "label": null, 155 | "logBase": 1, 156 | "max": null, 157 | "min": null, 158 | "show": true 159 | }, 160 | { 161 | "format": "short", 162 | "label": null, 163 | "logBase": 1, 164 | "max": null, 165 | "min": null, 166 | "show": true 167 | } 168 | ], 169 | "yaxis": { 170 | "align": false, 171 | "alignLevel": null 172 | } 173 | }, 174 | { 175 | "aliasColors": {}, 176 | "bars": true, 177 | "dashLength": 10, 178 | "dashes": false, 179 | "datasource": "K6", 180 | "fill": 1, 181 | "gridPos": { 182 | "h": 7, 183 | "w": 8, 184 | "x": 8, 185 | "y": 0 186 | }, 187 | "id": 7, 188 | "interval": ">1s", 189 | "legend": { 190 | "alignAsTable": true, 191 | "avg": true, 192 | "current": false, 193 | "max": false, 194 | "min": false, 195 | "show": true, 196 | "total": true, 197 | "values": true 198 | }, 199 | "lines": false, 200 | "linewidth": 1, 201 | "links": [], 202 | "nullPointMode": "null", 203 | "percentage": false, 204 | "pointradius": 5, 205 | "points": false, 206 | "renderer": "flot", 207 | "seriesOverrides": [ 208 | { 209 | "alias": "Num Errors", 210 | "color": "#BF1B00" 211 | } 212 | ], 213 | "spaceLength": 10, 214 | "stack": true, 215 | "steppedLine": false, 216 | "targets": [ 217 | { 218 | "alias": "Num Errors", 219 | "dsType": "influxdb", 220 | "groupBy": [ 221 | { 222 | "params": [ 223 | "$__interval" 224 | ], 225 | "type": "time" 226 | }, 227 | { 228 | "params": [ 229 | "none" 230 | ], 231 | "type": "fill" 232 | } 233 | ], 234 | "measurement": "errors", 235 | "orderByTime": "ASC", 236 | "policy": "default", 237 | "refId": "C", 238 | "resultFormat": "time_series", 239 | "select": [ 240 | [ 241 | { 242 | "params": [ 243 | "value" 244 | ], 245 | "type": "field" 246 | }, 247 | { 248 | "params": [], 249 | "type": "count" 250 | } 251 | ] 252 | ], 253 | "tags": [] 254 | } 255 | ], 256 | "thresholds": [], 257 | "timeFrom": null, 258 | "timeShift": null, 259 | "title": "Errors Per Second", 260 | "tooltip": { 261 | "shared": true, 262 | "sort": 0, 263 | "value_type": "individual" 264 | }, 265 | "type": "graph", 266 | "xaxis": { 267 | "buckets": null, 268 | "mode": "time", 269 | "name": null, 270 | "show": true, 271 | "values": [] 272 | }, 273 | "yaxes": [ 274 | { 275 | "format": "short", 276 | "label": null, 277 | "logBase": 1, 278 | "max": null, 279 | "min": null, 280 | "show": true 281 | }, 282 | { 283 | "format": "short", 284 | "label": null, 285 | "logBase": 1, 286 | "max": null, 287 | "min": null, 288 | "show": true 289 | } 290 | ], 291 | "yaxis": { 292 | "align": false, 293 | "alignLevel": null 294 | } 295 | }, 296 | { 297 | "aliasColors": {}, 298 | "bars": true, 299 | "dashLength": 10, 300 | "dashes": false, 301 | "datasource": "K6", 302 | "fill": 1, 303 | "gridPos": { 304 | "h": 7, 305 | "w": 8, 306 | "x": 16, 307 | "y": 0 308 | }, 309 | "id": 10, 310 | "interval": ">1s", 311 | "legend": { 312 | "alignAsTable": true, 313 | "avg": true, 314 | "current": false, 315 | "max": false, 316 | "min": false, 317 | "show": true, 318 | "total": true, 319 | "values": true 320 | }, 321 | "lines": false, 322 | "linewidth": 1, 323 | "links": [], 324 | "nullPointMode": "null", 325 | "percentage": false, 326 | "pointradius": 5, 327 | "points": false, 328 | "renderer": "flot", 329 | "seriesOverrides": [ 330 | { 331 | "alias": "Num Errors", 332 | "color": "#BF1B00" 333 | } 334 | ], 335 | "spaceLength": 10, 336 | "stack": true, 337 | "steppedLine": false, 338 | "targets": [ 339 | { 340 | "alias": "Num Checks", 341 | "dsType": "influxdb", 342 | "groupBy": [ 343 | { 344 | "params": [ 345 | "$__interval" 346 | ], 347 | "type": "time" 348 | }, 349 | { 350 | "params": [ 351 | "none" 352 | ], 353 | "type": "fill" 354 | } 355 | ], 356 | "measurement": "checks", 357 | "orderByTime": "ASC", 358 | "policy": "default", 359 | "refId": "C", 360 | "resultFormat": "time_series", 361 | "select": [ 362 | [ 363 | { 364 | "params": [ 365 | "value" 366 | ], 367 | "type": "field" 368 | }, 369 | { 370 | "params": [], 371 | "type": "count" 372 | } 373 | ] 374 | ], 375 | "tags": [] 376 | } 377 | ], 378 | "thresholds": [], 379 | "timeFrom": null, 380 | "timeShift": null, 381 | "title": "Checks Per Second", 382 | "tooltip": { 383 | "shared": true, 384 | "sort": 0, 385 | "value_type": "individual" 386 | }, 387 | "type": "graph", 388 | "xaxis": { 389 | "buckets": null, 390 | "mode": "time", 391 | "name": null, 392 | "show": true, 393 | "values": [] 394 | }, 395 | "yaxes": [ 396 | { 397 | "format": "short", 398 | "label": null, 399 | "logBase": 1, 400 | "max": null, 401 | "min": null, 402 | "show": true 403 | }, 404 | { 405 | "format": "short", 406 | "label": null, 407 | "logBase": 1, 408 | "max": null, 409 | "min": null, 410 | "show": true 411 | } 412 | ], 413 | "yaxis": { 414 | "align": false, 415 | "alignLevel": null 416 | } 417 | }, 418 | { 419 | "aliasColors": {}, 420 | "bars": false, 421 | "dashLength": 10, 422 | "dashes": false, 423 | "datasource": "K6", 424 | "description": "Grouped by 1 sec intervals", 425 | "fill": 1, 426 | "gridPos": { 427 | "h": 7, 428 | "w": 12, 429 | "x": 0, 430 | "y": 7 431 | }, 432 | "id": 5, 433 | "interval": ">1s", 434 | "legend": { 435 | "alignAsTable": false, 436 | "avg": false, 437 | "current": false, 438 | "max": false, 439 | "min": false, 440 | "show": true, 441 | "total": false, 442 | "values": false 443 | }, 444 | "lines": true, 445 | "linewidth": 1, 446 | "links": [], 447 | "nullPointMode": "null", 448 | "percentage": false, 449 | "pointradius": 5, 450 | "points": false, 451 | "renderer": "flot", 452 | "seriesOverrides": [], 453 | "spaceLength": 10, 454 | "stack": false, 455 | "steppedLine": false, 456 | "targets": [ 457 | { 458 | "alias": "max", 459 | "dsType": "influxdb", 460 | "groupBy": [ 461 | { 462 | "params": [ 463 | "$__interval" 464 | ], 465 | "type": "time" 466 | }, 467 | { 468 | "params": [ 469 | "none" 470 | ], 471 | "type": "fill" 472 | } 473 | ], 474 | "measurement": "http_req_duration", 475 | "orderByTime": "ASC", 476 | "policy": "default", 477 | "refId": "C", 478 | "resultFormat": "time_series", 479 | "select": [ 480 | [ 481 | { 482 | "params": [ 483 | "value" 484 | ], 485 | "type": "field" 486 | }, 487 | { 488 | "params": [], 489 | "type": "max" 490 | } 491 | ] 492 | ], 493 | "tags": [] 494 | }, 495 | { 496 | "alias": "p95", 497 | "dsType": "influxdb", 498 | "groupBy": [ 499 | { 500 | "params": [ 501 | "$__interval" 502 | ], 503 | "type": "time" 504 | }, 505 | { 506 | "params": [ 507 | "none" 508 | ], 509 | "type": "fill" 510 | } 511 | ], 512 | "measurement": "http_req_duration", 513 | "orderByTime": "ASC", 514 | "policy": "default", 515 | "refId": "D", 516 | "resultFormat": "time_series", 517 | "select": [ 518 | [ 519 | { 520 | "params": [ 521 | "value" 522 | ], 523 | "type": "field" 524 | }, 525 | { 526 | "params": [ 527 | 95 528 | ], 529 | "type": "percentile" 530 | } 531 | ] 532 | ], 533 | "tags": [] 534 | }, 535 | { 536 | "alias": "p80", 537 | "dsType": "influxdb", 538 | "groupBy": [ 539 | { 540 | "params": [ 541 | "$__interval" 542 | ], 543 | "type": "time" 544 | }, 545 | { 546 | "params": [ 547 | "none" 548 | ], 549 | "type": "fill" 550 | } 551 | ], 552 | "measurement": "http_req_duration", 553 | "orderByTime": "ASC", 554 | "policy": "default", 555 | "refId": "A", 556 | "resultFormat": "time_series", 557 | "select": [ 558 | [ 559 | { 560 | "params": [ 561 | "value" 562 | ], 563 | "type": "field" 564 | }, 565 | { 566 | "params": [ 567 | "80" 568 | ], 569 | "type": "percentile" 570 | } 571 | ] 572 | ], 573 | "tags": [] 574 | }, 575 | { 576 | "alias": "p50", 577 | "dsType": "influxdb", 578 | "groupBy": [ 579 | { 580 | "params": [ 581 | "$__interval" 582 | ], 583 | "type": "time" 584 | }, 585 | { 586 | "params": [ 587 | "none" 588 | ], 589 | "type": "fill" 590 | } 591 | ], 592 | "measurement": "http_req_duration", 593 | "orderByTime": "ASC", 594 | "policy": "default", 595 | "refId": "B", 596 | "resultFormat": "time_series", 597 | "select": [ 598 | [ 599 | { 600 | "params": [ 601 | "value" 602 | ], 603 | "type": "field" 604 | }, 605 | { 606 | "params": [ 607 | "50" 608 | ], 609 | "type": "percentile" 610 | } 611 | ] 612 | ], 613 | "tags": [] 614 | }, 615 | { 616 | "alias": "min", 617 | "dsType": "influxdb", 618 | "groupBy": [ 619 | { 620 | "params": [ 621 | "$__interval" 622 | ], 623 | "type": "time" 624 | }, 625 | { 626 | "params": [ 627 | "none" 628 | ], 629 | "type": "fill" 630 | } 631 | ], 632 | "measurement": "http_req_duration", 633 | "orderByTime": "ASC", 634 | "policy": "default", 635 | "refId": "E", 636 | "resultFormat": "time_series", 637 | "select": [ 638 | [ 639 | { 640 | "params": [ 641 | "value" 642 | ], 643 | "type": "field" 644 | }, 645 | { 646 | "params": [], 647 | "type": "min" 648 | } 649 | ] 650 | ], 651 | "tags": [] 652 | } 653 | ], 654 | "thresholds": [], 655 | "timeFrom": null, 656 | "timeShift": null, 657 | "title": "http_req_duration", 658 | "tooltip": { 659 | "shared": true, 660 | "sort": 0, 661 | "value_type": "individual" 662 | }, 663 | "type": "graph", 664 | "xaxis": { 665 | "buckets": null, 666 | "mode": "time", 667 | "name": null, 668 | "show": true, 669 | "values": [] 670 | }, 671 | "yaxes": [ 672 | { 673 | "format": "ms", 674 | "label": null, 675 | "logBase": 1, 676 | "max": null, 677 | "min": "0", 678 | "show": true 679 | }, 680 | { 681 | "format": "short", 682 | "label": null, 683 | "logBase": 1, 684 | "max": null, 685 | "min": null, 686 | "show": true 687 | } 688 | ], 689 | "yaxis": { 690 | "align": false, 691 | "alignLevel": null 692 | } 693 | }, 694 | { 695 | "cards": { 696 | "cardPadding": null, 697 | "cardRound": null 698 | }, 699 | "color": { 700 | "cardColor": "rgb(0, 234, 255)", 701 | "colorScale": "sqrt", 702 | "colorScheme": "interpolateSpectral", 703 | "exponent": 0.5, 704 | "mode": "opacity" 705 | }, 706 | "dataFormat": "timeseries", 707 | "datasource": "K6", 708 | "gridPos": { 709 | "h": 7, 710 | "w": 12, 711 | "x": 12, 712 | "y": 7 713 | }, 714 | "heatmap": {}, 715 | "highlightCards": true, 716 | "id": 8, 717 | "interval": ">1s", 718 | "legend": { 719 | "show": false 720 | }, 721 | "links": [], 722 | "targets": [ 723 | { 724 | "dsType": "influxdb", 725 | "groupBy": [ 726 | { 727 | "params": [ 728 | "$__interval" 729 | ], 730 | "type": "time" 731 | }, 732 | { 733 | "params": [ 734 | "null" 735 | ], 736 | "type": "fill" 737 | } 738 | ], 739 | "measurement": "http_req_duration", 740 | "orderByTime": "ASC", 741 | "policy": "default", 742 | "refId": "A", 743 | "resultFormat": "time_series", 744 | "select": [ 745 | [ 746 | { 747 | "params": [ 748 | "value" 749 | ], 750 | "type": "field" 751 | }, 752 | { 753 | "params": [], 754 | "type": "mean" 755 | } 756 | ] 757 | ], 758 | "tags": [] 759 | } 760 | ], 761 | "title": "http_req_duration", 762 | "tooltip": { 763 | "show": true, 764 | "showHistogram": false 765 | }, 766 | "type": "heatmap", 767 | "xAxis": { 768 | "show": true 769 | }, 770 | "xBucketNumber": null, 771 | "xBucketSize": null, 772 | "yAxis": { 773 | "decimals": null, 774 | "format": "ms", 775 | "logBase": 2, 776 | "max": null, 777 | "min": null, 778 | "show": true, 779 | "splitFactor": null 780 | }, 781 | "yBucketBound": "auto", 782 | "yBucketNumber": null, 783 | "yBucketSize": null 784 | }, 785 | { 786 | "aliasColors": {}, 787 | "bars": false, 788 | "dashLength": 10, 789 | "dashes": false, 790 | "datasource": "K6", 791 | "fill": 1, 792 | "gridPos": { 793 | "h": 7, 794 | "w": 12, 795 | "x": 0, 796 | "y": 14 797 | }, 798 | "id": 4, 799 | "interval": ">1s", 800 | "legend": { 801 | "alignAsTable": true, 802 | "avg": true, 803 | "current": false, 804 | "max": true, 805 | "min": true, 806 | "show": true, 807 | "total": false, 808 | "values": true 809 | }, 810 | "lines": true, 811 | "linewidth": 1, 812 | "links": [], 813 | "nullPointMode": "null", 814 | "percentage": false, 815 | "pointradius": 5, 816 | "points": false, 817 | "renderer": "flot", 818 | "seriesOverrides": [], 819 | "spaceLength": 10, 820 | "stack": false, 821 | "steppedLine": false, 822 | "targets": [ 823 | { 824 | "dsType": "influxdb", 825 | "groupBy": [ 826 | { 827 | "params": [ 828 | "$__interval" 829 | ], 830 | "type": "time" 831 | }, 832 | { 833 | "params": [ 834 | "none" 835 | ], 836 | "type": "fill" 837 | } 838 | ], 839 | "measurement": "http_req_connecting", 840 | "orderByTime": "ASC", 841 | "policy": "default", 842 | "refId": "C", 843 | "resultFormat": "time_series", 844 | "select": [ 845 | [ 846 | { 847 | "params": [ 848 | "value" 849 | ], 850 | "type": "field" 851 | }, 852 | { 853 | "params": [ 854 | 95 855 | ], 856 | "type": "percentile" 857 | } 858 | ] 859 | ], 860 | "tags": [] 861 | } 862 | ], 863 | "thresholds": [], 864 | "timeFrom": null, 865 | "timeShift": null, 866 | "title": "http_req_connecting (95%ile)", 867 | "tooltip": { 868 | "shared": true, 869 | "sort": 0, 870 | "value_type": "individual" 871 | }, 872 | "type": "graph", 873 | "xaxis": { 874 | "buckets": null, 875 | "mode": "time", 876 | "name": null, 877 | "show": true, 878 | "values": [] 879 | }, 880 | "yaxes": [ 881 | { 882 | "format": "ms", 883 | "label": null, 884 | "logBase": 1, 885 | "max": null, 886 | "min": null, 887 | "show": true 888 | }, 889 | { 890 | "format": "short", 891 | "label": null, 892 | "logBase": 1, 893 | "max": null, 894 | "min": null, 895 | "show": true 896 | } 897 | ], 898 | "yaxis": { 899 | "align": false, 900 | "alignLevel": null 901 | } 902 | }, 903 | { 904 | "aliasColors": {}, 905 | "bars": false, 906 | "dashLength": 10, 907 | "dashes": false, 908 | "datasource": "K6", 909 | "fill": 1, 910 | "gridPos": { 911 | "h": 7, 912 | "w": 12, 913 | "x": 12, 914 | "y": 14 915 | }, 916 | "id": 9, 917 | "interval": ">1s", 918 | "legend": { 919 | "alignAsTable": true, 920 | "avg": true, 921 | "current": false, 922 | "max": true, 923 | "min": true, 924 | "show": true, 925 | "total": false, 926 | "values": true 927 | }, 928 | "lines": true, 929 | "linewidth": 1, 930 | "links": [], 931 | "nullPointMode": "null", 932 | "percentage": false, 933 | "pointradius": 5, 934 | "points": false, 935 | "renderer": "flot", 936 | "seriesOverrides": [], 937 | "spaceLength": 10, 938 | "stack": false, 939 | "steppedLine": false, 940 | "targets": [ 941 | { 942 | "dsType": "influxdb", 943 | "groupBy": [ 944 | { 945 | "params": [ 946 | "$__interval" 947 | ], 948 | "type": "time" 949 | }, 950 | { 951 | "params": [ 952 | "none" 953 | ], 954 | "type": "fill" 955 | } 956 | ], 957 | "measurement": "http_req_blocked", 958 | "orderByTime": "ASC", 959 | "policy": "default", 960 | "refId": "C", 961 | "resultFormat": "time_series", 962 | "select": [ 963 | [ 964 | { 965 | "params": [ 966 | "value" 967 | ], 968 | "type": "field" 969 | }, 970 | { 971 | "params": [ 972 | 95 973 | ], 974 | "type": "percentile" 975 | } 976 | ] 977 | ], 978 | "tags": [] 979 | } 980 | ], 981 | "thresholds": [], 982 | "timeFrom": null, 983 | "timeShift": null, 984 | "title": "http_req_blocked (95%ile)", 985 | "tooltip": { 986 | "shared": true, 987 | "sort": 0, 988 | "value_type": "individual" 989 | }, 990 | "type": "graph", 991 | "xaxis": { 992 | "buckets": null, 993 | "mode": "time", 994 | "name": null, 995 | "show": true, 996 | "values": [] 997 | }, 998 | "yaxes": [ 999 | { 1000 | "format": "ms", 1001 | "label": null, 1002 | "logBase": 1, 1003 | "max": null, 1004 | "min": null, 1005 | "show": true 1006 | }, 1007 | { 1008 | "format": "short", 1009 | "label": null, 1010 | "logBase": 1, 1011 | "max": null, 1012 | "min": null, 1013 | "show": true 1014 | } 1015 | ], 1016 | "yaxis": { 1017 | "align": false, 1018 | "alignLevel": null 1019 | } 1020 | } 1021 | ], 1022 | "refresh": "5s", 1023 | "schemaVersion": 16, 1024 | "style": "dark", 1025 | "tags": [], 1026 | "templating": { 1027 | "list": [] 1028 | }, 1029 | "time": { 1030 | "from": "now-5m", 1031 | "to": "now" 1032 | }, 1033 | "timepicker": { 1034 | "refresh_intervals": [ 1035 | "5s", 1036 | "10s", 1037 | "30s", 1038 | "1m", 1039 | "5m", 1040 | "15m", 1041 | "30m", 1042 | "1h", 1043 | "2h", 1044 | "1d" 1045 | ], 1046 | "time_options": [ 1047 | "5m", 1048 | "15m", 1049 | "1h", 1050 | "6h", 1051 | "12h", 1052 | "24h", 1053 | "2d", 1054 | "7d", 1055 | "30d" 1056 | ] 1057 | }, 1058 | "timezone": "browser", 1059 | "title": "k6", 1060 | "uid": "RgdVrzDZz", 1061 | "version": 4 1062 | } -------------------------------------------------------------------------------- /presentation-slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cajames/performance-testing-with-k6/33e7b31fe55a1678e1fb73d9d751c6ad44707dc3/presentation-slides.pdf -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Performance Testing with K6 2 | 3 | > Load testing workshop, demonstrating k6 4 | 5 | ## Video 6 | 7 | [![Performance Testing with k6 Video](https://img.youtube.com/vi/Hu1K2ZGJ_K4/0.jpg)](https://www.youtube.com/watch?v=Hu1K2ZGJ_K4) 8 | 9 | ## Getting started: 10 | - `docker-compose up -d influxdb grafana` 11 | - Load http://localhost:3000, and import the `grafana_dashboard.json` config to a new dashboard. 12 | - `docker-compose run k6 run /tests/01-simple/test.js` 13 | 14 | ## To use cloud run 15 | 16 | - Create an account with LoadImpact here to use the cloud run: [https://app.loadimpact.com/account/login](https://app.loadimpact.com/account/login) 17 | - Replace `LI_TOKEN` in the `Dockerfile` with your account token. 18 | - `docker-compose run k6 cloud /tests/01-simple/test.js` to run the test in the cloud 19 | 20 | Look through the k6 docs here: https://support.loadimpact.com/4.0/ -------------------------------------------------------------------------------- /tests/01-simple/test.js: -------------------------------------------------------------------------------- 1 | import http from "k6/http"; 2 | import { check, sleep } from "k6"; 3 | import { Counter } from "k6/metrics"; 4 | 5 | let ErrorCount = new Counter("errors"); 6 | 7 | export const options = { 8 | vus: 10, 9 | duration: "15s", 10 | thresholds: { 11 | errors: ["count<10"] 12 | } 13 | }; 14 | 15 | export default function() { 16 | const path = Math.random() < 0.9 ? "200" : "500"; 17 | 18 | let res = http.get(`https://httpbin.test.loadimpact.com/status/${path}`); 19 | let success = check(res, { 20 | "status is 200": r => r.status === 200 21 | }); 22 | if (!success) { 23 | ErrorCount.add(1); 24 | } 25 | 26 | sleep(2); 27 | } 28 | -------------------------------------------------------------------------------- /tests/02-stages/test.js: -------------------------------------------------------------------------------- 1 | import http from "k6/http"; 2 | import { check, sleep } from "k6"; 3 | import { Counter, Rate } from "k6/metrics"; 4 | 5 | /* 6 | * Stages (aka ramping) is how you, in code, specify the ramping of VUs. 7 | * That is, how many VUs should be active and generating traffic against 8 | * the target system at any specific point in time for the duration of 9 | * the test. 10 | * 11 | * The following stages configuration will result in up-flat-down ramping 12 | * profile over a 20s total test duration. 13 | */ 14 | 15 | let ErrorCount = new Counter("errors"); 16 | let ErrorRate = new Rate("error_rate"); 17 | 18 | export let options = { 19 | stages: [ 20 | // Ramp-up from 1 to 5 VUs in 10s 21 | { duration: "15s", target: 50 }, 22 | 23 | // Stay at rest on 5 VUs for 5s 24 | { duration: "30s", target: 50 }, 25 | 26 | // Ramp-down from 5 to 0 VUs for 5s 27 | { duration: "15s", target: 0 } 28 | ], 29 | thresholds: { 30 | error_rate: ["rate<0.1"] 31 | } 32 | }; 33 | 34 | export default function() { 35 | const status = Math.random() < 0.9 ? "200" : "500"; 36 | let res = http.get(`http://httpbin.org/status/${status}`); 37 | let success = check(res, { 38 | "status is 200": r => r.status === 200 39 | }); 40 | if (!success) { 41 | ErrorCount.add(1); 42 | ErrorRate.add(true); 43 | } else { 44 | ErrorRate.add(false); 45 | } 46 | 47 | sleep(0.5); 48 | } 49 | --------------------------------------------------------------------------------