Dial your load - custom load patterns in VSTS Load Tests

We often are asked about our support for different load patterns in a load test.

What's a load pattern? A load pattern controls the number of users that the load test is simulating at a given period of time in the load test.

We ship with three load patterns: constant, step, and goal-based. But we also provide a key extensibility point in our load test plugin that enables you to pretty easily build any pattern you want. It even enables you to "dial" the load up or down in real time while the test is running.

Here's a simple plugin that billbar wrote that ramps load up and then back down:

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.VisualStudio.TestTools.LoadTesting;
namespace TestProject1
{
/*
This class is a sample LoadTest Plug-in class that ensures implements a custom load profile.
Specifically, in this example the user load steps up from 1 to 50 users by increasing the load
by one user every 30 seconds, and then decreases the user load by 1 user every 30 seconds until
the user load reaches 0.
To use this class:
1. Add the class to a test project.
2. [Optional] If you want a different load pattern than the one described above, change the
implementation of the method GetLoadForElapsedTime().
3. Build the test project.
4. Hook this load test plugin up to your load test: in the load test editor, select the top-most node
in the load test tree (the load test name in the tree), and go to the property sheet.
Click on the ... icon by the value for "Load Test Plug-in" and you should be able to select the
CustomLoadProfileLoadTestPlugin class as your plugin.
*/
public class CustomLoadProfileLoadTestPlugin : ILoadTestPlugin
{
#region ILoadTestPlugin Members
// The initialize method is called just before the load test starts running
public void Initialize(LoadTest loadTest)
{
m_loadTest = loadTest;
// Register to listen for the heartbeat event

loadTest.Heartbeat += new EventHandler<HeartbeatEventArgs>(loadTest_Heartbeat);
}
// This method returns the user load as a function of the number of elapsed seconds
// into the load test. In this example, the user load starts at 1, increases by 1
// every 30 seconds to a max of 50, and then decreases by 1 every 30 seconds until the
// user load goes to 0. The load test that uses this example should be set to have a during
// of at least 50 minutes to go through the entire cycle.
private int GetLoadForElapsedTime(int elapsedSeconds)
{
if (elapsedSeconds < 30 * 50)
{
return (elapsedSeconds / 30) + 1;
}
else
{
return Math.Max(0, 50 - ((elapsedSeconds - (30 * 50)) / 30));
}
}
// This method changes the current user load for the 1st Scenario in the load test
// This example assumes there is only one scenario in the load test
void SetLoad(int newLoad)
{
((LoadTestScenario)m_loadTest.Scenarios[0]).CurrentLoad = newLoad;
}
// HeartBeat event handler - this gets calls once every second during the load test
// including during the warmup period
void loadTest_Heartbeat(object sender, HeartbeatEventArgs e)
{
if (e.IsWarmupComplete)
{
SetLoad(GetLoadForElapsedTime(e.ElapsedSeconds));
}
}
LoadTest m_loadTest;
#endregion
}
}

Here's the load test plugin I wrote that reads the current load from a file. Then I used notepad to "dial" the load up and down (I also wrote a simple winforms app that allows you to spin the load up and down, but I'll leave that as an exercise to the reader :)):

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.VisualStudio.TestTools.LoadTesting;
namespace Plugins
{
/*
This class is a sample load test plugin that allows you
to dynamically change the load while the test is running.
Notice the m_loadFilePath, which is the file that load
will be read from.
This sample assumes there is a single load scenario. It
would be fairly easy to extend this to multiple scenarios.
*/
public class LoadDialLoadTestPlugin : ILoadTestPlugin
{
#region ILoadTestPlugin Members
public void Initialize(LoadTest loadTest)
{
m_loadTest = loadTest;
if (File.Exists(m_loadFilePath))
{
loadTest.Heartbeat += new EventHandler<HeartbeatEventArgs>(loadTest_Heartbeat); m_loadFileTime = File.GetLastWriteTime(m_loadFilePath);
SetLoad();
}
}
void SetLoad()
{
// Read the load and set it on the first scenario
StreamReader loadFileStream = File.OpenText(m_loadFilePath);
string load = loadFileStream.ReadLine();
((LoadTestScenario)m_loadTest.Scenarios[0]).CurrentLoad = Int16.Parse(load);
loadFileStream.Close();
}
void loadTest_Heartbeat(object sender, HeartbeatEventArgs e)
{
// If running on a rig, we only want to set the load from one agent
if (m_loadTest.Context.AgentId != 1)
{
return;
}
// If the file has been modified, read the new load
DateTime loadFileTime = File.GetLastWriteTime(m_loadFilePath);
if (loadFileTime > m_loadFileTime)
{
SetLoad();
}
}
LoadTest m_loadTest;
DateTime m_loadFileTime;
string m_loadFilePath = "c:\\public\\load.txt";
#endregion
}
}

You can see how super-easy it is to add your own custom load patterns using the load test plugin.