com.teradata.benchto.service.BenchmarkControllerTest.java Source code

Java tutorial

Introduction

Here is the source code for com.teradata.benchto.service.BenchmarkControllerTest.java

Source

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.teradata.benchto.service;

import com.teradata.benchto.service.category.IntegrationTest;
import com.teradata.benchto.service.model.BenchmarkRun;
import com.teradata.benchto.service.model.BenchmarkRunExecution;
import com.teradata.benchto.service.model.Environment;
import com.teradata.benchto.service.repo.BenchmarkRunRepo;
import com.teradata.benchto.service.repo.EnvironmentRepo;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.concurrent.Callable;

import static com.teradata.benchto.service.model.MeasurementUnit.BYTES;
import static com.teradata.benchto.service.model.MeasurementUnit.MILLISECONDS;
import static com.teradata.benchto.service.model.Status.ENDED;
import static com.teradata.benchto.service.model.Status.FAILED;
import static com.teradata.benchto.service.utils.TimeUtils.currentDateTime;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@Category(IntegrationTest.class)
public class BenchmarkControllerTest extends IntegrationTestBase {
    @Autowired
    private BenchmarkRunRepo benchmarkRunRepo;

    @Autowired
    private EnvironmentRepo environmentRepo;

    @Test
    public void testBenchmarkStartEndHappyPath() throws Exception {
        doTestBenchmarkSuccessfulExecution(true, false);
    }

    @Test
    public void testExecutionFinishReportedAfterBenchmarkEnd() throws Exception {
        doTestBenchmarkSuccessfulExecution(false, true);
    }

    private void doTestBenchmarkSuccessfulExecution(boolean reportRunFinishBeforeBenchmarkFinish,
            boolean sendEndTimeWithExecutionFinish) throws Exception {
        String environmentName = "environmentName";
        String benchmarkName = "benchmarkName" + reportRunFinishBeforeBenchmarkFinish;
        String uniqueName = benchmarkName + "_k1=v1";
        String benchmarkSequenceId = "benchmarkSequenceId";
        String executionSequenceId = "executionSequenceId";
        ZonedDateTime testStart = currentDateTime();

        // create environment
        mvc.perform(post("/v1/environment/{environmentName}", environmentName).contentType(APPLICATION_JSON)
                .content("{\"attribute1\": \"value1\", \"attribute2\": \"value2\"}")).andExpect(status().isOk());

        // get environment
        mvc.perform(get("/v1/environment/{environmentName}", environmentName)).andExpect(status().isOk())
                .andExpect(jsonPath("$.name", is(environmentName)))
                .andExpect(jsonPath("$.attributes.attribute1", is("value1")))
                .andExpect(jsonPath("$.attributes.attribute2", is("value2")));

        // start benchmark
        mvc.perform(
                post("/v1/benchmark/{benchmarkName}/{benchmarkSequenceId}/start", uniqueName, benchmarkSequenceId)
                        .contentType(APPLICATION_JSON)
                        .content("{\"name\": \"" + benchmarkName + "\",\"environmentName\": \"" + environmentName
                                + "\", \"variables\":{\"k1\":\"v1\"}}"))
                .andExpect(status().isOk()).andExpect(content().string(uniqueName));

        // get benchmark - no measurements, no executions
        mvc.perform(get("/v1/benchmark/{uniqueName}/{benchmarkSequenceId}", uniqueName, benchmarkSequenceId))
                .andExpect(status().isOk()).andExpect(jsonPath("$.name", is(benchmarkName)))
                .andExpect(jsonPath("$.uniqueName", is(uniqueName))).andExpect(jsonPath("$.status", is("STARTED")))
                .andExpect(jsonPath("$.sequenceId", is(benchmarkSequenceId)))
                .andExpect(jsonPath("$.environment.name", is(environmentName)))
                .andExpect(jsonPath("$.variables.k1", is("v1"))).andExpect(jsonPath("$.measurements", hasSize(0)))
                .andExpect(jsonPath("$.executions", hasSize(0)));

        // start execution
        mvc.perform(post("/v1/benchmark/{uniqueName}/{benchmarkSequenceId}/execution/{executionSequenceId}/start",
                uniqueName, benchmarkSequenceId, executionSequenceId).contentType(APPLICATION_JSON)
                        .content("{\"attributes\": {}}"))
                .andExpect(status().isOk());

        // get benchmark - no measurements, single execution without measurements
        mvc.perform(get("/v1/benchmark/{uniqueName}/{benchmarkSequenceId}", uniqueName, benchmarkSequenceId))
                .andExpect(status().isOk()).andExpect(jsonPath("$.name", is(benchmarkName)))
                .andExpect(jsonPath("$.uniqueName", is(uniqueName))).andExpect(jsonPath("$.status", is("STARTED")))
                .andExpect(jsonPath("$.sequenceId", is(benchmarkSequenceId)))
                .andExpect(jsonPath("$.environment.name", is(environmentName)))
                .andExpect(jsonPath("$.measurements", hasSize(0))).andExpect(jsonPath("$.executions", hasSize(1)))
                .andExpect(jsonPath("$.variables.k1", is("v1")))
                .andExpect(jsonPath("$.executions[0].status", is("STARTED")))
                .andExpect(jsonPath("$.executions[0].sequenceId", is(executionSequenceId)));

        Instant executionFinish = currentDateTime().toInstant();
        Callable<?> reportExecutionFinish = () -> {
            // finish execution - post execution measurements
            mvc.perform(post(
                    "/v1/benchmark/{uniqueName}/{benchmarkSequenceId}/execution/{executionSequenceId}/finish",
                    uniqueName, benchmarkSequenceId, executionSequenceId).contentType(APPLICATION_JSON).content(
                            "{\"measurements\":[{\"name\": \"duration\", \"value\": 12.34, \"unit\": \"MILLISECONDS\"},{\"name\": \"bytes\", \"value\": 56789.0, \"unit\": \"BYTES\"}],"
                                    + "\"attributes\":{\"attribute1\": \"value1\"}, \"status\": \"FAILED\""
                                    + (sendEndTimeWithExecutionFinish
                                            ? (", \"endTime\": " + toJsonRepresentation(executionFinish))
                                            : "")
                                    + "}"))
                    .andExpect(status().isOk());

            return null;
        };

        Callable<?> reportBenchmarkFinish = () -> {
            // finish benchmark - post benchmark measurements
            mvc.perform(post("/v1/benchmark/{uniqueName}/{benchmarkSequenceId}/finish", uniqueName,
                    benchmarkSequenceId).contentType(APPLICATION_JSON).content(
                            "{\"measurements\":[{\"name\": \"meanDuration\", \"value\": 12.34, \"unit\": \"MILLISECONDS\"},{\"name\": \"sumBytes\", \"value\": 56789.0, \"unit\": \"BYTES\"}],"
                                    + "\"attributes\":{\"attribute1\": \"value1\"}, \"status\": \"ENDED\"}"))
                    .andExpect(status().isOk());

            return null;
        };

        ZonedDateTime testEnd;
        if (reportRunFinishBeforeBenchmarkFinish) {
            reportExecutionFinish.call();
            reportBenchmarkFinish.call();
            testEnd = currentDateTime();
        } else {
            reportBenchmarkFinish.call();
            testEnd = currentDateTime();
            Thread.sleep(2); // make sure current time changes (assuming we're not on Windows)
            reportExecutionFinish.call();
        }

        mvc.perform(get("/v1/benchmark/{uniqueName}?environment={environment}", uniqueName, environmentName))
                .andExpect(status().isOk()).andExpect(jsonPath("$.[0].name", is(benchmarkName)))
                .andExpect(jsonPath("$.[0].uniqueName", is(uniqueName)))
                .andExpect(jsonPath("$.[0].sequenceId", is(benchmarkSequenceId)))
                .andExpect(jsonPath("$.[0].status", is("ENDED")))
                .andExpect(jsonPath("$.[0].variables.k1", is("v1")))
                .andExpect(jsonPath("$.[0].environment.name", is(environmentName)))
                .andExpect(jsonPath("$.[0].attributes.attribute1", is("value1")))
                .andExpect(jsonPath("$.[0].measurements", hasSize(2)))
                .andExpect(jsonPath("$.[0].measurements[*].name", containsInAnyOrder("meanDuration", "sumBytes")))
                .andExpect(jsonPath("$.[0].measurements[*].value", containsInAnyOrder(12.34, 56789.0)))
                .andExpect(jsonPath("$.[0].measurements[*].unit", containsInAnyOrder("MILLISECONDS", "BYTES")))
                .andExpect(jsonPath("$.[0].executions", hasSize(1)))
                .andExpect(jsonPath("$.[0].executions[0].sequenceId", is(executionSequenceId)))
                .andExpect(jsonPath("$.[0].executions[0].status", is("FAILED")))
                .andExpect(jsonPath("$.[0].executions[0].attributes.attribute1", is("value1")))
                .andExpect(jsonPath("$.[0].executions[0].measurements[*].name",
                        containsInAnyOrder("duration", "bytes")))
                .andExpect(
                        jsonPath("$.[0].executions[0].measurements[*].value", containsInAnyOrder(12.34, 56789.0)))
                .andExpect(jsonPath("$.[0].executions[0].measurements[*].unit",
                        containsInAnyOrder("MILLISECONDS", "BYTES")));

        // assert database state
        withinTransaction(() -> {
            Environment environment = environmentRepo.findByName(environmentName);
            assertThat(environment).isNotNull();
            assertThat(environment.getName()).isEqualTo(environmentName);
            assertThat(environment.getAttributes().get("attribute1")).isEqualTo("value1");
            assertThat(environment.getAttributes().get("attribute2")).isEqualTo("value2");

            BenchmarkRun benchmarkRun = benchmarkRunRepo.findByUniqueNameAndSequenceId(uniqueName,
                    benchmarkSequenceId);
            assertThat(benchmarkRun).isNotNull();
            assertThat(benchmarkRun.getId()).isGreaterThan(0);
            assertThat(benchmarkRun.getName()).isEqualTo(benchmarkName);
            assertThat(benchmarkRun.getVariables()).containsEntry("k1", "v1");
            assertThat(benchmarkRun.getUniqueName()).isEqualTo(uniqueName);
            assertThat(benchmarkRun.getSequenceId()).isEqualTo(benchmarkSequenceId);
            assertThat(benchmarkRun.getStatus()).isEqualTo(ENDED);
            assertThat(benchmarkRun.getMeasurements()).hasSize(2).extracting("unit").contains(BYTES, MILLISECONDS);
            assertThat(benchmarkRun.getStarted()).isAfter(testStart).isBefore(testEnd);
            assertThat(benchmarkRun.getEnded()).isAfter(testStart).isBefore(testEnd);
            assertThat(benchmarkRun.getExecutions()).hasSize(1);

            BenchmarkRunExecution execution = benchmarkRun.getExecutions().iterator().next();
            assertThat(execution.getId()).isGreaterThan(0);
            assertThat(execution.getSequenceId()).isEqualTo(executionSequenceId);
            assertThat(execution.getStatus()).isEqualTo(FAILED);
            assertThat(execution.getMeasurements()).hasSize(2).extracting("name").contains("duration", "bytes");
            assertThat(execution.getStarted()).isAfter(testStart).isBefore(testEnd);
            assertThat(execution.getEnded()).isAfter(testStart).isBefore(testEnd);
        });
    }

    private static String toJsonRepresentation(Instant instant) {
        return format("%d.%03d", instant.getEpochSecond(), instant.toEpochMilli() % 1000);
    }

    @Test
    public void testJsr303Validation() throws Exception {
        String environmentName = generateStringOfLength('T', 100);
        String benchmarkName = "benchmarkName";
        String benchmarkSequenceId = "benchmarkSequenceId";

        // environment name larger than max 64 bytes - we should get bad request response - 4XX
        mvc.perform(post("//v1/benchmark/{benchmarkName}/{benchmarkSequenceId}/start", benchmarkName,
                benchmarkSequenceId).contentType(APPLICATION_JSON)
                        .content("{\"environmentName\": \"" + environmentName + "\"}"))
                .andExpect(status().is4xxClientError());
    }

    public String generateStringOfLength(char ch, int length) {
        StringBuffer str = new StringBuffer(length);
        for (int i = 0; i < length; i++) {
            str.append(ch);
        }
        return str.toString();
    }
}