Introduction to Amazon Code Pipeline with Java part 14: the loadtest executor service

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:

Set Apica load test properties for code pipeline

  • 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:

Load test properties added to action

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.

Advertisements

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

ultimatemindsettoday

A great WordPress.com site

iReadable { }

.NET Tips & Tricks

Robin Sedlaczek's Blog

Developer on Microsoft Technologies

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

the software architecture

thoughts, ideas, diagrams,enterprise code, design pattern , solution designs

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: