neoload 1.3.19.dev2__tar.gz → 1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. {neoload-1.3.19.dev2 → neoload-1.4.0}/PKG-INFO +11 -28
  2. {neoload-1.3.19.dev2 → neoload-1.4.0}/README.md +10 -27
  3. neoload-1.4.0/neoload/commands/__init__.py +2 -0
  4. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/project.py +44 -3
  5. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/report.py +3 -16
  6. neoload-1.4.0/neoload/commands/validate.py +30 -0
  7. neoload-1.4.0/neoload/neoload_cli_lib/resources.py +14 -0
  8. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/schema_validation.py +65 -28
  9. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/user_data.py +48 -18
  10. {neoload-1.3.19.dev2/examples/as-code-demo → neoload-1.4.0/neoload/resources/templates}/default.yaml +2 -4
  11. neoload-1.4.0/neoload/version.py +1 -0
  12. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload.egg-info/PKG-INFO +11 -28
  13. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload.egg-info/SOURCES.txt +4 -4
  14. neoload-1.4.0/tests/commands/project/test_project_create.py +52 -0
  15. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_validate.py +9 -32
  16. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/conftest.py +1 -2
  17. neoload-1.4.0/tests/neoload_cli_lib/test_SchemaValidation.py +149 -0
  18. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_include_resolution.py +7 -0
  19. neoload-1.4.0/tests/resources/jinja/__init__.py +0 -0
  20. neoload-1.3.19.dev2/neoload/commands/__init__.py +0 -2
  21. neoload-1.3.19.dev2/neoload/commands/checkvu.py +0 -98
  22. neoload-1.3.19.dev2/neoload/commands/validate.py +0 -19
  23. neoload-1.3.19.dev2/neoload/neoload_cli_lib/checkvu_runner.py +0 -189
  24. neoload-1.3.19.dev2/neoload/version.py +0 -1
  25. neoload-1.3.19.dev2/tests/commands/test_checkvu.py +0 -207
  26. neoload-1.3.19.dev2/tests/neoload_cli_lib/test_SchemaValidation.py +0 -43
  27. {neoload-1.3.19.dev2 → neoload-1.4.0}/.github/workflows/python-integration-tests.yml +0 -0
  28. {neoload-1.3.19.dev2 → neoload-1.4.0}/.github/workflows/python-package.yml +0 -0
  29. {neoload-1.3.19.dev2 → neoload-1.4.0}/.github/workflows/python-post-release-changelog-pr.yml +0 -0
  30. {neoload-1.3.19.dev2 → neoload-1.4.0}/.github/workflows/python-release.yml +0 -0
  31. {neoload-1.3.19.dev2 → neoload-1.4.0}/.gitignore +0 -0
  32. {neoload-1.3.19.dev2 → neoload-1.4.0}/.travis.yml +0 -0
  33. {neoload-1.3.19.dev2 → neoload-1.4.0}/CHANGELOG.md +0 -0
  34. {neoload-1.3.19.dev2 → neoload-1.4.0}/LICENSE +0 -0
  35. {neoload-1.3.19.dev2 → neoload-1.4.0}/MANIFEST.in +0 -0
  36. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/docker/Dockerfile +0 -0
  37. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/aws/.nlignore +0 -0
  38. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/aws/buildspec.yaml +0 -0
  39. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/azure_devops/.nlignore +0 -0
  40. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/azure_devops/Azure_DevOps_Pipeline_NeoLoad_CLI.jpg +0 -0
  41. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/azure_devops/Azure_DevOps_Pipeline_NeoLoad_SLA_jUnit.jpg +0 -0
  42. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/azure_devops/README.md +0 -0
  43. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/azure_devops/neoload-cli-docker.yml +0 -0
  44. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/azure_devops/neoload-cli-dyninfra.yml +0 -0
  45. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/bamboo-specs/.nlignore +0 -0
  46. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/bamboo-specs/Bamboo_Pipeline_NeoLoad_SLA_jUnit.jpg +0 -0
  47. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/bamboo-specs/README.md +0 -0
  48. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/bamboo-specs/bamboo-v1.yaml +0 -0
  49. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/bamboo-specs/bamboo-v2.yaml +0 -0
  50. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/github/neoload-github-actions-demo.yml +0 -0
  51. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/gitlab/.nlignore +0 -0
  52. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/gitlab/openshift.gitlab-ci.yml +0 -0
  53. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/jenkins/Jenkinsfile_dyninfra +0 -0
  54. {neoload-1.3.19.dev2 → neoload-1.4.0}/examples/pipelines/jenkins/Jenkinsfile_slafails +0 -0
  55. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/__init__.py +0 -0
  56. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/__main__.py +0 -0
  57. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/config.py +0 -0
  58. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/docker.py +0 -0
  59. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/fastfail.py +0 -0
  60. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/login.py +0 -0
  61. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/logout.py +0 -0
  62. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/logs.py +0 -0
  63. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/logs_url.py +0 -0
  64. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/run.py +0 -0
  65. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/status.py +0 -0
  66. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/stop.py +0 -0
  67. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/test_results.py +0 -0
  68. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/test_settings.py +0 -0
  69. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/wait.py +0 -0
  70. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/workspaces.py +0 -0
  71. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/commands/zones.py +0 -0
  72. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/__init__.py +0 -0
  73. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/bad_as_code_exception.py +0 -0
  74. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/cli_exception.py +0 -0
  75. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/config_global.py +0 -0
  76. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/displayer.py +0 -0
  77. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/docker_lib.py +0 -0
  78. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/filtering.py +0 -0
  79. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/hooks.py +0 -0
  80. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/logs_tools.py +0 -0
  81. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/logs_traduction_map.py +0 -0
  82. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/name_resolver.py +0 -0
  83. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/neoLoad_project.py +0 -0
  84. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/paths.py +0 -0
  85. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/rest_crud.py +0 -0
  86. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/running_tools.py +0 -0
  87. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/neoload_cli_lib/tools.py +0 -0
  88. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/__init__.py +0 -0
  89. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/__init__.py +0 -0
  90. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/builtin_console_summary.j2 +0 -0
  91. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/builtin_transactions_csv.j2 +0 -0
  92. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/common/common.js +0 -0
  93. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/common/external_data.html.j2 +0 -0
  94. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/common/general_details.html.j2 +0 -0
  95. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/common/header.j2 +0 -0
  96. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/common/hits_per_second.html.j2 +0 -0
  97. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/common/running_vus.html.j2 +0 -0
  98. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/common/styles.css +0 -0
  99. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/common/transactions.html.j2 +0 -0
  100. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/common/workload_characteristics.html.j2 +0 -0
  101. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/custom_transactions_export.j2 +0 -0
  102. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/sample-custom-report.html.j2 +0 -0
  103. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/sample-trends-report.html.j2 +0 -0
  104. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/trends/general_details.html.j2 +0 -0
  105. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/trends/transaction_trends.html.j2 +0 -0
  106. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/resources/jinja/trends/trends.js +0 -0
  107. {neoload-1.3.19.dev2/tests → neoload-1.4.0/neoload/resources/templates}/__init__.py +0 -0
  108. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload/version_manager.py +0 -0
  109. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload.egg-info/dependency_links.txt +0 -0
  110. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload.egg-info/entry_points.txt +0 -0
  111. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload.egg-info/requires.txt +0 -0
  112. {neoload-1.3.19.dev2 → neoload-1.4.0}/neoload.egg-info/top_level.txt +0 -0
  113. {neoload-1.3.19.dev2 → neoload-1.4.0}/notes/PSB_20200421_TODO.txt +0 -0
  114. {neoload-1.3.19.dev2 → neoload-1.4.0}/notes/acceptance.txt +0 -0
  115. {neoload-1.3.19.dev2 → neoload-1.4.0}/pull_request_template.md +0 -0
  116. {neoload-1.3.19.dev2 → neoload-1.4.0}/pytest.ini +0 -0
  117. {neoload-1.3.19.dev2 → neoload-1.4.0}/requirements.txt +0 -0
  118. {neoload-1.3.19.dev2 → neoload-1.4.0}/resources/as-code.latest.schema.json +0 -0
  119. {neoload-1.3.19.dev2 → neoload-1.4.0}/setup.cfg +0 -0
  120. {neoload-1.3.19.dev2 → neoload-1.4.0}/setup.py +0 -0
  121. {neoload-1.3.19.dev2 → neoload-1.4.0}/sonar-project.properties +0 -0
  122. {neoload-1.3.19.dev2/tests/resources → neoload-1.4.0/tests}/__init__.py +0 -0
  123. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/docker/test_docker_cleanups.py +0 -0
  124. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/docker/test_docker_connections.py +0 -0
  125. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/docker/test_docker_hooks.py +0 -0
  126. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/fastfail/test_fastfail_slas.py +0 -0
  127. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/project/test_upload.py +0 -0
  128. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/project/test_upload_with_password.py +0 -0
  129. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/report/conftest.py +0 -0
  130. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/report/test_report.py +0 -0
  131. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/report/test_report_json_output.py +0 -0
  132. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/report/test_report_templates.py +0 -0
  133. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/report/test_report_transactions.py +0 -0
  134. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/report/test_report_trends.py +0 -0
  135. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/report/test_trends_json_output.py +0 -0
  136. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/report/test_trends_templates.py +0 -0
  137. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/status/test_status_with_names.py +0 -0
  138. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_config.py +0 -0
  139. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_login.py +0 -0
  140. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_logout.py +0 -0
  141. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_logs/test_logs.py +0 -0
  142. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_logs_url.py +0 -0
  143. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_results/test_result_delete.py +0 -0
  144. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_results/test_result_ls.py +0 -0
  145. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_results/test_result_patch.py +0 -0
  146. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_results/test_result_put.py +0 -0
  147. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_run.py +0 -0
  148. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_settings/test_create.py +0 -0
  149. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_settings/test_createorpatch.py +0 -0
  150. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_settings/test_delete.py +0 -0
  151. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_settings/test_ls.py +0 -0
  152. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_settings/test_patch.py +0 -0
  153. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/test_settings/test_put.py +0 -0
  154. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/wait/test_wait.py +0 -0
  155. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/workspaces/test_workspace_ls.py +0 -0
  156. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/workspaces/test_workspace_use.py +0 -0
  157. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/commands/zones/test_zones.py +0 -0
  158. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/helpers/__init__.py +0 -0
  159. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/helpers/test_utils.py +0 -0
  160. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/expected/fastfail.log +0 -0
  161. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/expected/junit-sla.xml +0 -0
  162. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/expected/run.log +0 -0
  163. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/expected/summary.txt +0 -0
  164. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/runAllScripts.sh +0 -0
  165. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/cleanup.sh +0 -0
  166. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/project.upload.test.sh +0 -0
  167. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/results.delete.test.sh +0 -0
  168. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/results.patch.test.sh +0 -0
  169. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/results.put.test.sh +0 -0
  170. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/run.fastfail.test.sh +0 -0
  171. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/run.oneliner.test.sh +0 -0
  172. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/run.test.sh +0 -0
  173. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/settings.create.delete.test.sh +0 -0
  174. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/settings.patch.test.sh +0 -0
  175. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/settings.put.test.sh +0 -0
  176. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/validate.test.sh +0 -0
  177. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/wait.test.sh +0 -0
  178. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/integration/scripts/zones.ls.test.sh +0 -0
  179. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_displayer.py +0 -0
  180. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_docker.py +0 -0
  181. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_etag_caching.py +0 -0
  182. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_filtering.py +0 -0
  183. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_rest_crud.py +0 -0
  184. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_running_tools.py +0 -0
  185. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_tools.py +0 -0
  186. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_user_data.py +0 -0
  187. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_cli_lib/test_validator_selection.py +0 -0
  188. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/.nlignore +0 -0
  189. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/broken_yaml.yaml +0 -0
  190. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/circular_includes/a.yaml +0 -0
  191. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/circular_includes/b.yaml +0 -0
  192. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/empty.yaml +0 -0
  193. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/example_1/.gitlab-ci.yml +0 -0
  194. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/example_1/.nlignore +0 -0
  195. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/example_1/data/cities.csv +0 -0
  196. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/example_1/default.yaml +0 -0
  197. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/example_1/paths/geosearch_get.yaml +0 -0
  198. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/example_1/slas/prod.yaml +0 -0
  199. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/example_1/slas/uat.yaml +0 -0
  200. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/example_1.zip +0 -0
  201. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/example_2.zip +0 -0
  202. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/invalid_to_schema.yaml +0 -0
  203. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/neoload_projects/simpledemo.yml +0 -0
  204. {neoload-1.3.19.dev2/tests/resources/jinja → neoload-1.4.0/tests/resources}/__init__.py +0 -0
  205. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/expected_neoload_junit_slas.xml +0 -0
  206. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/expected_summary_text_no_sla.txt +0 -0
  207. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/expected_summary_text_with_sla.txt +0 -0
  208. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/expected_custom_report.html +0 -0
  209. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/expected_custom_report_filtered.html +0 -0
  210. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/expected_custom_transactions.csv +0 -0
  211. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/expected_report.json +0 -0
  212. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/expected_report_filtered.json +0 -0
  213. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/expected_template_transactions.json +0 -0
  214. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/expected_template_transactions_csv.csv +0 -0
  215. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/expected_template_trends.html +0 -0
  216. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/expected_trends.json +0 -0
  217. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/raw_expected_custom_report.html +0 -0
  218. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/resources/report/raw_expected_report.json +0 -0
  219. {neoload-1.3.19.dev2 → neoload-1.4.0}/tests/test_readme.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: neoload
3
- Version: 1.3.19.dev2
3
+ Version: 1.4.0
4
4
  Summary: A command-line native utility for launching and observing NeoLoad performance tests
5
5
  Home-page: https://github.com/Neotys-Labs/neoload-cli
6
6
  Author: Neotys
@@ -215,24 +215,6 @@ Pressing `Ctrl+C` causes the CLI to attempt to stop the test gracefully.
215
215
  neoload stop # Sends the stop signal to the test and waits until it ends.
216
216
  ```
217
217
 
218
- ## CheckVU an as-code project
219
- This command runs a CheckVU on an as-code project: it executes a single virtual user to verify that the project runs. It is meant to support fast iteration on as-code projects (generate -> checkvu -> fix).
220
-
221
- It delegates to a standalone headless CheckVU JAR and streams the JAR's output and exit code directly.
222
-
223
- ```
224
- Usage: neoload checkvu [OPTIONS] PROJECT_FILE
225
- Help: neoload checkvu --help
226
- neoload checkvu default.yaml
227
- neoload checkvu -u myUser default.yaml
228
- ```
229
- - `PROJECT_FILE` is a path to an as-code yaml file. The CLI validates it against the as-code schema first (same as `neoload validate`), using `-s, --as-code-schema` to override the default schema.
230
- - `-e, --engine-jar <path-or-url>` resolves the CheckVU JAR: a local file path or a download URL. If omitted, a previously cached JAR is reused, otherwise a default URL is used to download the latest JAR.
231
- - `-j, --java` selects the java executable; by default `JAVA_HOME/bin/java` then `java` on the PATH. Java 21+ is required and verified before running.
232
- - `-w, --work-dir <path>` sets the directory used for engine files and logs. Defaults to a temporary directory deleted afterwards unless `--keep-temp-work-dir` is set; a directory you supply yourself is never deleted.
233
- - `--app-proxy`, `--app-proxy-username` and `--app-proxy-bypass` configure the proxy used for application traffic. The proxy password is set with `NEOLOAD_CHECK_VU_APP_PROXY_PASSWORD` environment variable instead so it never shows up in the process list or CI logs.
234
- - `--controller-properties` and `--load-generator-properties` are advanced options to merge a `.properties` file into the JAR's embedded `controller.properties` / `agent.properties`.
235
-
236
218
  ## Reporting
237
219
 
238
220
  The NeoLoad CLI provides basic support for viewing and exporting test results.
@@ -418,9 +400,14 @@ The configuration lets you customize the CLI's behavior. For now, it is only use
418
400
 
419
401
  ### As-Code Demo Project
420
402
 
421
- [`examples/as-code-demo`](examples/as-code-demo) contains a NeoLoad As-Code YAML project that works out-of-the-box:
422
- no NeoLoad Web project, no manual scenario setup - just point NeoLoad at
423
- [`default.yaml`](examples/as-code-demo/default.yaml) and run.
403
+ Create a starter NeoLoad As-Code YAML project with:
404
+
405
+ ```
406
+ neoload project create DemoWebShop
407
+ ```
408
+
409
+ This scaffolds `DemoWebShop/default.yaml` from the bundled Demo Web Shop template —
410
+ no NeoLoad Web project, no manual scenario setup.
424
411
 
425
412
  Target: [Tricentis Demo Web Shop](https://demowebshop.tricentis.com/) (nopCommerce demo).
426
413
 
@@ -435,16 +422,12 @@ The `BuyAsGuest` user path walks through a typical guest purchase:
435
422
 
436
423
  It uses two variables (`product_id`, `quantity`) and a single population (`GuestShoppers`)
437
424
 
438
- Run CheckVU against the project:
439
- ```
440
- neoload checkvu examples/as-code-demo/default.yaml
441
- ```
442
-
443
425
  Run the full test:
444
426
  ```
427
+ neoload project create DemoWebShop
445
428
  neoload login $NLW_TOKEN \
446
429
  test-settings --zone defaultzone --lgs 1 createorpatch DemoWebShopTest \
447
- project --path examples/as-code-demo/default.yaml upload DemoWebShopTest \
430
+ project --path DemoWebShop/default.yaml upload DemoWebShopTest \
448
431
  run --scenario DemoWebShop
449
432
  ```
450
433
 
@@ -176,24 +176,6 @@ Pressing `Ctrl+C` causes the CLI to attempt to stop the test gracefully.
176
176
  neoload stop # Sends the stop signal to the test and waits until it ends.
177
177
  ```
178
178
 
179
- ## CheckVU an as-code project
180
- This command runs a CheckVU on an as-code project: it executes a single virtual user to verify that the project runs. It is meant to support fast iteration on as-code projects (generate -> checkvu -> fix).
181
-
182
- It delegates to a standalone headless CheckVU JAR and streams the JAR's output and exit code directly.
183
-
184
- ```
185
- Usage: neoload checkvu [OPTIONS] PROJECT_FILE
186
- Help: neoload checkvu --help
187
- neoload checkvu default.yaml
188
- neoload checkvu -u myUser default.yaml
189
- ```
190
- - `PROJECT_FILE` is a path to an as-code yaml file. The CLI validates it against the as-code schema first (same as `neoload validate`), using `-s, --as-code-schema` to override the default schema.
191
- - `-e, --engine-jar <path-or-url>` resolves the CheckVU JAR: a local file path or a download URL. If omitted, a previously cached JAR is reused, otherwise a default URL is used to download the latest JAR.
192
- - `-j, --java` selects the java executable; by default `JAVA_HOME/bin/java` then `java` on the PATH. Java 21+ is required and verified before running.
193
- - `-w, --work-dir <path>` sets the directory used for engine files and logs. Defaults to a temporary directory deleted afterwards unless `--keep-temp-work-dir` is set; a directory you supply yourself is never deleted.
194
- - `--app-proxy`, `--app-proxy-username` and `--app-proxy-bypass` configure the proxy used for application traffic. The proxy password is set with `NEOLOAD_CHECK_VU_APP_PROXY_PASSWORD` environment variable instead so it never shows up in the process list or CI logs.
195
- - `--controller-properties` and `--load-generator-properties` are advanced options to merge a `.properties` file into the JAR's embedded `controller.properties` / `agent.properties`.
196
-
197
179
  ## Reporting
198
180
 
199
181
  The NeoLoad CLI provides basic support for viewing and exporting test results.
@@ -379,9 +361,14 @@ The configuration lets you customize the CLI's behavior. For now, it is only use
379
361
 
380
362
  ### As-Code Demo Project
381
363
 
382
- [`examples/as-code-demo`](examples/as-code-demo) contains a NeoLoad As-Code YAML project that works out-of-the-box:
383
- no NeoLoad Web project, no manual scenario setup - just point NeoLoad at
384
- [`default.yaml`](examples/as-code-demo/default.yaml) and run.
364
+ Create a starter NeoLoad As-Code YAML project with:
365
+
366
+ ```
367
+ neoload project create DemoWebShop
368
+ ```
369
+
370
+ This scaffolds `DemoWebShop/default.yaml` from the bundled Demo Web Shop template —
371
+ no NeoLoad Web project, no manual scenario setup.
385
372
 
386
373
  Target: [Tricentis Demo Web Shop](https://demowebshop.tricentis.com/) (nopCommerce demo).
387
374
 
@@ -396,16 +383,12 @@ The `BuyAsGuest` user path walks through a typical guest purchase:
396
383
 
397
384
  It uses two variables (`product_id`, `quantity`) and a single population (`GuestShoppers`)
398
385
 
399
- Run CheckVU against the project:
400
- ```
401
- neoload checkvu examples/as-code-demo/default.yaml
402
- ```
403
-
404
386
  Run the full test:
405
387
  ```
388
+ neoload project create DemoWebShop
406
389
  neoload login $NLW_TOKEN \
407
390
  test-settings --zone defaultzone --lgs 1 createorpatch DemoWebShopTest \
408
- project --path examples/as-code-demo/default.yaml upload DemoWebShopTest \
391
+ project --path DemoWebShop/default.yaml upload DemoWebShopTest \
409
392
  run --scenario DemoWebShop
410
393
  ```
411
394
 
@@ -0,0 +1,2 @@
1
+ __all__ = ["config", "docker", "fastfail", "login", "logout", "logs_url", "project", "run", "status", "stop", "test_results", "test_settings",
2
+ "validate", "wait", "workspaces", "zones", "report"]
@@ -4,18 +4,30 @@ import click
4
4
  import urllib.parse as urlparse
5
5
  from commands import test_settings
6
6
  from pathlib import Path
7
- from neoload_cli_lib import user_data, tools, rest_crud, neoLoad_project
7
+ from neoload_cli_lib import user_data, tools, rest_crud, neoLoad_project, cli_exception, resources
8
+
9
+ __template_namespace = 'resources.templates'
10
+ __template_filename = 'default.yaml'
11
+ __project_yaml_name = 'default.yaml'
8
12
 
9
13
 
10
14
  @click.command()
11
- @click.argument("command", required=True, type=click.Choice(['up', 'upload', 'meta']))
15
+ @click.argument("command", required=True, type=click.Choice(['create', 'up', 'upload', 'meta']))
12
16
  @click.option("--path", "-p", type=click.Path(exists=True), default=os.getcwd(),
13
17
  help="Path of project folder, zip or yml file. . is default value")
14
18
  @click.option("--save", "-s", type=click.Path(exists=False),
15
19
  help="Path to a (non-existent) file ending in .zip to preserve what was uploaded")
16
20
  @click.argument("name_or_id", type=str, required=False)
17
21
  def cli(command, name_or_id, path, save):
18
- """Upload and list scenario from settings"""
22
+ """
23
+ create # Create a local as-code project folder from the demo yaml template.
24
+ upload # Upload a project to NeoLoad Web test settings (alias: up) .
25
+ meta # Display project metadata from the current test settings .
26
+ """
27
+ if command == "create":
28
+ create_local_project(name_or_id)
29
+ return
30
+
19
31
  rest_crud.set_current_command()
20
32
  if not name_or_id or name_or_id == "cur":
21
33
  name_or_id = user_data.get_meta(test_settings.meta_key)
@@ -75,3 +87,32 @@ def meta_data(setting_id):
75
87
 
76
88
  def get_endpoint(settings_id: str):
77
89
  return rest_crud.base_endpoint_with_workspace() + '/tests/' + settings_id + "/project"
90
+
91
+
92
+ def create_local_project(project_name):
93
+ if project_name is None:
94
+ raise cli_exception.CliException("Missing project name. Usage: neoload project create <project-name>")
95
+ project_name = project_name.strip()
96
+ if not project_name or project_name in ('.', '..'):
97
+ raise cli_exception.CliException(f"Invalid project name: '{project_name}'.")
98
+ if os.path.sep in project_name or (os.path.altsep and os.path.altsep in project_name):
99
+ raise cli_exception.CliException(
100
+ f"Invalid project name: '{project_name}'. Use a single folder name, not a path."
101
+ )
102
+
103
+ if os.path.exists(project_name):
104
+ raise cli_exception.CliException(
105
+ f"Cannot create project '{project_name}': path already exists."
106
+ )
107
+
108
+ yaml_path = os.path.join(project_name, __project_yaml_name)
109
+ try:
110
+ template = resources.get_resource_as_string(__template_namespace, __template_filename)
111
+ os.mkdir(project_name)
112
+ with open(yaml_path, 'w', encoding='utf-8') as yaml_file:
113
+ yaml_file.write(template)
114
+ except OSError as err:
115
+ raise cli_exception.CliException(f"Failed to create project '{project_name}': {err}") from err
116
+
117
+ print(f"Project '{project_name}' created successfully.")
118
+ print(f" {yaml_path}")
@@ -8,7 +8,7 @@ import statistics
8
8
  import math
9
9
  import time
10
10
 
11
- from neoload_cli_lib import tools, rest_crud, user_data, displayer, cli_exception
11
+ from neoload_cli_lib import tools, rest_crud, user_data, displayer, cli_exception, resources
12
12
  from dateutil.relativedelta import relativedelta
13
13
 
14
14
  import logging
@@ -165,19 +165,6 @@ def parse_filter_spec(filter_spec):
165
165
  return ret
166
166
 
167
167
 
168
- def get_resource_as_string(namespace, file):
169
- try:
170
- import importlib.resources as pkg_resources
171
- except ImportError:
172
- # Try backported to PY<37 `importlib_resources`.
173
- import importlib_resources as pkg_resources
174
-
175
- logging.debug({'namespace': namespace, 'file': file})
176
- if hasattr(pkg_resources, 'files'): # files is present from Python 3.9
177
- return pkg_resources.files(namespace).joinpath(file).read_text()
178
- return pkg_resources.read_text(namespace, file)
179
-
180
-
181
168
  def split_path(path):
182
169
  sep = os.path.sep
183
170
  if sep not in path: sep = '/' # try internal posix style
@@ -1131,11 +1118,11 @@ def unique(seq, idfun=None):
1131
1118
 
1132
1119
 
1133
1120
  def get_builtin_template_transaction_csv():
1134
- return get_resource_as_string('resources.jinja', 'builtin_transactions_csv.j2').strip()
1121
+ return resources.get_resource_as_string('resources.jinja', 'builtin_transactions_csv.j2').strip()
1135
1122
 
1136
1123
 
1137
1124
  def get_builtin_template_console_summary():
1138
- return get_resource_as_string('resources.jinja', 'builtin_console_summary.j2').strip()
1125
+ return resources.get_resource_as_string('resources.jinja', 'builtin_console_summary.j2').strip()
1139
1126
 
1140
1127
 
1141
1128
  def print_extended_help():
@@ -0,0 +1,30 @@
1
+ import click
2
+ from neoload_cli_lib import cli_exception
3
+ import neoload_cli_lib.schema_validation as schema_validation
4
+ import os
5
+
6
+ @click.command()
7
+ @click.option('--schema-url', help="The URL (or local path) to the as-code schema. "
8
+ "When omitted, download schemas/v<schemaVersion>/as-code.schema.json from neoload-models (v3). "
9
+ "If schemaVersion is absent, use schemas/v3.0/as-code.schema.json.",
10
+ metavar="URL", default=None)
11
+ @click.option('--refresh', is_flag=True, help="THIS OPTION IS NOW USELESS", hidden=True)
12
+ @click.option('--ssl-cert', default="", help="Path to SSL certificate or write False to disable certificate checking")
13
+ @click.argument('file')
14
+ def cli(file, refresh, schema_url, ssl_cert):
15
+ """Verify that the yaml FILE matches the neoload as-code file format"""
16
+
17
+ force_schema = os.environ.get('NLCLI_FORCE_SCHEMA')
18
+ if force_schema is not None and len(force_schema) > 0:
19
+ schema_url = force_schema
20
+
21
+ path = os.path.abspath(file)
22
+ try:
23
+ if os.path.isdir(path):
24
+ schema_validation.validate_yaml_dir(path, schema_url, ssl_cert)
25
+ print('All yaml files underneath the path provided are valid.')
26
+ else:
27
+ schema_validation.validate_yaml(file, schema_url, ssl_cert)
28
+ print('Yaml file is valid.')
29
+ except Exception as err:
30
+ raise cli_exception.CliException(str(err))
@@ -0,0 +1,14 @@
1
+ import logging
2
+
3
+
4
+ def get_resource_as_string(namespace, file):
5
+ try:
6
+ import importlib.resources as pkg_resources
7
+ except ImportError:
8
+ # Try backported to PY<37 `importlib_resources`.
9
+ import importlib_resources as pkg_resources
10
+
11
+ logging.debug({'namespace': namespace, 'file': file})
12
+ if hasattr(pkg_resources, 'files'): # files is present from Python 3.9
13
+ return pkg_resources.files(namespace).joinpath(file).read_text(encoding='utf-8')
14
+ return pkg_resources.read_text(namespace, file, encoding='utf-8')
@@ -16,10 +16,12 @@ import gitignorefile
16
16
  from neoload_cli_lib.neoLoad_project import is_not_to_be_included
17
17
 
18
18
  YAML_NOT_CONFIRM_MESSAGE = "YAML does not confirm to NeoLoad DSL schema."
19
- __default_schema_url = "https://raw.githubusercontent.com/Neotys-Labs/neoload-models/v3/neoload-project/src/main/resources/as-code.latest.schema.json"
19
+ __models_raw_root = "https://raw.githubusercontent.com/Neotys-Labs/neoload-models/v3"
20
+ __compatibility_url = __models_raw_root + "/schemas/compatibility.json"
21
+ __default_schema_version = "3.0"
20
22
 
21
23
  _MERGED_ARRAY_FIELDS = ['sla_profiles', 'variables', 'servers', 'user_paths', 'populations', 'scenarios', 'frameworks']
22
- _MERGED_SPECIAL_FIELDS = set(_MERGED_ARRAY_FIELDS) | {'project_settings', 'name', 'includes'}
24
+ _MERGED_SPECIAL_FIELDS = set(_MERGED_ARRAY_FIELDS) | {'project_settings', 'name', 'includes', 'schemaVersion'}
23
25
 
24
26
 
25
27
  def parse_yaml_file(file_path):
@@ -55,6 +57,10 @@ def merge_projects(projects):
55
57
  if project.get('name'):
56
58
  merged['name'] = project['name']
57
59
 
60
+ for project in projects:
61
+ if 'schemaVersion' in project and project.get('schemaVersion') is not None:
62
+ merged['schemaVersion'] = project['schemaVersion']
63
+
58
64
  # Carry over any other/unrecognized top-level key too, so genuinely
59
65
  # invalid content isn't silently dropped by the merge instead of being
60
66
  # caught by the schema (e.g. root "additionalProperties: false").
@@ -112,8 +118,58 @@ def resolve_and_merge_project(entry_file_path):
112
118
  return merge_projects(resolved)
113
119
 
114
120
 
121
+ def normalize_schema_version(value):
122
+ """Return the schemaVersion contract as a string. Absent values default to 3.0."""
123
+ if value is None or value == '':
124
+ return __default_schema_version
125
+ if isinstance(value, bool):
126
+ raise cli_exception.CliException('Invalid schemaVersion: %s' % value)
127
+ if isinstance(value, int):
128
+ return '%s.0' % value
129
+ if isinstance(value, float):
130
+ if value == int(value):
131
+ return '%s.0' % int(value)
132
+ return str(value)
133
+ return str(value).strip()
134
+
135
+
136
+ def schema_url_for_version(version):
137
+ return '%s/schemas/v%s/as-code.schema.json' % (__models_raw_root, version)
138
+
139
+
140
+ def load_supported_schema_versions(ssl_cert=''):
141
+ """Supported versions are the keys of neoload-models schemas/compatibility.json (v3)."""
142
+ compatibility_json, _etag, _not_modified = get_network_schema_by_spec(__compatibility_url, ssl_cert)
143
+ if compatibility_json is None:
144
+ raise cli_exception.CliException(
145
+ 'Could not load schema compatibility matrix from %s' % __compatibility_url)
146
+ try:
147
+ compatibility = json.loads(compatibility_json)
148
+ except JSONDecodeError as err:
149
+ raise cli_exception.CliException(
150
+ 'Invalid schema compatibility matrix at %s:\n%s' % (__compatibility_url, err))
151
+ if not isinstance(compatibility, dict) or not compatibility:
152
+ raise cli_exception.CliException(
153
+ 'Schema compatibility matrix at %s does not list any versions.' % __compatibility_url)
154
+ return compatibility
155
+
156
+
157
+ def resolve_schema_spec(project_object, schema_spec=None, ssl_cert=''):
158
+ """Pick the GitHub schema URL from schemaVersion, unless the caller overrode it."""
159
+ if schema_spec is not None:
160
+ return schema_spec, None
161
+ version = normalize_schema_version((project_object or {}).get('schemaVersion'))
162
+ compatibility = load_supported_schema_versions(ssl_cert)
163
+ if version not in compatibility:
164
+ supported = ', '.join(sorted(compatibility.keys()))
165
+ raise cli_exception.CliException(
166
+ 'Unsupported schemaVersion "%s". Supported versions: %s' % (version, supported))
167
+ return schema_url_for_version(version), version
168
+
169
+
115
170
  def validate_project_object(project_object, schema_spec, ssl_cert='', check_schema=True, label=None):
116
- json_schema = init_yaml_schema_with_checks(schema_spec,ssl_cert,check_schema)
171
+ schema_spec, schema_key = resolve_schema_spec(project_object, schema_spec, ssl_cert)
172
+ json_schema = init_yaml_schema_with_checks(schema_spec, ssl_cert, check_schema, schema_key=schema_key)
117
173
  try:
118
174
  schema_as_object = json.loads(json_schema)
119
175
  except JSONDecodeError as err:
@@ -207,10 +263,10 @@ def validate_yaml_dir(path, schema_spec, ssl_cert='',continue_on_error=True):
207
263
  raise ValueError('One or more errors in files underneath this directory.')
208
264
 
209
265
 
210
- def init_yaml_schema_with_checks(schema_spec, ssl_cert='', check_schema=True):
211
- json_schema = get_yaml_schema(False)
266
+ def init_yaml_schema_with_checks(schema_spec, ssl_cert='', check_schema=True, schema_key=None):
267
+ json_schema = get_yaml_schema(False, schema_key=schema_key)
212
268
  if json_schema is not None:
213
- cached_etag = get_yaml_schema_etag()
269
+ cached_etag = get_yaml_schema_etag(schema_key=schema_key)
214
270
  if cached_etag:
215
271
  logging.info('Loaded schema and ETag from disk cache.')
216
272
  else:
@@ -222,13 +278,11 @@ def init_yaml_schema_with_checks(schema_spec, ssl_cert='', check_schema=True):
222
278
  if not check_schema:
223
279
  return json_schema
224
280
 
225
- schema_spec_remote = __default_schema_url
226
- if schema_spec is None: schema_spec = schema_spec_remote
227
281
  logging.debug("Checking schema source for changes %s" %schema_spec)
228
282
 
229
283
  try:
230
284
  if is_network_spec(schema_spec):
231
- cached_etag = get_yaml_schema_etag() if json_schema is not None else None
285
+ cached_etag = get_yaml_schema_etag(schema_key=schema_key) if json_schema is not None else None
232
286
  json_schema_spec, response_etag, not_modified = get_network_schema_by_spec(schema_spec, ssl_cert, cached_etag)
233
287
  if not_modified:
234
288
  logging.info('Remote schema unchanged since last download (ETag match) - using cached schema.')
@@ -239,7 +293,7 @@ def init_yaml_schema_with_checks(schema_spec, ssl_cert='', check_schema=True):
239
293
  else:
240
294
  logging.info('Cached schema updated from remote source (no ETag).')
241
295
  json_schema = json_schema_spec
242
- update_schema(json_schema_spec, response_etag)
296
+ update_schema(json_schema_spec, response_etag, schema_key=schema_key)
243
297
  else:
244
298
  json_schema = None
245
299
  else:
@@ -253,7 +307,7 @@ def init_yaml_schema_with_checks(schema_spec, ssl_cert='', check_schema=True):
253
307
  if hash_disk != hash_spec:
254
308
  logging.info('Cached schema differs from source!')
255
309
  json_schema = json_schema_spec
256
- update_schema(json_schema_spec)
310
+ update_schema(json_schema_spec, schema_key=schema_key)
257
311
  else:
258
312
  logging.info('No differences between cached and remote schema.')
259
313
  except Exception as err:
@@ -308,20 +362,3 @@ def get_json_schema_by_spec(schema_spec, ssl_cert):
308
362
 
309
363
  return json_schema_spec
310
364
 
311
-
312
- def validate_path(file, schema_url, ssl_cert=''):
313
- """Validates an as-code yaml file against the schema from NLCLI_FORCE_SCHEMA
314
- or downloaded from given URL or from the defautl URL."""
315
- force_schema = os.environ.get('NLCLI_FORCE_SCHEMA')
316
- if force_schema is not None and len(force_schema) > 0:
317
- schema_url = force_schema
318
-
319
- path = os.path.abspath(file)
320
- try:
321
- if os.path.isdir(path):
322
- validate_yaml_dir(path, schema_url, ssl_cert)
323
- return 'All yaml files underneath the path provided are valid.'
324
- validate_yaml(file, schema_url, ssl_cert)
325
- return 'Yaml file is valid.'
326
- except Exception as err:
327
- raise cli_exception.CliException(str(err))
@@ -18,6 +18,16 @@ CONFIG_FILE = __local_file if os.path.exists(__local_file) else os.path.join(__c
18
18
  __yaml_schema_file = os.path.join(__config_dir, "yaml_schema.json")
19
19
  __yaml_schema_etag_file = os.path.join(__config_dir, "yaml_schema.etag")
20
20
 
21
+
22
+ def __schema_cache_paths(schema_key=None):
23
+ if not schema_key:
24
+ return __yaml_schema_file, __yaml_schema_etag_file
25
+ safe_key = re.sub(r'[^0-9A-Za-z._-]', '_', str(schema_key))
26
+ return (
27
+ os.path.join(__config_dir, "yaml_schema-%s.json" % safe_key),
28
+ os.path.join(__config_dir, "yaml_schema-%s.etag" % safe_key),
29
+ )
30
+
21
31
  __no_write = False
22
32
 
23
33
 
@@ -239,44 +249,64 @@ def get_meta_required(key):
239
249
  return get_user_data().metadata.get(key)
240
250
 
241
251
 
242
- def __load_yaml_schema():
243
- if os.path.exists(__yaml_schema_file):
244
- with open(__yaml_schema_file, "r") as stream:
252
+ def __load_yaml_schema(schema_key=None):
253
+ schema_file, _etag_file = __schema_cache_paths(schema_key)
254
+ if os.path.exists(schema_file):
255
+ with open(schema_file, "r") as stream:
245
256
  return stream.read()
246
257
  return None
247
258
 
248
259
 
249
- def __load_yaml_schema_etag():
250
- if os.path.exists(__yaml_schema_etag_file):
251
- with open(__yaml_schema_etag_file, "r") as stream:
260
+ def __load_yaml_schema_etag(schema_key=None):
261
+ _schema_file, etag_file = __schema_cache_paths(schema_key)
262
+ if os.path.exists(etag_file):
263
+ with open(etag_file, "r") as stream:
252
264
  return stream.read() or None
253
265
  return None
254
266
 
255
267
 
256
268
  __yaml_schema_singleton = __load_yaml_schema()
257
269
  __yaml_schema_etag_singleton = __load_yaml_schema_etag()
258
-
259
-
260
- def get_yaml_schema(throw=True):
270
+ __yaml_schema_by_key = {}
271
+ __yaml_schema_etag_by_key = {}
272
+
273
+
274
+ def get_yaml_schema(throw=True, schema_key=None):
275
+ if schema_key:
276
+ if schema_key not in __yaml_schema_by_key:
277
+ __yaml_schema_by_key[schema_key] = __load_yaml_schema(schema_key)
278
+ schema = __yaml_schema_by_key[schema_key]
279
+ if schema is None and throw:
280
+ raise cli_exception.CliException("No yaml schema found. Please add --refresh option to download it first")
281
+ return schema
261
282
  if __yaml_schema_singleton is None and throw:
262
283
  raise cli_exception.CliException("No yaml schema found. Please add --refresh option to download it first")
263
284
  return __yaml_schema_singleton
264
285
 
265
286
 
266
- def get_yaml_schema_etag():
287
+ def get_yaml_schema_etag(schema_key=None):
288
+ if schema_key:
289
+ if schema_key not in __yaml_schema_etag_by_key:
290
+ __yaml_schema_etag_by_key[schema_key] = __load_yaml_schema_etag(schema_key)
291
+ return __yaml_schema_etag_by_key[schema_key]
267
292
  return __yaml_schema_etag_singleton
268
293
 
269
294
 
270
- def update_schema(yaml_schema_as_json: str, etag: str = None):
295
+ def update_schema(yaml_schema_as_json: str, etag: str = None, schema_key=None):
271
296
  global __yaml_schema_singleton, __yaml_schema_etag_singleton
272
- __yaml_schema_singleton = yaml_schema_as_json
273
- __yaml_schema_etag_singleton = etag
297
+ schema_file, etag_file = __schema_cache_paths(schema_key)
274
298
  os.makedirs(__config_dir, exist_ok=True)
275
- with open(__yaml_schema_file, "w") as stream:
276
- stream.write(__yaml_schema_singleton)
299
+ with open(schema_file, "w") as stream:
300
+ stream.write(yaml_schema_as_json)
277
301
  if etag:
278
- with open(__yaml_schema_etag_file, "w") as stream:
302
+ with open(etag_file, "w") as stream:
279
303
  stream.write(etag)
280
- elif os.path.exists(__yaml_schema_etag_file):
304
+ elif os.path.exists(etag_file):
281
305
  # no etag for this schema source (e.g. a local file) - don't leave a stale one around
282
- os.remove(__yaml_schema_etag_file)
306
+ os.remove(etag_file)
307
+ if schema_key:
308
+ __yaml_schema_by_key[schema_key] = yaml_schema_as_json
309
+ __yaml_schema_etag_by_key[schema_key] = etag
310
+ return
311
+ __yaml_schema_singleton = yaml_schema_as_json
312
+ __yaml_schema_etag_singleton = etag
@@ -4,13 +4,11 @@
4
4
  # Target : https://demowebshop.tricentis.com/ (nopCommerce demo)
5
5
  # Scenario: add a product to the cart -> checkout as guest -> view details
6
6
  #
7
- # Out-of-the-box usage (from the repo root, via neoload-cli):
8
- # Run CheckVU against the project:
9
- # neoload checkvu examples/as-code-demo/default.yaml
7
+ # Out-of-the-box usage (via neoload-cli), from this project directory:
10
8
  # Run the full test:
11
9
  # neoload login $NLW_TOKEN \
12
10
  # test-settings --zone defaultzone --lgs 1 createorpatch DemoWebShopTest \
13
- # project --path examples/as-code-demo/default.yaml upload DemoWebShopTest \
11
+ # project --path default.yaml upload DemoWebShopTest \
14
12
  # run --scenario DemoWebShop
15
13
  #
16
14
  # =============================================================================
@@ -0,0 +1 @@
1
+ __version__ = "1.4.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: neoload
3
- Version: 1.3.19.dev2
3
+ Version: 1.4.0
4
4
  Summary: A command-line native utility for launching and observing NeoLoad performance tests
5
5
  Home-page: https://github.com/Neotys-Labs/neoload-cli
6
6
  Author: Neotys
@@ -215,24 +215,6 @@ Pressing `Ctrl+C` causes the CLI to attempt to stop the test gracefully.
215
215
  neoload stop # Sends the stop signal to the test and waits until it ends.
216
216
  ```
217
217
 
218
- ## CheckVU an as-code project
219
- This command runs a CheckVU on an as-code project: it executes a single virtual user to verify that the project runs. It is meant to support fast iteration on as-code projects (generate -> checkvu -> fix).
220
-
221
- It delegates to a standalone headless CheckVU JAR and streams the JAR's output and exit code directly.
222
-
223
- ```
224
- Usage: neoload checkvu [OPTIONS] PROJECT_FILE
225
- Help: neoload checkvu --help
226
- neoload checkvu default.yaml
227
- neoload checkvu -u myUser default.yaml
228
- ```
229
- - `PROJECT_FILE` is a path to an as-code yaml file. The CLI validates it against the as-code schema first (same as `neoload validate`), using `-s, --as-code-schema` to override the default schema.
230
- - `-e, --engine-jar <path-or-url>` resolves the CheckVU JAR: a local file path or a download URL. If omitted, a previously cached JAR is reused, otherwise a default URL is used to download the latest JAR.
231
- - `-j, --java` selects the java executable; by default `JAVA_HOME/bin/java` then `java` on the PATH. Java 21+ is required and verified before running.
232
- - `-w, --work-dir <path>` sets the directory used for engine files and logs. Defaults to a temporary directory deleted afterwards unless `--keep-temp-work-dir` is set; a directory you supply yourself is never deleted.
233
- - `--app-proxy`, `--app-proxy-username` and `--app-proxy-bypass` configure the proxy used for application traffic. The proxy password is set with `NEOLOAD_CHECK_VU_APP_PROXY_PASSWORD` environment variable instead so it never shows up in the process list or CI logs.
234
- - `--controller-properties` and `--load-generator-properties` are advanced options to merge a `.properties` file into the JAR's embedded `controller.properties` / `agent.properties`.
235
-
236
218
  ## Reporting
237
219
 
238
220
  The NeoLoad CLI provides basic support for viewing and exporting test results.
@@ -418,9 +400,14 @@ The configuration lets you customize the CLI's behavior. For now, it is only use
418
400
 
419
401
  ### As-Code Demo Project
420
402
 
421
- [`examples/as-code-demo`](examples/as-code-demo) contains a NeoLoad As-Code YAML project that works out-of-the-box:
422
- no NeoLoad Web project, no manual scenario setup - just point NeoLoad at
423
- [`default.yaml`](examples/as-code-demo/default.yaml) and run.
403
+ Create a starter NeoLoad As-Code YAML project with:
404
+
405
+ ```
406
+ neoload project create DemoWebShop
407
+ ```
408
+
409
+ This scaffolds `DemoWebShop/default.yaml` from the bundled Demo Web Shop template —
410
+ no NeoLoad Web project, no manual scenario setup.
424
411
 
425
412
  Target: [Tricentis Demo Web Shop](https://demowebshop.tricentis.com/) (nopCommerce demo).
426
413
 
@@ -435,16 +422,12 @@ The `BuyAsGuest` user path walks through a typical guest purchase:
435
422
 
436
423
  It uses two variables (`product_id`, `quantity`) and a single population (`GuestShoppers`)
437
424
 
438
- Run CheckVU against the project:
439
- ```
440
- neoload checkvu examples/as-code-demo/default.yaml
441
- ```
442
-
443
425
  Run the full test:
444
426
  ```
427
+ neoload project create DemoWebShop
445
428
  neoload login $NLW_TOKEN \
446
429
  test-settings --zone defaultzone --lgs 1 createorpatch DemoWebShopTest \
447
- project --path examples/as-code-demo/default.yaml upload DemoWebShopTest \
430
+ project --path DemoWebShop/default.yaml upload DemoWebShopTest \
448
431
  run --scenario DemoWebShop
449
432
  ```
450
433