diff --git a/054-AzureLoadTesting/Coach/README.md b/054-AzureLoadTesting/Coach/README.md
new file mode 100644
index 0000000000..917fbf645b
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/README.md
@@ -0,0 +1,64 @@
+# What The Hack - Azure Load Testing - Coach Guide
+
+## Introduction
+Welcome to the coach's guide for the Azure Load Testing What The Hack. Here you will find links to specific guidance for coaches for each of the challenges.
+
+NOTE: If you are a Hackathon participant, this is the answer guide. Don't cheat yourself by looking at these during the hack! Go learn something. :)
+
+## Coach's Guides
+- Challenge 00: **[Prerequisites - Ready, Set, GO!](./Solution-00.md)**
+ - Prepare your workstation to work with Azure.
+- Challenge 01: **[Develop a Load Testing Strategy](./Solution-01.md)**
+ - How to develop a load testing strategy for your application
+- Challenge 02: **[Create a Load Testing Script](./Solution-02.md)**
+ - Deploy a sample application and create JMeter scripts to support your load testing strategy
+- Challenge 03: **[Create Azure Load Testing Service and Establish Baselines](./Solution-03.md)**
+ - Create Azure Load Testing Service and learn techniques on how to establish baselines for your application
+- Challenge 04: **[Enable Automated Load Testing (CI/CD)](./Solution-04.md)**
+ - Incorporate load testing into your CI/CD Pipeline
+- Challenge 05: **[Identify & Remediate Bottlenecks](./Solution-05.md)**
+ - Review load test results and identify bottlenecks
+- Challenge 06: **[Stress Testing](./Solution-06.md)**
+ - How to perform stress tests and observing your application behavior
+- Challenge 07: **[Load Testing With Chaos Experiment (Resilience Testing)](./Solution-07.md)**
+ - Incorporate load testing and chaos experiments together
+
+## Coach Prerequisites
+
+This hack has pre-reqs that a coach is responsible for understanding and/or setting up BEFORE hosting an event. Please review the [What The Hack Hosting Guide](https://aka.ms/wthhost) for information on how to host a hack event.
+
+The guide covers the common preparation steps a coach needs to do before any What The Hack event, including how to properly configure Microsoft Teams.
+
+### Student Resources
+
+Before the hack, it is the Coach's responsibility to download and package up the contents of the `/Student/Resources` folder of this hack into a "Resources.zip" file as this contains the sample application they will need for this hack. The coach should then provide a copy of the Resources.zip file to all students at the start of the hack.
+
+Always refer students to the [What The Hack website](https://aka.ms/wth) for the student guide: [https://aka.ms/wth](https://aka.ms/wth)
+
+**NOTE:** Students should **not** be given a link to the What The Hack repo before or during a hack. The student guide does **NOT** have any links to the Coach's guide or the What The Hack repo on GitHub.
+
+## Azure Requirements
+
+This hack requires students to have access to an Azure subscription/resource group where they can create and consume Azure resources. These Azure requirements should be shared with a stakeholder in the organization that will be providing the Azure subscription(s) that will be used by the students.
+
+Requirements:
+
+- Contributor permissions to a subscription or resource group
+- Resources - The following resources will be created during the hack
+ - Azure Load Testing
+ - Azure App Service
+ - Azure Cosmos DB
+ - Azure Application Insights
+
+## Suggested Hack Agenda
+This hack is estimated to take 3 days with 4 hours each day.
+## Repository Contents
+
+- `./Coach`
+ - Coach's Guide and related files
+- `./Coach/Solutions`
+ - Solution files with completed example answers to a challenge
+- `./Student`
+ - Student's Challenge Guide
+- `./Student/Resources`
+ - Sample app code, ARM Template, and deployment script is located here for students to deploy the sample app used in the challenges (Must be packaged up by the coach and provided to students at start of event)
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Coach/Solution-00.md b/054-AzureLoadTesting/Coach/Solution-00.md
new file mode 100644
index 0000000000..8c491ff3e7
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solution-00.md
@@ -0,0 +1,7 @@
+# Challenge 00 - Prerequisites - Ready, Set, GO! - Coach's Guide
+
+**[Home](./README.md)** - [Next Solution >](./Solution-01.md)
+
+## Notes & Guidance
+
+We are only setting up the students machines here. Please reference the student section. Feel free to assist more during the prerequisite. [Student Pre-reqs.](../Student/Challenge-00.md)
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Coach/Solution-01.md b/054-AzureLoadTesting/Coach/Solution-01.md
new file mode 100644
index 0000000000..1d8fc57ae8
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solution-01.md
@@ -0,0 +1,39 @@
+# Challenge 01 - Develop a Load Testing Strategy - Coach's Guide
+
+[< Previous Solution](./Solution-00.md) - **[Home](./README.md)** - [Next Solution >](./Solution-02.md)
+
+## Notes & Guidance
+
+Below is a sample load testing plan we have mapped out. Students will have something different as we left it up to the student to interpret the environment however the overall feel should be similar.
+
+- Sample Load Testing Plan
+
+
+- Define what services and the scope of your testing - Requirements
+ - We will be simulating an average day when a user hits our website during normal business hours 8 - 5 PM. We will be testing all 3 endpoints (Get/Add/lasttimestamp) to ensure all features are tested.
+
+- Environment Requirements
+ - Since we are testing the user, we will need the following resources at the same level as production.
+ - App Service
+ - Cosmos DB
+
+
+- Identify the load characteristics and scenario
+ - Our current average daily load is 1000 users/hour. We will mimic the average daily load hitting all 3 endpoints. Since there is consistent daily load we will mimic this with gradual load increasing linearly.
+
+- Identify the test failure criteria
+ - Our test will fail if we are unable to support 1000 users as we already know this is the current demand.
+ - We will also consider this a failed test if we find performance below expected thresholds as this may impact customer satisfaction.
+
+- Identify how you will be monitoring your application
+ - We will be monitoring our applications with Application Insights to detect any errors and monitor performance.
+
+- Identify potential bottlenecks/limitations in advance
+ - Since we do not cache any data at any level. Any component failing could cause an issue downstream.
+
+- Please note any assumptions
+ - We are assuming these are only casual end users and not other 3rd parties who could be trying to obtain information about our traffic.
+ - We are using consumption based model for Azure App Services
+ - Application is not caching any data and always makes calls to Cosmos DB
+
+- Reinforce the importance of using existing metrics/usage patterns/data to inform the load testing on their own application.
diff --git a/054-AzureLoadTesting/Coach/Solution-02.md b/054-AzureLoadTesting/Coach/Solution-02.md
new file mode 100644
index 0000000000..628a560c38
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solution-02.md
@@ -0,0 +1,6 @@
+# Challenge 02 - Create a Load Testing Script - Coach's Guide
+
+[< Previous Solution](./Solution-01.md) - **[Home](./README.md)** - [Next Solution >](./Solution-03.md)
+## Notes & Guidance
+
+- Sample solution JMeter script is located in the solution directory [here](./Solutions/Challenge2/).
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Coach/Solution-03.md b/054-AzureLoadTesting/Coach/Solution-03.md
new file mode 100644
index 0000000000..6c237eb5b8
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solution-03.md
@@ -0,0 +1,36 @@
+# Challenge 03 - Create Azure Load Testing Service and Establish Baselines - Coach's Guide
+
+[< Previous Solution](./Solution-02.md) - **[Home](./README.md)** - [Next Solution >](./Solution-04.md)
+
+## Notes & Guidance
+
+Below are the instructions to complete challenge 3
+
+- Create Azure Load Testing resource
+ - Search for the Azure Load Testing resource on the top search bar and select the resource.
+ - On the top left hand corner select "Create"
+ - Select the Resource Group that was created by the sample app or create your own. The resources must be in the same location.
+ - Enter a unique name for the resource.
+ - Ensure the location matches the location that your application is deployed to.
+ - Select "Review + create"
+ - Review your configurations and then select "Create"
+- Create Load Test
+ - Go into your new resource. You may see a warning on the top depending on your current access describing the access levels required. If so, add yourself as one of the roles such as "Load Testing Owner" or "Load Testing Contributor" as you will not be able to proceed otherwise.
+ - Select "Create"
+ - Fill out the name of the test and a description of the test.
+ - Go to the "Test Plan" tab and select the JMeter script you have locally and then select "Upload"
+ - Under the "Parameters" tab, enter "webapp" for the name of the environment variable, followed by the URL for your sample app in the "Value" section.
+ - Under the "Monitoring" tab, select "Add/Modify" and select the resources from the sample app followed by "Apply" so they are monitored.
+ - Select "Review + create"
+ - Review the settings and select "Create"
+- Run the load test
+ - In your Azure Load Test service, select "Tests" from the left hand side
+ - Select the test that you created from the list
+ - At the top of the screen select "Run"
+ - A summary page should appear. Add that this run is the baseline in the description. Select "Run"
+- Set Pass/Fail Criteria
+ - Go back to your load test and select "Configure" followed by "Test"
+ - Go to the "Test Criteria" Tab.
+ - Enter in your test criteria such as failure rate under x %
+
+Sample solution JMeter script is located in the solution directory [here](./Solutions/Challenge3/).
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Coach/Solution-04.md b/054-AzureLoadTesting/Coach/Solution-04.md
new file mode 100644
index 0000000000..1f1a4d6e07
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solution-04.md
@@ -0,0 +1,14 @@
+# Challenge 04 - Enable Automated Load Testing (CI/CD) - Coach's Guide
+
+[< Previous Solution](./Solution-03.md) - **[Home](./README.md)** - [Next Solution >](./Solution-05.md)
+
+## Notes & Guidance
+
+
+High level Notes
+
+- There is a sample action which will run a load test. The default action will either create or run the existing load test. However, the "TestName" parameter inside the config.yaml file will be automatically lower cased by the GitHub Action. Since the UI allows upper or lowercase letters, this can cause a duplicate test to be created.
+- GitHub will require another action to create issues while ADO has a built-in functionality to do this.
+- Students can use the baseline from their first run in challenge 3 to determine what their pass/fail criteria is.
+
+Sample solution JMeter script and configuration is located in the solution directory [here](./Solutions/Challenge4/).
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Coach/Solution-05.md b/054-AzureLoadTesting/Coach/Solution-05.md
new file mode 100644
index 0000000000..4c99a7b164
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solution-05.md
@@ -0,0 +1,13 @@
+# Challenge 05 - Identify & Remediate Bottlenecks - Coach's Guide
+
+[< Previous Solution](./Solution-04.md) - **[Home](./README.md)** - [Next Solution >](./Solution-06.md)
+
+## Notes & Guidance
+- This link goes into the issues in detail
+https://docs.microsoft.com/en-us/azure/load-testing/tutorial-identify-bottlenecks-azure-portal
+
+- The students should be seeing many errors and that Cosmos DB RU are maxed out. If they are not, have them increase the amount of load in their tests.
+- Make sure the students have configured monitoring integration from Azure Load Test with the services such as App Service, App Insights, and Cosmos DB.
+ https://docs.microsoft.com/en-us/azure/load-testing/how-to-appservice-insights
+- Cosmos DB can either be scaled up manually or set to auto-scale.
+- Post scale tests should show a drastic decrease in errors and Cosmos DB RU nowhere near the max. You may still see some errors which was normal.
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Coach/Solution-06.md b/054-AzureLoadTesting/Coach/Solution-06.md
new file mode 100644
index 0000000000..244981e5d4
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solution-06.md
@@ -0,0 +1,9 @@
+# Challenge 06 - Stress Testing - Coach's Guide
+
+[< Previous Solution](./Solution-05.md) - **[Home](./README.md)** - [Next Solution >](./Solution-07.md)
+
+## Notes & Guidance
+
+I start noticing failures when we reach 6 users. It seems like 4 users will hit 60% of Cosmos DB consumption assuming a 1k limit. There is then a sharp jump when you hit 10 users in terms of the number of failures. Cosmos DB is still the bottleneck as our App Service is still running on one instance and does not appear to be constrained at all.
+
+Sample solution JMeter script is located in the solution directory [here](./Solutions/Challenge6/).
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Coach/Solution-07.md b/054-AzureLoadTesting/Coach/Solution-07.md
new file mode 100644
index 0000000000..688748dc5a
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solution-07.md
@@ -0,0 +1,37 @@
+# Challenge 07 - Load Testing With Chaos Experiment (Resilience Testing) - Coach's Guide
+
+[< Previous Solution](./Solution-06.md) - **[Home](./README.md)**
+
+## Notes & Guidance
+
+Here are instructions on how to setup Chaos Studio and run the experiment. Chaos Studio does not offer a GitHub Action at this time. We want the users to get a taste of chaos engineering so they can trigger the chaos experiment manually while the load test runs. They are not required to implement this all in the pipeline. That is an advanced challenge.
+
+- Azure Chaos studio only supports a number of faults such as VMs, AKS, Cosmos DB, and networking to name a few. Since our sample app only contains App Services and Cosmos DB, we will use the Cosmos DB faults.
+- First you will need to enable geo-redundancy in your Cosmos DB. Go to your Cosmos DB instance and select "Enable Geo Redundancy" on the top bar. Keep note of the paired region your Cosmos DB is paired with.
+- Create Azure Chaos Studio/Experiment
+ - Register Chaos Studio Provider
+ - Go to your subscription
+ - On the left-hand side, select "Resource provider"
+ - In the list of providers, search for "Microsoft.Chaos"
+ - Click on the provider and select "Register"
+ - Go to Azure Chaos Studio
+ - Under "Targets" select "Enable Targets" then "Enable service-direct targets"
+ - Select the Cosmos DB service for your load test.
+ - On the left-hand side, select "Experiments"
+ - Select "Add an experiment"
+ - Fill in your subscription, resource group, location, and name for this experiment. Keep track of the experiment name as a managed user will be created for you.
+ - Go to the experiment designer on the next tab. Change the name of the step or branch if you wish.
+ - Select "Add Action" follows by "Add Fault"
+ - Select "Cosmos DB Failover" as the Fault. You can choose the duration but 2-3 mins should be enough. Finally, enter the region that your instance is paired with in the "readRegion" section.
+ - Save your experiment.
+- Update Cosmos DB Permissions
+ - In Cosmos DB select "Access Control"
+ - Select "Add" followed by "Add Role Assignment"
+ - Select the CosmosDBOperator role, then click "Select members".
+ - Search the name of the experiment from the earlier step and then click "Select".
+ - Review and assign the permissions which will grant the role to the experiment.
+
+- Run load test + experiment
+ - Run the load test first, then while the load test is running kick off the chaos experiment. You should notice that the application does not fail, but there will be a large spike in response time when you kick off the chaos experiment. You should only see one spike and the app should return to normal behavior afterwards.
+
+
diff --git a/054-AzureLoadTesting/Coach/Solutions/Challenge2/WTH Load Test Home Page.jmx b/054-AzureLoadTesting/Coach/Solutions/Challenge2/WTH Load Test Home Page.jmx
new file mode 100644
index 0000000000..0b26d8e1c3
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solutions/Challenge2/WTH Load Test Home Page.jmx
@@ -0,0 +1,217 @@
+
+
+
+
+ WTH Load testing
+ false
+ true
+ false
+
+
+
+ site
+ loadtestwth.azurewebsites.net
+ =
+
+
+
+
+
+
+
+ continue
+
+ false
+ 1000
+
+ 10
+ 240
+ false
+
+
+ true
+
+
+
+
+
+
+ ${site}
+
+ https
+
+ get
+ GET
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+ true
+
+
+
+ false
+ 1
+ =
+
+
+
+ ${site}
+
+ https
+
+ add
+ POST
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+ ${site}
+
+ https
+
+ lasttimestamp
+ GET
+ true
+ false
+ true
+ false
+
+ HttpClient4
+ 60000
+ 60000
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/054-AzureLoadTesting/Coach/Solutions/Challenge3/WTH Load Test-ALD.jmx b/054-AzureLoadTesting/Coach/Solutions/Challenge3/WTH Load Test-ALD.jmx
new file mode 100644
index 0000000000..76ff20e000
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solutions/Challenge3/WTH Load Test-ALD.jmx
@@ -0,0 +1,217 @@
+
+
+
+
+ WTH Load testing
+ false
+ true
+ false
+
+
+
+ site
+ ${__BeanShell( System.getenv("webapp") )}
+ =
+
+
+
+
+
+
+
+ continue
+
+ false
+ 1000
+
+ 10
+ 240
+ false
+
+
+ true
+
+
+
+
+
+
+ ${site}
+
+ https
+
+ get
+ GET
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+ true
+
+
+
+ false
+ 1
+ =
+
+
+
+ ${site}
+
+ https
+
+ add
+ POST
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+ ${site}
+
+ https
+
+ lasttimestamp
+ GET
+ true
+ false
+ true
+ false
+
+ HttpClient4
+ 60000
+ 60000
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/054-AzureLoadTesting/Coach/Solutions/Challenge4/LoadTest.yml b/054-AzureLoadTesting/Coach/Solutions/Challenge4/LoadTest.yml
new file mode 100644
index 0000000000..95071a44d5
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solutions/Challenge4/LoadTest.yml
@@ -0,0 +1,57 @@
+# This is a basic workflow to help you get started with Actions
+
+name: Load Test Trigger
+
+# Controls when the workflow will run
+on:
+ push:
+ branches:
+ - main
+
+env:
+ AZURE_WEBAPP_NAME: "loadtestwth" # set this to your application's name
+ LOAD_TEST_RESOURCE: "loadtestwth"
+ LOAD_TEST_RESOURCE_GROUP: "loadtestwtheastus-rg"
+
+
+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
+jobs:
+
+ loadTest:
+ name: Load Test
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout GitHub Actions
+ uses: actions/checkout@v2
+
+ - name: Login to Azure
+ uses: azure/login@v1
+ continue-on-error: false
+ with:
+ creds: ${{ secrets.AZURE_CREDENTIALS }}
+
+ - name: 'Azure Load Testing'
+ uses: azure/load-testing@v1
+ with:
+ loadTestConfigFile: 'LoadTestConfig.yaml'
+ loadTestResource: ${{ env.LOAD_TEST_RESOURCE }}
+ resourceGroup: ${{ env.LOAD_TEST_RESOURCE_GROUP }}
+ env: |
+ [
+ {
+ "name": "webapp",
+ "value": "${{ env.AZURE_WEBAPP_NAME }}.azurewebsites.net"
+ }
+ ]
+
+ - uses: JasonEtco/create-an-issue@v2
+ if: ${{ failure() }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ filename: .github/ISSUE_TEMPLATE/LoadTest.md
+
+ - uses: actions/upload-artifact@v2
+ with:
+ name: loadTestResults
+ path: ${{ github.workspace }}/loadTest
diff --git a/054-AzureLoadTesting/Coach/Solutions/Challenge4/LoadTestConfig.yaml b/054-AzureLoadTesting/Coach/Solutions/Challenge4/LoadTestConfig.yaml
new file mode 100644
index 0000000000..38f216b594
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solutions/Challenge4/LoadTestConfig.yaml
@@ -0,0 +1,8 @@
+version: v0.1
+testName: PersonalTest
+testPlan: WTH_Load_Test-ALD.jmx
+description: 'CI/CD Test Run'
+engineInstances: 1
+failureCriteria:
+ - avg(response_time_ms) > 3
+ - percentage(error) > 50
diff --git a/054-AzureLoadTesting/Coach/Solutions/Challenge4/WTH_Load_Test-ALD.jmx b/054-AzureLoadTesting/Coach/Solutions/Challenge4/WTH_Load_Test-ALD.jmx
new file mode 100644
index 0000000000..76ff20e000
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solutions/Challenge4/WTH_Load_Test-ALD.jmx
@@ -0,0 +1,217 @@
+
+
+
+
+ WTH Load testing
+ false
+ true
+ false
+
+
+
+ site
+ ${__BeanShell( System.getenv("webapp") )}
+ =
+
+
+
+
+
+
+
+ continue
+
+ false
+ 1000
+
+ 10
+ 240
+ false
+
+
+ true
+
+
+
+
+
+
+ ${site}
+
+ https
+
+ get
+ GET
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+ true
+
+
+
+ false
+ 1
+ =
+
+
+
+ ${site}
+
+ https
+
+ add
+ POST
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+ ${site}
+
+ https
+
+ lasttimestamp
+ GET
+ true
+ false
+ true
+ false
+
+ HttpClient4
+ 60000
+ 60000
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/054-AzureLoadTesting/Coach/Solutions/Challenge6/WTH_Load_Test-ALD.jmx b/054-AzureLoadTesting/Coach/Solutions/Challenge6/WTH_Load_Test-ALD.jmx
new file mode 100644
index 0000000000..c6f3229065
--- /dev/null
+++ b/054-AzureLoadTesting/Coach/Solutions/Challenge6/WTH_Load_Test-ALD.jmx
@@ -0,0 +1,222 @@
+
+
+
+
+ WTH Load testing
+ false
+ true
+ false
+
+
+
+ site
+ ${__BeanShell( System.getenv("webapp") )}
+ =
+
+
+ numUsers
+ ${__BeanShell( System.getenv("numUsers") )}
+ =
+
+
+
+
+
+
+
+ continue
+
+ false
+ -1
+
+ ${numUsers}
+ 240
+ false
+
+
+ true
+
+
+
+
+
+
+ ${site}
+
+ https
+
+ get
+ GET
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+ true
+
+
+
+ false
+ 1
+ =
+
+
+
+ ${site}
+
+ https
+
+ add
+ POST
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+ ${site}
+
+ https
+
+ lasttimestamp
+ GET
+ true
+ false
+ true
+ false
+
+ HttpClient4
+ 60000
+ 60000
+
+
+
+ false
+
+ saveConfig
+
+
+ true
+ true
+ true
+
+ true
+ true
+ true
+ true
+ false
+ true
+ true
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ true
+ 0
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/054-AzureLoadTesting/README.md b/054-AzureLoadTesting/README.md
new file mode 100644
index 0000000000..e062d1a7e0
--- /dev/null
+++ b/054-AzureLoadTesting/README.md
@@ -0,0 +1,42 @@
+# What The Hack - Azure Load Testing
+
+## Introduction
+Azure Load Testing Service (Preview) enables developers and testers to generate high-scale load that reveal actionable insights into app performance, scalability, capacity - and ultimately resiliency - with a fully managed service.
+
+## Learning Objectives
+This hack is designed to introduce you to Azure Load Testing and guide you through a series of hands-on challenges to accomplish the following:
+
+- Leverage a cloud-based load testing service with high fidelity support for JMeter and new/existing JMeter scripts
+- Build a comprehensive view of curated client and server metrics with actionable insights into app performance
+- Integrate with CI/CD workflows for automated, collaborative load-testing
+- Perform load testing in conjunction with Azure Chaos Studio to ensure resiliency during an application/service/region degradation or failure
+
+## Challenges
+- Challenge 00: **[Prerequisites - Ready, Set, GO!](Student/Challenge-00.md)**
+ - Prepare your workstation to work with Azure.
+- Challenge 01: **[Develop a Load Testing Strategy](Student/Challenge-01.md)**
+ - How to develop a load testing strategy for your application
+- Challenge 02: **[Create a Load Testing Script](Student/Challenge-02.md)**
+ - Deploy a sample application and create JMeter scripts to support your load testing strategy
+- Challenge 03: **[Create Azure Load Testing Service and Establish Baselines](Student/Challenge-03.md)**
+ - Create Azure Load Testing Service and learn techniques on how to establish baselines for your application
+- Challenge 04: **[Enable Automated Load Testing (CI/CD)](Student/Challenge-04.md)**
+ - Incorporating load testing into your CI/CD Pipeline
+- Challenge 05: **[Identify & Remediate Bottlenecks](Student/Challenge-05.md)**
+ - Reviewing load test results and identifying bottlenecks
+- Challenge 06: **[Stress Testing](Student/Challenge-06.md)**
+ - How to perform stress tests and observing your application behavior
+- Challenge 07: **[Load Testing With Chaos Experiment (Resilience Testing)](Student/Challenge-07.md)**
+ - Incorporating load testing and chaos experiments together
+
+## Prerequisites
+- Familiarity with the fundamentals of load testing
+- Azure subscription for creating the Load Testing service and running the sample application
+- GitHub or Azure DevOps to automate load testing in your CI/CD pipelines
+- [Apache JMeter](https://jmeter.apache.org/usermanual/get-started.html) installed on your local machine or in a VM to create your load testing script
+- [Azure Cloud Shell](https://shell.azure.com) or [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli)
+
+
+## Contributors
+- Kevin M. Gates
+- Andy Huang
diff --git a/054-AzureLoadTesting/Student/Challenge-00.md b/054-AzureLoadTesting/Student/Challenge-00.md
new file mode 100644
index 0000000000..373554464f
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Challenge-00.md
@@ -0,0 +1,66 @@
+# Challenge 00 - Prerequisites - Ready, Set, GO!
+
+**[Home](../README.md)** - [Next Challenge >](./Challenge-01.md)
+
+
+## Introduction
+
+Thank you for participating in the Azure Load Testing What The Hack. Before you can hack, you will need to set up some prerequisites.
+
+## Prerequisites
+
+- [Azure Subscription](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-subscription)
+- [Managing Cloud Resources](../../000-HowToHack/WTH-Common-Prerequisites.md#managing-cloud-resources)
+ - [Azure Portal](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-portal)
+ - [Azure CLI](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-cli)
+ - [Note for Windows Users](../../000-HowToHack/WTH-Common-Prerequisites.md#note-for-windows-users)
+ - [Azure PowerShell CmdLets](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-powershell-cmdlets)
+ - [Azure Cloud Shell](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-cloud-shell)
+- [Visual Studio Code](../../000-HowToHack/WTH-Common-Prerequisites.md#visual-studio-code)
+- [Azure Storage Explorer](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-storage-explorer)
+- [Apache JMeter](https://jmeter.apache.org/usermanual/get-started.html) - This requires Java 8+ to be installed
+- [GitHub](https://github.com/) or [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/?nav=min)
+
+## Description
+
+Now that you have the common prerequisites installed on your workstation, there is a sample application that we will be working off of for this hack.
+
+Your coach will provide you with a Resources.zip file that contains resources you will need to complete the hack. If you plan to work locally, you should unzip it on your workstation. If you plan to use the Azure Cloud Shell, you should upload it to the Cloud Shell and unzip it there.
+
+### Sample WebApp with Cosmos DB
+
+ The sample app is a WebApp deployed on App Service with Cosmos DB as a database. It counts the number of visitors visiting the page and inserts the same into a sample collection in Cosmos DB.
+
+### Installation
+
+1. In your terminal window, log into Azure and set a subscription(subscription which would contain the webapp) :
+
+ az login
+ az account set -s mySubscriptionName
+
+1. Deploy the sample app using the PowerShell script. (Tip: macOS users can install PowerShell [here](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-macos?view=powershell-7.1))
+
+ cd nodejs-appsvc-cosmosdb-bottleneck
+ .\deploymentscript.ps1
+
+1. You will be prompted to supply a unique application name and a location (default is `eastus`). A resource group for the resources would be created with the same name.
+1. Once deployment is complete, browse to the running sample application with your browser.
+
+ https://.azurewebsites.net
+
+### **Clean up resources**
+
+You may want to delete the resources to avoid incurring additional charges at the end of this hack. Use the `az group delete` command to remove the resource group and all related resources.
+
+ az group delete --name myResourceGroup
+
+Similarly, you can utilize the **Delete resource group** toolbar button on the sample application's resource group to remove all the resources.
+
+## Success Criteria
+
+To complete this challenge successfully, you should be able to:
+
+- Verify that you have a Bash shell with the Azure CLI available.
+- Apache JMeter
+- Verify that your sample application is running
+
diff --git a/054-AzureLoadTesting/Student/Challenge-01.md b/054-AzureLoadTesting/Student/Challenge-01.md
new file mode 100644
index 0000000000..092b29d2a0
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Challenge-01.md
@@ -0,0 +1,38 @@
+# Challenge 01 - Develop a Load Testing Strategy
+
+[< Previous Challenge](./Challenge-00.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-02.md)
+
+## Introduction
+
+When some people think of load testing, the first thought that comes to mind is pointing a tool at your site and cranking the load to the max and see what happens. While that might be exciting at the moment, it’s critical to take a step back and develop a load testing strategy that is tailored to the application. This means breaking down the architecture, internal/external dependencies, high availability design, scaling and the data tier. Having a plan not only helps you prepare while you are testing the application but also provides context as to why and how you are testing the application for anyone in the future.
+
+## Description
+
+Create a load testing strategy to describe your plan and goals. Below are some examples of topics to think of. Are there any additional you can think of adding?
+
+- Define what services and the scope of your testing
+- Identify the load characteristics and scenario
+- Identify the test failure criteria
+- Identify how you will be monitoring your application
+- Identify potential bottlenecks/limitations in advance
+- Please note any assumptions
+
+Below is the sample application that we will be using:
+
+The sample app is a single page web application that displays the number of times the endpoint has been hit and is used as a tracker for the number of guests have visited your site. There are three endpoints for this application:
+
+- (Get) Get - carries a get operation from the database to retrieve the current count
+- (Post) Add - Updates the database with the number of visitors. You will need to pass the number of visits to increment.
+- (Get) lasttimestamp - Updates the time stamp since this was accessed.
+
+This is deployed on App Service with Cosmos DB as the database.
+## Success Criteria
+
+- Present your comprehensive load testing plan - paying special attention to how the load test will ‘touch’ the various application and components.
+- Explain what potential bottlenecks you might encounter during the test. For each bottleneck, how will you tweak or mitigate the bottleneck?
+- Explain how a service failure or degradation might impact the performance of the application and/or load test
+
+## Learning Resources
+
+- [Azure subscription and service limits, quotas, and constraints](https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits)
+- [How to write a test plan for load testing](https://www.flood.io/blog/how-to-write-a-test-plan-for-load-testing)
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Challenge-02.md b/054-AzureLoadTesting/Student/Challenge-02.md
new file mode 100644
index 0000000000..6f327a6685
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Challenge-02.md
@@ -0,0 +1,37 @@
+# Challenge 02 - Create a Load Testing Script
+
+[< Previous Challenge](./Challenge-01.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-03.md)
+
+## Pre-requisites
+
+- Ensure you have outlined your load testing strategy as described in the previous challenge.
+
+## Introduction
+
+In this challenge, you will create your load testing script. Your load testing script should target the 3 application endpoints and implement the load testing strategy you created in the previous challenge. Your scripts should help you get a baseline for how the application can handle typical user loads.
+
+Azure Load Testing is based on Apache JMeter - a popular open source load testing tool. This means you can reuse existing JMeter scripts or create new scripts by using the JMeter GUI.
+
+## Description
+
+- Using the JMeter GUI, create a load testing script that targets the 3 application endpoints:
+ - (Get) Get - carries a get operation from the database to retrieve the current count
+ - (Post) Add - Updates the database with the number of visitors. You will need to pass the number of visits to increment.
+ - (Get) lasttimestamp - Updates the time stamp since this was accessed.
+- Execute the load test using the JMeter GUI against your 3 endpoints and use the Azure portal to confirm the App Service is getting the traffic.
+
+## Success Criteria
+
+- Verify have a load testing script (.jmx) created that targets the 3 application endpoints.
+- Verify your load test in JMeter works and you are able to see the load in your sample application.
+
+## Learning Resources
+
+- [Node.js sample application](https://github.com/Whowong/nodejs-appsvc-loadtest)
+- [Apache JMeter Docs](https://jmeter.apache.org/index.html)
+- [Create Test Plan from Template](https://jmeter.apache.org/usermanual/get-started.html#template)
+- [JMeter best practices](https://jmeter.apache.org/usermanual/best-practices.html)
+- [Custom Plugins for Apache JMeter](https://jmeter-plugins.org/)
+
+## Advanced Challenges (Optional)
+- Your initial load test scripts may gradually increase load in a linear rate. What if you wanted to simulate users starting their day at work at different time zones? See if you are able to create a load test which steps into higher load like a stairway.
diff --git a/054-AzureLoadTesting/Student/Challenge-03.md b/054-AzureLoadTesting/Student/Challenge-03.md
new file mode 100644
index 0000000000..df3384bbcb
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Challenge-03.md
@@ -0,0 +1,32 @@
+# Challenge 03 - Create Azure Load Testing Service and Establish Baselines
+
+[< Previous Challenge](./Challenge-02.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-04.md)
+
+## Pre-requisites
+
+- Before creating your Azure Load Test service, ensure you have created your load testing script(s) in the previous challenge.
+## Introduction
+
+In this challenge you will create the Load Testing service in Azure and use the load testing scripts you created in our last challenge to run baseline tests.
+
+Baselines help to determine the current efficiency state of your application and its supporting infrastructure. They can provide good insights for improvements and determine if the application is meeting business goals. Lastly, they can be created for any application regardless of its maturity. No matter when you establish the baseline, measure performance against that baseline during continued development. When code and/or infrastructure changes, the effect on performance can be actively measured.
+
+## Description
+
+- Create a Load Testing service in Azure.
+- Create a load test in the Load Testing service that accepts the website URL as an environment variable and passes that value to your load testing script.
+- Run your load test multiple times using a typical user load and establish a performance baseline.
+- Review the test results, identify the bottlenecks (CPU, memory, resource limits) and compile a list of insights.
+- Discuss where you may be able to leverage this baseline data you have gathered.
+
+## Success Criteria
+
+- Show your load tests run in Azure Load Testing service and what your performance baseline is.
+- Verify you can run the same load test and change parameters to hit different environments.
+
+## Learning Resources
+
+- [Establish Baselines](https://docs.microsoft.com/en-us/azure/architecture/framework/scalability/performance-test#establish-baselines)
+- [Create configurable load tests with secrets and environment variables](https://docs.microsoft.com/en-us/azure/load-testing/how-to-parameterize-load-tests)
+- [Load Testing documentation](https://docs.microsoft.com/en-us/azure/load-testing/)
+
diff --git a/054-AzureLoadTesting/Student/Challenge-04.md b/054-AzureLoadTesting/Student/Challenge-04.md
new file mode 100644
index 0000000000..c0ac4c74b8
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Challenge-04.md
@@ -0,0 +1,26 @@
+# Challenge 04 - Enable Automated Load Testing (CI/CD)
+
+[< Previous Challenge](./Challenge-03.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-05.md)
+
+## Introduction
+
+You can integrate Azure Load Testing in your CI/CD pipeline at meaningful points during the development lifecycle. For example, you could automatically run a load test at the end of each sprint or in a staging environment to validate a release candidate build. In the test configuration, you specify pass/fail rules to catch performance regressions early in the development cycle. For example, when the average response time exceeds a threshold, the test should fail. To get the maximum value from this approach, it is critical to integrate this in your CI/CD workflow as soon as possible.
+
+You can trigger Azure Load Testing from Azure Pipelines or GitHub Actions workflows.
+
+## Description
+- Create a new Azure DevOps project or GitHub repo.
+- Use the Azure Load Testing extension with Azure DevOps or the Azure Load Testing GitHub Action to execute your load test with a manual trigger.
+- Intentionally set the pass/fail rules in your test configuration to a value (i.e., response time) that would cause the test to fail during the workflow.
+- On load test failure, automatically create a work item or issue.
+
+## Success Criteria
+
+- Demonstrate that you can execute your load test on a manual trigger.
+- Demonstrate that when the load test fails due to it not meeting the performance target, a work item or issue is created automatically.
+
+## Learning Resources
+
+- [Load Testing documentation](https://docs.microsoft.com/en-us/azure/load-testing/)
+
+
diff --git a/054-AzureLoadTesting/Student/Challenge-05.md b/054-AzureLoadTesting/Student/Challenge-05.md
new file mode 100644
index 0000000000..cdd34403c7
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Challenge-05.md
@@ -0,0 +1,21 @@
+# Challenge 05 - Identify & Remediate Bottlenecks
+
+[< Previous Challenge](./Challenge-04.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-06.md)
+
+## Introduction
+
+From our last challenge we should now have load tests running against your environment! While our load tests are automated now, we need to make sure we review the tests to see if we can identify any bottlenecks or changes in behavior. From there we can share our findings and work towards remediating the issues. If your application is hosted in Azure, you can leverage some synergy Azure Load Testing has with the other cloud services.
+
+## Description
+
+Review your load test results to see where there are potential bottlenecks in your application. If needed, perform additional tests with different settings to help identity any bottlenecks. Once you have identified one or more bottlenecks, see how you could resolve the bottleneck and show that the fix resolved the issue.
+
+## Success Criteria
+
+- Show how you found the bottleneck
+- Verify that your bottleneck has been resolved.
+
+## Learning Resources
+
+[Adding Monitoring to Load Testing](https://docs.microsoft.com/en-us/azure/load-testing/how-to-appservice-insights)
+
diff --git a/054-AzureLoadTesting/Student/Challenge-06.md b/054-AzureLoadTesting/Student/Challenge-06.md
new file mode 100644
index 0000000000..fbc5d00722
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Challenge-06.md
@@ -0,0 +1,24 @@
+# Challenge 06 - Stress Testing
+
+[< Previous Challenge](./Challenge-05.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-07.md)
+
+## Introduction
+
+Unlike load testing, which ensures that a system can handle what it's designed to handle, stress testing focuses on overloading the system until it breaks. A stress test determines how stable a system is and its ability to withstand extreme increases in load. It does this by testing the maximum number requests from another service (for example) that a system can handle at a given time before performance is compromised and fails. Find this maximum to understand what kind of load the current environment can adequately support.
+
+
+## Description
+
+- Create a new set of test scripts or parameters and run a stress test
+- Identify the bottlenecks and breakpoints of the application under stress
+- Decide whether to add the steps needed to remediate to the backlog #DevOps
+
+## Success Criteria
+
+- Show a side-by-side comparison of the load tests results and the stress test results.
+- Show where the bottlenecks and breakpoints are in the application from these tests.
+
+## Learning Resources
+
+[Learn more about stress testing](https://docs.microsoft.com/en-us/azure/architecture/framework/scalability/performance-test#stress-testing)
+
diff --git a/054-AzureLoadTesting/Student/Challenge-07.md b/054-AzureLoadTesting/Student/Challenge-07.md
new file mode 100644
index 0000000000..c5663ff8af
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Challenge-07.md
@@ -0,0 +1,27 @@
+# Challenge 07 - Load Testing With Chaos Experiment (Resilience Testing)
+
+[< Previous Challenge](./Challenge-06.md) - **[Home](../README.md)**
+
+## Introduction
+
+We have gone over load testing for the majority of this hack. While the information you gather from load testing can help determine how you scale your application. The resiliency of an application isn’t solely decided by how quickly it can scale up or out - but also how it handles failures. This means planning for a failure of every application component: a single container, cluster, VM, database and region. Testing while having certain components fail is called Resilience testing. We will be going over that here.
+
+## Description
+
+- Use Azure Chaos Studio to design a Chaos experiment
+- Run a load test (make sure you have a recent baseline first)
+- During the load test, start the Chaos experiment and note the failures
+- Prioritize the failure points and build an action plan to remediate
+
+## Success Criteria
+
+- Show the failure points that occurred during your resilience testing and your remediation plan
+
+## Learning Resources
+
+[What is Azure Chaos Studio](https://docs.microsoft.com/en-us/azure/chaos-studio/chaos-studio-overview)
+
+
+## Advanced Challenges
+
+- Add your Chaos Experiment to your CI/CD workflow and configure it to run during your load test.
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/.deployment b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/.deployment
new file mode 100644
index 0000000000..56a8193d93
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/.deployment
@@ -0,0 +1,2 @@
+[config]
+command = deployment\deploy.cmd
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/ARMTemplate/parameters.json b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/ARMTemplate/parameters.json
new file mode 100644
index 0000000000..536093e900
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/ARMTemplate/parameters.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "name": {
+ "value": ""
+ },
+ "location": {
+ "value": ""
+ },
+ "tags": {
+ "value": {}
+ }
+ }
+}
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/ARMTemplate/template.json b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/ARMTemplate/template.json
new file mode 100644
index 0000000000..bc85fc30bd
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/ARMTemplate/template.json
@@ -0,0 +1,24 @@
+{
+ "$schema": "http://schema.management.azure.com/schemas/2019-08-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "name": {
+ "type": "String"
+ },
+ "location": {
+ "type": "String"
+ },
+ "tags": {
+ "type": "Object"
+ }
+ },
+ "resources": [
+ {
+ "type": "Microsoft.LoadTestService/loadtests",
+ "apiVersion": "2021-12-01-preview",
+ "name": "[parameters('name')]",
+ "location": "[parameters('location')]",
+ "tags": "[parameters('tags')]"
+ }
+ ]
+}
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/LICENSE b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/LICENSE
new file mode 100644
index 0000000000..21071075c2
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/LICENSE
@@ -0,0 +1,21 @@
+ MIT License
+
+ Copyright (c) Microsoft Corporation. All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/LICENSE.md b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/LICENSE.md
new file mode 100644
index 0000000000..79656060de
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/LICENSE.md
@@ -0,0 +1,21 @@
+ MIT License
+
+ Copyright (c) Microsoft Corporation.
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/Web.Debug.config b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/Web.Debug.config
new file mode 100644
index 0000000000..a6610362ec
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/Web.Debug.config
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/Web.config b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/Web.config
new file mode 100644
index 0000000000..8cb4131128
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/Web.config
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/azure-pipelines.yml b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/azure-pipelines.yml
new file mode 100644
index 0000000000..6d74d1f2a3
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/azure-pipelines.yml
@@ -0,0 +1,160 @@
+# Node.js
+# Build a general Node.js project with npm.
+# Add steps that analyze code, save build artifacts, deploy, and more:
+# https://docs.microsoft.com/azure/devops/pipelines/languages/javascript
+
+trigger:
+- main
+
+pool:
+ vmImage: ubuntu-latest
+
+variables:
+ webAppName: ''
+ serviceConnection: ''
+ azureSubscriptionId: ''
+ loadTestResource: ''
+ loadTestResourceGroup: ''
+ location: 'EAST US'
+
+
+stages:
+- stage: Build
+ displayName: Build
+ jobs:
+ - job: Build
+ displayName: Build
+ pool:
+ vmImage: windows-latest
+
+ steps:
+
+ - task: ArchiveFiles@2
+ displayName: 'Archive files'
+ inputs:
+ rootFolderOrFile: '$(System.DefaultWorkingDirectory)'
+ includeRootFolder: false
+ archiveType: zip
+ archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
+ replaceExistingArchive: true
+
+ - publish: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
+ artifact: drop
+
+- stage: Deploy
+ displayName: Deploy
+ dependsOn: Build
+ condition: succeeded()
+ jobs:
+ - job: Deploy
+ displayName: Deploy
+ pool:
+ vmImage: windows-latest
+
+ steps:
+ - task: AzureResourceManagerTemplateDeployment@3
+ inputs:
+ deploymentScope: 'Resource Group'
+ azureResourceManagerConnection: $(serviceConnection)
+ subscriptionId: $(azureSubscriptionId)
+ action: 'Create Or Update Resource Group'
+ resourceGroupName: '$(webAppName)-rg'
+ location: $(location)
+ templateLocation: 'Linked artifact'
+ csmFile: '$(System.DefaultWorkingDirectory)/windows-webapp-template.json'
+ overrideParameters: '-webAppName $(webAppName) -hostingPlanName $(webAppName)-host -appInsightsLocation "$(location)" -databaseAccountId $(webAppName)db -databaseAccountLocation "$(location)"'
+ deploymentMode: 'Incremental'
+ deploymentOutputs: 'output'
+
+ - task: PowerShell@2
+ inputs:
+ targetType: 'inline'
+ script: |
+ $deploymentOutput= ConvertFrom-Json '$(output)'
+ $connectionStringValue= $deploymentOutput.azureCosmosDBAccountKeys.value
+ Write-Host "##vso[task.setvariable variable=connectionString;issecret=true;]$connectionStringValue"
+
+ - task: AzureAppServiceSettings@1
+ inputs:
+ azureSubscription: $(serviceConnection)
+ appName: '$(webAppName)'
+ resourceGroupName: '$(webAppName)-rg'
+ appSettings: |
+ [
+ {
+ "name": "CONNECTION_STRING",
+ "value": "$(connectionString)",
+ "slotSetting": false
+ },
+ {
+ "name": "MSDEPLOY_RENAME_LOCKED_FILES",
+ "value": 1,
+ "slotSetting": false
+ },
+ {
+ "name": "SCM_DO_BUILD_DURING_DEPLOYMENT",
+ "value": true,
+ "slotSetting": false
+ },
+ {
+ "name": "HEADER_VALUE",
+ "value": "$(mySecret)",
+ "slotSetting": false
+ }
+ ]
+
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ artifact: drop
+
+ - task: AzureRmWebAppDeployment@4
+ inputs:
+ ConnectionType: 'AzureRM'
+ azureSubscription: $(serviceConnection)
+ appType: 'webApp'
+ WebAppName: $(webAppName)
+ packageForLinux: '$(Pipeline.Workspace)/$(Build.BuildId).zip'
+ ScriptType: 'Inline Script'
+ InlineScript: 'npm install'
+
+- stage: LoadTest
+ displayName: Load Test
+ dependsOn: Deploy
+ condition: succeeded()
+ jobs:
+ - job: LoadTest
+ displayName: Load Test
+ pool:
+ vmImage: ubuntu-latest
+ steps:
+
+ - task: AzureResourceManagerTemplateDeployment@3
+ inputs:
+ deploymentScope: 'Resource Group'
+ azureResourceManagerConnection: $(serviceConnection)
+ subscriptionId: $(azureSubscriptionId)
+ action: 'Create Or Update Resource Group'
+ resourceGroupName: $(loadTestResourceGroup)
+ location: '$(location)'
+ templateLocation: 'Linked artifact'
+ csmFile: '$(System.DefaultWorkingDirectory)/ARMTemplate/template.json'
+ csmParametersFile: '$(System.DefaultWorkingDirectory)/ARMTemplate/parameters.json'
+ overrideParameters: '-name $(loadTestResource) -location "$(location)"'
+ deploymentMode: 'Incremental'
+
+ - task: AzureLoadTest@1
+ inputs:
+ azureSubscription: $(serviceConnection)
+ loadTestConfigFile: 'SampleApp.yaml'
+ resourceGroup: $(loadTestResourceGroup)
+ loadTestResource: $(loadTestResource)
+ env: |
+ [
+ {
+ "name": "webapp",
+ "value": "$(webAppName).azurewebsites.net"
+ }
+ ]
+
+ - publish: $(System.DefaultWorkingDirectory)/loadTest
+ artifact: results
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/config.json b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/config.json
new file mode 100644
index 0000000000..65f89719e7
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/config.json
@@ -0,0 +1,3 @@
+{
+ "enableSecretsFeature": false
+}
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/connectionData.json b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/connectionData.json
new file mode 100644
index 0000000000..4f104f2154
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/connectionData.json
@@ -0,0 +1,4 @@
+{
+ "databaseName": "sampledatabase",
+ "collectionName": "samplecollection"
+}
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/css/site.css b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/css/site.css
new file mode 100644
index 0000000000..dde451d488
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/css/site.css
@@ -0,0 +1,144 @@
+html,
+body {
+ height: 100%;
+ width: 100%;
+ padding: 0;
+ margin: 0;
+}
+
+@font-face {
+ font-family: "Segoe UI";
+ src: url('../fonts/segoeuil.ttf');
+}
+
+.main-container {
+ height: 100%;
+ width: 100%;
+ background-color: #1d539d;
+ color: white;
+ padding-top: 6%;
+ box-sizing: border-box;
+ overflow-y: auto;
+ overflow-x: hidden;
+ font-family: "Segoe UI";
+}
+
+.cloud-image {
+ width: 1200px;
+ height: 250px;
+ padding-bottom: 50px;
+ margin: auto;
+}
+
+.success-text {
+ padding-bottom: 20px;
+ font-size: 62px;
+ line-height: 73px;
+}
+
+.description {
+ font-size: 34px;
+ line-height: 40px;
+}
+
+.next-steps-container {
+ padding-top: 50px;
+}
+
+.next-steps-header {
+ font-size: 24px;
+ line-height: 28px;
+ padding-bottom: 25px;
+}
+
+.next-steps-body {
+ display: flex;
+ flex-direction: column;
+}
+
+.step {
+ display: flex;
+ margin: 7px 0px;
+ font-size: 15px;
+ line-height: 21px;
+}
+
+.step-icon {
+ height: 20px;
+ width: 20px;
+ margin-right: 10px;
+}
+
+.step-text a {
+ color: white;
+ text-decoration: none;
+}
+
+.step-text a:hover {
+ color: white;
+ text-decoration: underline;
+}
+
+.content {
+ box-sizing: border-box;
+ min-width: 700px;
+ max-width: 830px;
+ position: relative;
+ margin: auto;
+}
+
+.tweet-container {
+ min-width: 30px;
+ min-height: 100px;
+ margin: 0 20px;
+ position: absolute;
+ left: -100px;
+ top: 110px;
+}
+
+.content-body {
+ min-width: 400px;
+}
+
+@media (max-width: 1024px) {
+ .main-container {
+ padding-top: 1%;
+ }
+
+ .cloud-image {
+ padding-bottom: 30px;
+ }
+
+ .next-steps-container {
+ padding-top: 30px;
+ }
+
+ .next-steps-header {
+ padding-bottom: 20px;
+ }
+
+ .success-text {
+ font-size: 50px;
+ line-height: 61px;
+ padding-bottom: 10px;
+ }
+
+ .description {
+ font-size: 26px;
+ line-height: 30px;
+ }
+
+ .step {
+ font-size: 12px;
+ line-height: 18px;
+ }
+
+ .tweet-container {
+ top: 80px;
+ }
+
+ .content {
+ max-width: 630px;
+ min-width: 630px;
+ }
+}
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/databaseOperations.js b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/databaseOperations.js
new file mode 100644
index 0000000000..6ca4e007b2
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/databaseOperations.js
@@ -0,0 +1,69 @@
+var MongoClient = require("mongodb").MongoClient;
+var fs = require('fs');
+var obj = JSON.parse(fs.readFileSync('connectionData.json', 'utf8'));
+var DbConnection = require('./db');
+
+var connectionString = "mongodb://account:key@account.documents.azure.com:10255/?ssl=true";
+var connectionString = process.env.CONNECTION_STRING;
+var stringSplit1 = connectionString.split("://")[1];
+var stringSplit2 = stringSplit1.split('@');
+var userNamePassword = stringSplit2[0];
+userNamePassword = userNamePassword.split(':');
+var userName = userNamePassword[0];
+var password = userNamePassword[1];
+var databaseName = obj.databaseName;
+var collectionName = obj.collectionName;
+connectionString = ("mongodb://" + encodeURIComponent(userName) + ":" + encodeURIComponent(password) + "@" + stringSplit2[1] + (stringSplit2.length >= 3 ? ("@" + stringSplit2[2] + "@") : ""));
+
+
+module.exports = {
+ queryCount: function (callback, errorCallback, retry = 2) {
+ DbConnection.Get()
+ .then((mongoClient) => {
+ // Find some documents
+ mongoClient.count(function (err, count) {
+ if (err != null) {
+ if(retry > 0) {
+ setTimeout(() => {
+ queryCount(callback, errorCallback, retry-1);
+ }, (3 - retry) * 600);
+ return;
+ } else {
+ errorCallback(err)
+ }
+ } else {
+ console.log(`Found ${count} records`);
+ callback(count);
+ }
+ });
+ })
+ },
+
+ addRecord: function (pageName, callback, errorCallback, retry = 2) {
+
+ DbConnection.Get()
+ .then((mongoClient) => {
+ var milliseconds = (new Date).getTime().toString();
+ var itemBody = {
+ "id": milliseconds,
+ "page": pageName
+ };
+ console.log("Connected correctly to server");
+ // Insert some documents
+ mongoClient.insertMany([itemBody], function (err, result) {
+ if (err != null) {
+ if(retry > 0) {
+ setTimeout(() => {
+ addRecord(pageName, callback, errorCallback, retry-1);
+ }, (3 - retry) * 600);
+ return;
+ } else {
+ errorCallback(err)
+ }
+ } else {
+ callback();
+ }
+ });
+ })
+ }
+}
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/db.js b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/db.js
new file mode 100644
index 0000000000..395e0dc907
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/db.js
@@ -0,0 +1,61 @@
+var MongoClient = require('mongodb').MongoClient;
+var fs = require('fs');
+
+var obj = JSON.parse(fs.readFileSync('connectionData.json', 'utf8'));
+var DbConnection = function () {
+
+ var db = null;
+ var instance = 0;
+
+ async function DbConnect() {
+ var connectionString = process.env.CONNECTION_STRING;
+ var stringSplit1 = connectionString.split("://")[1];
+ var stringSplit2 = stringSplit1.split('@');
+ var userNamePassword = stringSplit2[0];
+ userNamePassword = userNamePassword.split(':');
+ var userName = userNamePassword[0];
+ var password = userNamePassword[1];
+ var databaseName = obj.databaseName;
+ var collectionName = obj.collectionName;
+ connectionString = ("mongodb://" + encodeURIComponent(userName) + ":" + encodeURIComponent(password) + "@" + stringSplit2[1] + (stringSplit2.length >= 3 ? ("@" + stringSplit2[2] + "@") : ""));
+
+ try {
+ let _db = await MongoClient.connect(connectionString);
+
+ return _db.db(databaseName).collection(collectionName);
+ } catch (e) {
+ console.log("Error connecting to db")
+ console.log(connectionString)
+ console.log(databaseName)
+ console.log(collectionName)
+ console.log(e)
+ return e;
+ }
+ }
+
+ async function Get() {
+ try {
+ instance++; // this is just to count how many times our singleton is called.
+ console.log(`DbConnection called ${instance} times`);
+
+ if (db != null) {
+ console.log(`db connection is already alive`);
+ // db = await DbConnect(); // Bug, remove this line to enable connection pooling
+ return db;
+ } else {
+ console.log(`getting new db connection`);
+ db = await DbConnect();
+ return db;
+ }
+ } catch (e) {
+ return e;
+ }
+ }
+
+ return {
+ Get: Get
+ }
+}
+
+
+module.exports = DbConnection();
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/deployment/deploy.cmd b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/deployment/deploy.cmd
new file mode 100644
index 0000000000..7a40dcabf5
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/deployment/deploy.cmd
@@ -0,0 +1,133 @@
+@if "%SCM_TRACE_LEVEL%" NEQ "4" @echo off
+
+:: ----------------------
+:: KUDU Deployment Script
+:: Version: 1.0.17
+:: ----------------------
+
+:: Prerequisites
+:: -------------
+
+:: Verify node.js installed
+where node 2>nul >nul
+IF %ERRORLEVEL% NEQ 0 (
+ echo Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment.
+ goto error
+)
+
+:: Setup
+:: -----
+
+setlocal enabledelayedexpansion
+
+SET ARTIFACTS=%~dp0%..\artifacts
+
+IF NOT DEFINED DEPLOYMENT_SOURCE (
+ SET DEPLOYMENT_SOURCE=%~dp0%.
+)
+
+IF NOT DEFINED DEPLOYMENT_TARGET (
+ SET DEPLOYMENT_TARGET=%ARTIFACTS%\wwwroot
+)
+
+IF NOT DEFINED NEXT_MANIFEST_PATH (
+ SET NEXT_MANIFEST_PATH=%ARTIFACTS%\manifest
+
+ IF NOT DEFINED PREVIOUS_MANIFEST_PATH (
+ SET PREVIOUS_MANIFEST_PATH=%ARTIFACTS%\manifest
+ )
+)
+
+IF NOT DEFINED KUDU_SYNC_CMD (
+ :: Install kudu sync
+ echo Installing Kudu Sync
+ call npm install kudusync -g --silent
+ IF !ERRORLEVEL! NEQ 0 goto error
+
+ :: Locally just running "kuduSync" would also work
+ SET KUDU_SYNC_CMD=%appdata%\npm\kuduSync.cmd
+)
+goto Deployment
+
+:: Utility Functions
+:: -----------------
+
+:SelectNodeVersion
+
+IF DEFINED KUDU_SELECT_NODE_VERSION_CMD (
+ :: The following are done only on Windows Azure Websites environment
+ call %KUDU_SELECT_NODE_VERSION_CMD% "%DEPLOYMENT_SOURCE%" "%DEPLOYMENT_TARGET%" "%DEPLOYMENT_TEMP%"
+ IF !ERRORLEVEL! NEQ 0 goto error
+
+ IF EXIST "%DEPLOYMENT_TEMP%\__nodeVersion.tmp" (
+ SET /p NODE_EXE=<"%DEPLOYMENT_TEMP%\__nodeVersion.tmp"
+ IF !ERRORLEVEL! NEQ 0 goto error
+ )
+
+ IF EXIST "%DEPLOYMENT_TEMP%\__npmVersion.tmp" (
+ SET /p NPM_JS_PATH=<"%DEPLOYMENT_TEMP%\__npmVersion.tmp"
+ IF !ERRORLEVEL! NEQ 0 goto error
+ )
+
+ IF NOT DEFINED NODE_EXE (
+ SET NODE_EXE=node
+ )
+
+ SET NPM_CMD="!NODE_EXE!" "!NPM_JS_PATH!"
+) ELSE (
+ SET NPM_CMD=npm
+ SET NODE_EXE=node
+)
+
+goto :EOF
+
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+:: Deployment
+:: ----------
+
+:Deployment
+echo Handling node.js deployment.
+
+:: 1. KuduSync
+IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
+ call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
+ IF !ERRORLEVEL! NEQ 0 goto error
+)
+
+:: 2. Select node version
+call :SelectNodeVersion
+
+:: 3. Install npm packages
+IF EXIST "%DEPLOYMENT_TARGET%\package.json" (
+ pushd "%DEPLOYMENT_TARGET%"
+ call :ExecuteCmd !NPM_CMD! install --production
+ IF !ERRORLEVEL! NEQ 0 goto error
+ popd
+)
+
+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+goto end
+
+:: Execute command routine that will echo out when error
+:ExecuteCmd
+setlocal
+set _CMD_=%*
+call %_CMD_%
+if "%ERRORLEVEL%" NEQ "0" echo Failed exitCode=%ERRORLEVEL%, command=%_CMD_%
+exit /b %ERRORLEVEL%
+
+:error
+endlocal
+echo An error has occurred during web site deployment.
+call :exitSetErrorLevel
+call :exitFromFunction 2>nul
+
+:exitSetErrorLevel
+exit /b 1
+
+:exitFromFunction
+()
+
+:end
+endlocal
+echo Finished successfully.
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/deploymentscript.ps1 b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/deploymentscript.ps1
new file mode 100644
index 0000000000..e32831c2e3
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/deploymentscript.ps1
@@ -0,0 +1,97 @@
+function Get-UrlStatusCode([string] $Url)
+{
+ try
+ {
+ [System.Net.WebRequest]::Create($Url).GetResponse().StatusCode
+ }
+ catch [Net.WebException]
+ {
+ [int]$_.Exception.Response.StatusCode
+ }
+}
+
+$ErrorActionPreference = "Stop"
+[Console]::ResetColor()
+# az login --use-device-code
+$output = az account show -o json | ConvertFrom-Json
+$subscriptionList = az account list -o json | ConvertFrom-Json
+$subscriptionList | Format-Table name, id, tenantId -AutoSize
+$selectedSubscription = $output.name
+Write-Host "Currently logged in to subscription """$output.name.Trim()""" in tenant " $output.tenantId
+$selectedSubscription = Read-Host "Enter subscription Id ("$output.id")"
+$selectedSubscription = $selectedSubscription.Trim()
+if([string]::IsNullOrWhiteSpace($selectedSubscription)) {
+ $selectedSubscription = $output.id
+} else {
+ # az account set --subscription $selectedSubscription
+ Write-Host "Changed to subscription ("$selectedSubscription")"
+}
+
+while($true) {
+ $deploymentName = Read-Host -Prompt "Enter webapp name"
+ $deploymentName = $deploymentName.Trim()
+ if($deploymentName.ToLower() -match "xbox") {
+ Write-Host "Webapp name cannot have keywords xbox,windows,login,microsoft"
+ continue
+ } elseif ($deploymentName.ToLower() -match "windows") {
+ Write-Host "Webapp name cannot have keywords xbox,windows,login,microsoft"
+ continue
+ } elseif ($deploymentName.ToLower() -match "login") {
+ Write-Host "Webapp name cannot have keywords xbox,windows,login,microsoft"
+ continue
+ } elseif ($deploymentName.ToLower() -match "microsoft") {
+ Write-Host "Webapp name cannot have keywords xbox,windows,login,microsoft"
+ continue
+ }
+ # Create the request
+ $HTTP_Status = Get-UrlStatusCode('http://' + $deploymentName + '.azurewebsites.net')
+ if($HTTP_Status -eq 0) {
+ break
+ } else {
+ Write-Host "Webapp name taken"
+ }
+}
+
+$location = Read-Host -Prompt "Enter location (eastus)"
+$location = $location.Trim()
+if([string]::IsNullOrWhiteSpace($location)) {
+ $location = "eastus"
+}
+
+$resourceGroup = $deploymentName + $location + "-rg"
+Write-Host "Creating resource group " $resourceGroup
+az group create --location $location --name $resourceGroup --subscription $selectedSubscription
+$databaseName = $deploymentName + "db"
+
+Write-Host "Deploying Sample application.. (this might take a few minutes)"
+$deploymentOutputs = az deployment group create --resource-group $resourceGroup --subscription $selectedSubscription --mode Incremental --template-file ./windows-webapp-template.json --parameters "webAppName=$deploymentName" --parameters "hostingPlanName=$deploymentName-host" --parameters "appInsightsLocation=$location" --parameters "databaseAccountId=$databaseName" --parameters "databaseAccountLocation=$location" -o json
+$deploymentOutputs = $deploymentOutputs | ConvertFrom-Json
+$connectionString = [String]($deploymentOutputs.properties.outputs.azureCosmosDBAccountKeys.value -split '&')[0]
+
+Write-Host "Setting connection string to cosmos db"
+$setConnectionString = az webapp config appsettings set --name $deploymentName --resource-group $resourceGroup --subscription $selectedSubscription --settings CONNECTION_STRING="$connectionString"
+
+Write-Host "Setting app setting for App Service"
+$setAppSettings = az webapp config appsettings set --name $deploymentName --resource-group $resourceGroup --subscription $selectedSubscription --settings MSDEPLOY_RENAME_LOCKED_FILES=1
+
+$publishConfig = az webapp deployment list-publishing-credentials --name $deploymentName --resource-group $resourceGroup --subscription $selectedSubscription -o json | ConvertFrom-Json
+
+Write-Host "Publishing sample app.. (this might take a minute or two)"
+#Creating a deployment package first
+Compress-Archive -Path ./* -CompressionLevel Fastest -DestinationPath ./App.zip -Force
+
+#Deploying to the app service with zipped package
+az webapp deploy --resource-group $resourceGroup --name $deploymentName --src-path .\App.zip
+
+while($true) {
+ Write-Host "Warming up App Service.."
+ Start-Sleep -s 3
+ # Create the request
+ $HTTP_Status = Get-UrlStatusCode('http://' + $deploymentName + '.azurewebsites.net')
+ if($HTTP_Status -eq 200) {
+ Write-Host "Deployment Complete"
+ Write-Host "Open url https://$deploymentName.azurewebsites.net in the browser"
+ Write-Host "To delete the app, run command 'az group delete --name $resourceGroup'"
+ exit
+ }
+}
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/fonts/segoeuil.ttf b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/fonts/segoeuil.ttf
new file mode 100644
index 0000000000..53edf71e0c
Binary files /dev/null and b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/fonts/segoeuil.ttf differ
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/azureCosmosDB.svg b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/azureCosmosDB.svg
new file mode 100644
index 0000000000..3a2c00cb0b
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/azureCosmosDB.svg
@@ -0,0 +1,11 @@
+
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/cloneWhite.svg b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/cloneWhite.svg
new file mode 100644
index 0000000000..5ab997fd6f
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/cloneWhite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/deployWhite.svg b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/deployWhite.svg
new file mode 100644
index 0000000000..7ceb211e6e
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/deployWhite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/lightbulbWhite.svg b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/lightbulbWhite.svg
new file mode 100644
index 0000000000..c1fef37d16
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/lightbulbWhite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/stackWhite.svg b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/stackWhite.svg
new file mode 100644
index 0000000000..6ba12096a4
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/stackWhite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/successCloudNew.svg b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/successCloudNew.svg
new file mode 100644
index 0000000000..18759d8717
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/successCloudNew.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/tweetThis.svg b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/tweetThis.svg
new file mode 100644
index 0000000000..0645220976
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/img/tweetThis.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/index.html b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/index.html
new file mode 100644
index 0000000000..ff01c6d425
--- /dev/null
+++ b/054-AzureLoadTesting/Student/Resources/Sample-nodejs-loadtest-app/index.html
@@ -0,0 +1,15 @@
+
+
+
+ Node.js Application
+
+
+