Introduction to Amazon Code Pipeline with Java part 14: the loadtest executor service
June 4, 2016 Leave a comment
Introduction
In the previous post we took a closer look at how the client token lookup service could be implemented. The client lookup service is responsible for locating the Code Pipeline client token that matches the client ID which CP sends as the first signal of a new job. Without a matching client token CP won’t hand out the job details. It’s up to you how you implement the service exactly. The implementation details will probably depend on how you stored the client token and the client ID of a given user in your backend system.
In this post we’ll keep digging into the code in the job agent by looking at the LtpApiLoadtestJobExecutorService class.
The load test job executor service
Recall the code example from this post where we discussed the application’s entry point. We’ve got as far as the following bit up to now:
ICodePipelineService codePipelineService = new LtpWebApiCodePipelineService(hostnameVerifier, sslTrustManager, properties);
In this post we’ll go one line further onto…
LtpApiLoadtestJobExecutorService ltpApiLoadtestJobExecutorService = new LtpApiLoadtestJobExecutorService(hostnameVerifier, sslTrustManager, properties);
This class is a service that’s really like a wrapper around our own backend API service. We’ll therefore not see the exact implementation details. However, it’s still important to understand what it does in order to follow the full entry point code example. In case you’re interested to learn more about the implementation details you’re welcome to ask questions in the comments section below.
The LtpApiLoadtestJobExecutorService class implements the ILoadtestJobExecutorService interface:
public interface ILoadtestJobExecutorService { public PresetResponse checkPreset(String clientId, String clientToken, String presetName); public RunnableFileResponse checkRunnableFile(String clientId, String clientToken, String fileName); public StartJobByPresetResponse transmitJob(TransmitJobRequestArgs transmitJobArgs); public JobStatusResponse checkJobStatus(JobStatusRequest jobStatusRequest); public LoadtestJobSummaryResponse getJobSummaryResponse(LoadtestJobSummaryRequest summaryRequest); }
Let’s look at the role of each function. Here’s a screenshot we saw before with some terms that are important in this context:
- checkPreset: “preset” is a domain from our business. It’s a container for a lot of parameters that are necessary for a single load test. A load test requires a wide range of parameters, like the user count, the test duration, the test location and many more. A preset is a name under which a user can save these settings in our web site. It’s like the Save As function in word processors. The checkPreset function simply checks if there’s a preset by the name supplied in the “presetName” parameter. The PresetResponse object includes a boolean that tells us whether the preset exists. Without this preset the load test cannot continue.
- checkRunnableFile: similar to checkPreset, but this one checks for the presence of a load test scenario file which includes the steps to be taken during a load test. The load test cannot continue without this file
- transmitJob: this function is responsible for starting a load test job
- checkJobStatus: this function returns the load test status, such as “running” or “failed”
- getJobSummaryResponse: this function extracts some interesting statistics about a successful load test, such as the average response time or the number of failed URL calls
Since this interface and its implementation are not bound to Code Pipeline we’ll only see the implementation stubs:
package com.apica.awscodepipelinebuildrunner.loadtest; import com.amazonaws.util.json.Jackson; import com.apica.awscodepipelinebuildrunner.services.LtpWebApiServiceBase; import com.apica.awscodepipelinebuildrunner.ssl.ISslHostnameVerifier; import com.apica.awscodepipelinebuildrunner.ssl.ISslTrustManager; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.Properties; import javax.net.ssl.HttpsURLConnection; public class LtpApiLoadtestJobExecutorService extends LtpWebApiServiceBase implements ILoadtestJobExecutorService { public LtpApiLoadtestJobExecutorService(ISslHostnameVerifier sslHostnameVerifier, ISslTrustManager sslTrustManager, Properties properties) { super(sslHostnameVerifier, sslTrustManager, properties); } @Override public PresetResponse checkPreset(String clientId, String clientToken, String presetName) { PresetResponse presetResponse = new PresetResponse(); //code ignored return presetResponse; } @Override public RunnableFileResponse checkRunnableFile(String clientId, String clientToken, String fileName) { RunnableFileResponse runnableFileResponse = new RunnableFileResponse(); //code ignored return runnableFileResponse; } @Override public StartJobByPresetResponse transmitJob(TransmitJobRequestArgs transmitJobArgs) { StartJobByPresetResponse resp = new StartJobByPresetResponse(); //code ignored return resp; } @Override public JobStatusResponse checkJobStatus(JobStatusRequest jobStatusRequest) { JobStatusResponse resp = new JobStatusResponse(); //code ignored return resp; } @Override public LoadtestJobSummaryResponse getJobSummaryResponse(LoadtestJobSummaryRequest summaryRequest) { LoadtestJobSummaryResponse resp = new LoadtestJobSummaryResponse(); //code ignored return resp; } }
In fact all implementations follow the same pattern. They call a web API endpoint and process the response, that’s really all there is.
The above object is used as a parameter to the ApicaLoadtestJobProcessor object in the next line of the entry point code:
JobProcessor jobProcessor = new ApicaLoadtestJobProcessor(ltpApiLoadtestJobExecutorService, new CodePipelineLoadtestThresholdParser());
The details of JobProcessor and ApicaLoadtestJobProcessor are for the upcoming posts, but we can quickly sort out the second parameter CodePipelineLoadtestThresholdParser. A threshold in our load testing domain means a limit of some statistics. E.g. the user can specify that a load test should be marked as failed if the average response time has exceeded a certain value, like 1500 milliseconds. These threshold objects are saved somewhat cryptically in Code Pipeline:
The “avg_resp_page|gt|5000|f” bit of string means that the load test should fail “f” if the average response time per page “avg_resp_page” is greater than “gt” 5000 milliseconds. The CodePipelineLoadtestThresholdParser class is a helper class that helps translate these codes into “real” Threshold objects. Again, they are not specific to CP so we’ll only look at some stubs. The parser must implement the following interface:
public interface ICodePipelineLoadtestThresholdParser { List<Threshold> decode(String encodedInput); String encode(List<Threshold> thresholds); }
…and here’s the implementation stub:
package com.apica.awscodepipelinebuildrunner.model.thresholds; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class CodePipelineLoadtestThresholdParser implements ICodePipelineLoadtestThresholdParser { @Override public List<Threshold> decode(String encodedInput) { List<Threshold> thresholds = new ArrayList<>(); //code ignored return thresholds; } private List<Metric> allMetricTypes() { List<Metric> allMetrics = new ArrayList<>(); //code ignored return allMetrics; } private List<EvaluationOperation> allEvaluationTypes() { List<EvaluationOperation> operations = new ArrayList<>(); //code ignored return operations; } @Override public String encode(List<Threshold> thresholds) { return ""; } }
In the next post we’ll look at the JobProcessor interface. We’ll also need to look at a range of other objects and classes at the same time.
View all posts related to Amazon Web Services and Big Data here.