Automated testing
|
Overview
Manual testing can be useful in finding defects in a product but is time consuming, laborious and for products with the size and scope of MMOs can be extremely expensive. Automated testing involves the creation of programs to test your product in a repeatable and more efficient manner helping to reduce defects and potentially revealing classes of defects that would not otherwise be encountered until too late (such as what happens under the load of thousands of users). HeroEngine provides multiple frameworks allowing for the automated testing of HeroEngine itself, and also for your specific game implementation. These will allow you to stress test your game code and or hardware to determine what your capacity is, or if you have important bottlenecks that need to be fixed.
A commonly asked question is "How many users will I be able to service per physical server?", unfortunately the answer to the question is not simple as X users per machine. The number of users a physical server can support varies on a large number of factors almost all of which depend on your implementation and/or game design as the vast majority of all server load is directly attributable to game logic.
Some of the Factors affecting users per physical server:
- Hardware
- Bandwidth Budget per User
- Game Design
- Architecture of the Game Systems
- Programmer Experience
Fortunately, automated testing allows you to determine the answer for your game by creating tests that put your game systems under load with the additional benefit of providing testing for your game.
There are two different frameworks which available to perform automated testing, based on the type of testing that you are doing:
- Extremely lightweight client
- Headless client
Usage
What Must I Do to "Fully" Load Test A Game?
If you need to test a full game implementation to determine production load, you need:
- A full game implementation sufficiently close to what you expect to launch with for the data to be relevant
- A world running on production machines with an appropriate server cluster supporting it
- Dedicated Network infrastructure close to that which you plan to release on (i.e. you don't want your data contaminated by someone downloading from youtube)
- with network characteristics that realistically model your user population in:
- bandwidth
- latency
- packet loss
- with network characteristics that realistically model your user population in:
- Hardware to run sufficient testing clients to simulate the load you need
The constraints under which you are probably operating likely do not allow for a fully realistic test to be done (or at least not until late beta).
We recommend you determine the areas that are of concern and devise smaller tests that exercise just that functionality and then measure the resulting performance. For example, when we needed to test Repository Server infrastructure we created a test using the XLC that requested files randomly from amongst the files listed in a test file. Doing so revealed that a single Repository Server process was more than capable of keeping up with several thousand simulated users saturating the gigabit Ethernet card occupying less than a single core of an eight core physical server.
Client Authentication
By default, authentication for HeroEngine is handled through a stub implementation (HEUAccess) of the UACCESS Protocol. A stub, or your real authentication system, must be implemented to allow the clients to connect to the service directory and retrieve a list of subscriptions. For example, you might implement a stub that allowed any client specifying an account name "TEST-" to connect using any password to facilitate testing of large numbers of pseudo users using the lightweight or headless clients.
An example of such a stub can be found on the HEUAccess page.
Extremely Lightweight Client
Overview
This client is used to test underlying functionality of HeroEngine such as logging into a Service Directory or downloading files from the Repository. It is not used to run AI or Game Logic. Technically, the extremely lightweight client requires building four separate executables that are used together to perform the tests.
The client runs on Windows OSes and assuming modern hardware you can expect to run 200-250 per machine without any issues as you move into the 300-400 range you tend to run out of windows handles before having issues with the actual application itself.
Building the Solutions
Creating the Extremely Lightweight Client requires building four different executables:
- The Extremely Lightweight Client itself
- The Director, which launches the client process
- The Test Controller
- The Client that connects to the Test Controller
Building: Lightweight Client Director
- Open the solution \\<PerforceRoot>\hetesting\hetesting.sln
- Build the solution in release
- Create a directory C:\hetesting\
- copy the contents of \\<PerforceRoot>\hetesting\run to it
- Run the application C:\hetesting\light_client_director.exe
- Change the configurations as necessary (make sure each machine has a different account/charactername prefix set for it, we used A,B,C etc)
Directory Listening Port: tcp:209.16.216.141:62341 Service Directory Port: tcp:hedev.heroengine.com:10373 World: Dev Account Prefix: TEST-A Character Name Prefix: TestA
- Save the configuration for future runs
- Close the Light Client Director application
- Open the LCDConfigs.txt file, and change the second to last line to point to the machine on which you will be running the Stress Server
- Restart the Light Client Director application (you may want this to be in a looping .bat file for testing)
Building: Stress Server
- Open the solution \\<PerforceRoot>\stress\stress.sln
- Build the solution in release
- Create a folder named stressserver in C:\hetesting\
- copy the contents of \\<PerforceRoot>\hetesting\stress server\bin\Release\ to the folder C:\hetesting\stressserver\ you created previously
- Create a file in C:\hetesting\stressserver\ named stressserver.cfg
GROUP=SERVER LWD_LISTENER_PORT=50404 USER_LISTENER_PORT=50403 LWD_LISTENER_HOST=209.16.216.141 USER_LISTENER_HOST=209.16.216.141 //LWD_LISTENER_HOST=timmy.heroengine.com //USER_LISTENER_HOST=timmy.heroengine.com END_GROUP
- Run StressServer.exe
- Lightweight Client Directory should connect
Building: Stress Client
- Create a directory for the stress client e.g. C:\hetesting\stressclient
- Copy the contents of \\<PerforceRoot>\stress\stressclient\bin\Release to the directory
- Create a stressclient.cfg file
- the HOST parameter may be specified either by DNS name or IP
GROUP=CLIENT PORT=50403 HOST=209.16.216.141 //HOST=timmy.heroengine.com END_GROUP
Deployment
Deployment of the Extremely Lightweight Client framework entails copying the folder you created in the Build step to the various physical servers you intend to use for testing and modifying some configuration values.
Physical (Control) Server
One machine should be designated as the control
server and it is this machine that the Stress Server and Stress Client applications run. The control
server may also simultaneously function as a test
server by running a Light Client Director in addition to the Stress Server/Client applications.
Requirements:
- Supported OSes include Windows Vista, Windows 7, Windows 8, Server 2008, and later OS versions.
- Copy the C:\hetesting\ folder you created in the build step to the physical control server
- Run the Stress Server application
- Run the Stress Client Application
- Run the application C:\hetesting\light_client_directory.exe
- Modify the Configuration
- Director Listening Port: (this can either be by IP or dns lookup) leave the port as 62341
- Service Directory Port: This should point to the Service Directory for your test world
- World: The name of the test world
- Save the Configuration
- Modify the Configuration
Physical Test Server Setup
For each of the servers you intend to use to run test clients, you must perform a few simple setup steps.
Requirements:
- Supported OSes include Windows Vista, Windows 7, Windows 8, Server 2008 and later OS versions
- Copy the C:\hetesting\ folder from the "control" server to each physical test server
- Run the application C:\hetesting\light_client_directory.exe
- Modify the Account and Character Name Prefixes to be unique
- Save the Configuration Changes
The important configuration change that must be made is that each physical test
server should be given a different Account and Character Name Prefix.
For example, if you are using three test servers the first one should use TEST-A, the second one TEST-B, and the third one TEST-C. The reason is that the Director uses the prefix to create unique account names by incrementing a local (to the server) counter spinning up TEST-A1, TEST-A2, and so on. If two machines are configured to use the same prefix, the Lightweight Clients will end up disconnecting each other due to duplicate logins.
The prefix you choose is not important persay, but it may be important depending on how you have implemented HEUAccess to allow authentication of testing clients, for example the provided sample code allows any account named TEST* access. Consequently, you should check your HEUAccess implementation for any particular requirements it may have on account names.
Likewise, character name prefix should be unique per physical server (i.e. per Light Client Director).
Stress Server
The stress server communicates with the light client directors to coordinate the tests started by the stress client application. The only thing you can really do with the Stress Server application is start or stop it. You can think of the stress server as the equivalent of the Master Control server application (not to be confused with the Master Control Console GUI you run on your local machine).
- Users ; Number of stress clients connected to the stress server
- LWD ; Number of lightweight client directors connected to the stress server
- CTR ; Clients left yet to run, this will most often display 0 due to the speed at which clients can be spun up
- CCLC ; Current client launch count
- CRC ; Currently running clients
Stress Client
The stress client is used to configure and start/stop test runs by communicating with the stress server, you can think of this as the equivalent of the Master Control Console application.
- Users ; Number of stress clients connected to the stress server
- LWD ; Number of lightweight client directors connected to the stress server
- CTR ; Clients left yet to run, this will most often display 0 due to the speed at which clients can be spun up
- CCLC ; Current client launch count
- CRC ; Currently running clients
Exit Codes
- 0 - success
- 134 - Terminated normally by the Lightweight Client Director (via the button), this generally qualifies as success.
- 137 - Internal error, check solution
- Others - check solution
Test Modes
Currently, the stress client supports three different test modes:
- servicedirectory - tests authentication to the service directory, and the immediately disconnects
- repository - tests load on the repository servers
- game - partial framework that could be used for the most basic types of functionality such as logging into the game. Due to changes in the login process, as well as indeterminate dependencies on your games specific login/character creation code this is only a framework. This mode can NOT be used to fully test game functionality as it does not execute HeroScript code nor does it have a DOM/GOM.
// Possible parameters are as follows: // // --director-transport - string which contains the transport to the director process (auto generated) // --client-sequence - Number set by the director (auto generated) // --mode - possible modes are servicedirectory, repository, game // --service-directory - transport of the service directory to connect to // --username (auto generated) // --password (auto generated) // --world (auto generated) // --character (auto generated) // --extended-logging - set to true additional information displayed in stress client // // Repository parameters // // --file-list // --request-count // --request-duration // --request-limits // --request-rate // --request-order // --cache-directory // --bandwidth-target
Example
--mode=servicedirectory --service-directory=hedev.heroengine.com
Additional information can be found in the code located at \\<PerforceRoot>\hetesting\extremely_light_client\LightClient.cpp.
Light Client Director
The Light Client Director is in charge of spinning up Extremely Lightweight Clients on a particular physical server (i.e. you have one LCD per physical machine you are using in your test). The LCD can be thought of as the equivalent of a FireupDaemon on a HeroEngine Server and you may wish to write a .bat file to loop running the LCD process so that they auto restart after the Stress Server issues a Reset command (i.e. shutdown LCDs).
Please note, the Launch Clients button is deprecated functionality as launching clients is now initiated via the Stress Client UI
Headless client
Overview
![]() |
The Headless Client has roughly the same requirements as the Player Client, consequently machines used to host Headless Clients must be capable of running the Player Client. |
Headless client is more similar to a real client than the Extremely Lightweight Client, and runs AI scripts allowing it to do anything HSL can do (which is pretty close to everything). It is a version of the player client that runs as a server process. It is controllable through script, and basically connects to your game and plays your game under script control, to simulate what a player character might do under your game implementation.
The headless client takes up significantly more RAM than the Extremely Lightweight Client as it must load all of the models and the physics representation for the area, the DOM, the GOM, etc. Additionally, it is much heavier weight from CPU perspective as it is running all game logic normally. Due to the number of imponderables related to your game design, area design, and systems you can run anywhere from a few to an upper limit of low tens on a modern desktop (more on actual server hardware, but not an order of magnitude more).
- There are two server processes involved:
- Test Director process, which is roughly equivalent in functionality to the physics director in that it is in charge of handling requests from the servers to spin up new test client processes on machines within its designated server group.
- Test Client process, which is roughly equivalent to a physics server process spun up by a director.
Usage
In order to utilize the Headless client you must:
- Build the solutions
- Create a server group with appropriate hardware
- Deployment
- Create Daemon Definitions
- Write HSL Client-side AI to drive your test(s)
- Initiate a Test run via HSL
Building the Solutions
The test client requires that you build the following solutions:
- Firestorm
- HeroBlade
- HJTesting
Building: FireStorm
FireStorm is the communication layer of HeroEngine and must be compiled in release mode to prepare the firestorm.lib
.
- Open Firestorm solution located at \\<PerforceRoot>\firestorm\firestorm.sln
- Compile it in release executables mode
Building: HeroBlade
- Open the HeroBlade solution located at \\<PerforceRoot>\heroblade\HeroBlade.sln
- Compile it in release
Building: HJTesting
- Open the HJTesting solution located at \\<PerforceRoot>\hjtesting\hjtesting.sln
- Compile it in release
Create a server group
Server groups are arbitrary groupings of physical machines created using Master Control Console upon which HeroEngine's director processes (those configured to utilize a particular group) may spin up their child processes.
Hardware Requirements:
- All servers (or workstations) in the test group MUST be capable of running the Player Client. In other words they must be Windows OS, DirectX9+ with sufficient RAM and CPU to run the Player Client. If you can not run Player Client on it, you will not be able to run the Headless Client on it.
The software installation and configuration changes described below in #Deployment must be made on each of the machines in the server group.
Deployment
Deployment is performed by hand on each of the servers upon which you intend to spin up test clients.
- Create a directory parallel to the firestorm daemons install. For example, if you have FirestormDaemons installed at C:\Program Files\HeroEngine\FirestormDaemonsHEDEV\, create a directory C:\Program Files\HeroEngine\TestingHEDEV folder
- Copy the run directory for HJTesting to your new folder (after building the solutions above) it will be located in \\<PerforceRoot>\hjtesting\Run\
- Create a config file in C:\Documents and Settings\All users\Application Data\HeroEngine\configs\ named appropriately for your project. (e.g. TESTINGHEDEV.cfg)
[TEST_DIRECTOR] Executable_name=testdirector.exe Executable_path=C:\Program Files\HeroEngine\TESTINGHEDEV\
[TEST_CLIENT] Executable_name=testclient.exe Executable_path=C:\Program Files\HeroEngine\TESTINGHEDEV\
- Browse to the Firestorm Daemons install directory. Edit the configs.lst file to include a line with the path to the config file.
C:\Documents and Settings\All Users\Application Data\HeroEngine\configs\FIRESTORMDAEMONSHEDEV.cfg C:\Documents and Settings\All Users\Application Data\HeroEngine\configs\HJSERVERSHEDEV.cfg C:\Documents and Settings\All Users\Application Data\HeroEngine\configs\TESTINGHEDEV.cfg
- Restart the Fireup Daemon (on each server) to load the new config file
- Log into the server
- Select the loopFireup command window
- Cntrl-C and hit n
Set Up Daemon/Process Definitions
Using Master Control Console create TEST_DIRECTOR Daemon and TEST_CLIENT Process Definitions. Once the definitions are created, restart Master Control (i.e. type /reset in the chat panel of Master Control Console.
Director Daemon Definition
Using Master Control Console, edit the configurations to add a new daemon definition for the TEST_DIRECTOR. Which will require you enter the following parameters:
- Name - name for the daemon, TEST_DIRECTOR is fine unless you intend to run multiple test directors
- Server Group - name of the server group upon which processes should be spun up
- Executable Tag - name of the TAG in the configuration file that specifies the executable name and/or path. See the section on deployment for additional details on the configuration file, but below is a sample executable tag.
[TEST_DIRECTOR] Executable_name=testdirector.exe Executable_path=C:\Program Files\HeroEngine\TESTINGHEDEV\
Director Process Definition
Using Master Control Console, edit the configurations to add a new process definition for the TEST_DIRECTOR. Which will require you enter the following parameters:
- Name - Name of the process, we recommend for static processes such as this one that you include the name of the Fireup Daemon (machine) in the name. (e.g. for a machine named Nelson... TEST_DIRECTOR (NELSON) )
- Daemon - Select your the Directory Daemon from the drop down list.
- Startup Order - Number controlling startup ordering for processes during world spinup, 2200 should generally work.
- Fireup Daemon - Name of the Fireup Daemon upon which the director should be spun up. In the image, the fireup named NELSON (for the machine named Nelson) has been choosen.
[TEST_DIRECTOR] Executable_name=testdirector.exe Executable_path=C:\Program Files\HeroEngine\TESTINGHEDEV\
Modify the following Process Parameters:
- TestClientServiceDirectoryConnectString - The connect string can be derived from the parameters for the service directory for the world which is to be tested.
tcp:servicedirectory.play.net:10373
- InstancedTestDaemonID - The instance id for the test daemon is assigned during creation. Unfortunately, at this time it is not exposed in the UI. Consequently, you will need to utilize a SQL statement to retrieve the information.
Connect as FS_SERVICE to the database for the Master Control Schema (generally this is the same as your world, but some configurations may differ) select daemon from daemon where daemon_name = 'TEST_CLIENT';
Client Daemon Definition
Using Master Control Console, edit the configurations to add a new daemon definition for the TEST_CLIENT. Which will require you enter the following parameters:
- Name - name for the daemon, TEST_CLIENT is fine unless you intend to run multiple test clients
- Server Group - name of the server group upon which processes should be spun up
- Executable Tag - name of the TAG in the configuration file that specifies the executable name and/or path. See the section on deployment for additional details on the configuration file, but below is a sample executable tag.
[TEST_CLIENT] Executable_name=testclient.exe Executable_path=C:\Program Files\HeroEngine\TESTINGHEDEV\
Add Test Director Service to the World
Once defined, you must now add a service to the world to be tested so you can actually fire up the service and start using it.
- Start by selecting the World to be tested from the Services section of Master Control selecting GAME (<name>)
- Hit the Edit button
- On the Edit a Service Dialog hit the "Add" button.
- Select the test director process from the list and hit save
Reset Master Control
Reset Master Control so that the new definitions are loaded.
Fireup Director Service
- after resetting master control
- Select your world in Master Control Console
- Expand the tree so you can see all of the components of your world's GAME static processes
- Select the test_director, and hit the fireup button
Optionally, shutting down the world and bringing it back up will (in effect) do the same thing
Implement Script Behavior
There are essentially two scripted components:
- A server test framework utilized to spin up test clients and (probably) recording data submitted by them for later analysis
- A client test framework handling the client automation which knows how to perform a variety of tests testing/stressing your game's systems.
Implementing Server Test Framework
Basically, you need to write a system or simple command that utilizes the external function LaunchTestClient() passing appropriate parameters to the system. A more elaborate system would support the ability to collect data from the test clients and correlate them for later analysis and/or comparison. Ultimately, how complicated you make your test framework is a function of the features you want it to support.
// Sends a message to the test director to launch a headless test client with the given arguments // method _TestDirectorResponse(requestID as ID, launchSuccess as Boolean) will be called after the launch attempt external function LaunchTestClient(callback as NodeRef, requestID as ID, username as String, password as String, testNumber as ID, testArguments as String)
- requestID - arbitrary ID assigned by your system to the launch request
- callback - node which is to receive a callback upon (un)successful launch of the requested client.
- userName - User name to be used for authentication, generally something your authentication system HEUAccess. For ease of use, typically you modify your authentication system to simply allow all acounts with a known prefix to connect (e.g. TEST-)
- password - password for authentication, depending on the implementation of the authentication system may not matter
- testNumber - arbitrary ID assigned to this test by your system, generally used to group data results
- testArguments - arbitrary string argument which is passed to the client and exposed through the
GetTestParameters()
external function
Implementing Client Test Framework
The client test framework needs to understand what kind of test it is supposed to be performing, and then support the logic required to perform the test. You can think of this as AI for the client, basically telling it what to do based on the conditions known to it. For example, you might write a test that understands how to create a new character and exercise the features of your character creation system talking to the server scripts just as a real client would and perhaps even going so far as to fake mouse clicks on UI elements on the client.
- Create a game specific override class for the $BASECLIENT system node as described here
- implement HE_FirstChance() override method
- In the override, call the external function GetTestParameters(). If the function call returns true, then the client is a headless client and the test framework for client automation can be instantiated.
// Obtain the headless client test parameters. Note that these values are not set for non headless clients external function GetTestParameters(testNumber references ID, testArguments references String) as Boolean
- testNumber - arbitrary ID assigned by the server test framework to the test, typically used to correlate resulting data
- testArguments - arbitrary string assigned by the server test framework to this test client, typically used to determine what kind of client automation is desired.
- Instantiate a test client automation class based on the string supplied to the client by the server (via the LaunchTestClient() external function parameter
- Automation classes should perform tests in a repeatable fashion for testing your systems and producing repeatable load (stress)