org.jboss.pnc.causeway.ctl.ImportControllerTest.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.pnc.causeway.ctl.ImportControllerTest.java

Source

/**
 * Copyright (C) 2015 Red Hat, Inc. (jbrazdil@redhat.com)
 *
 * 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 org.jboss.pnc.causeway.ctl;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import com.redhat.red.build.koji.model.json.KojiImport;

import org.jboss.pnc.causeway.CausewayException;
import org.jboss.pnc.causeway.CausewayFailure;
import org.jboss.pnc.causeway.brewclient.BrewClient;
import org.jboss.pnc.causeway.brewclient.BuildTranslatorImpl;
import org.jboss.pnc.causeway.brewclient.ExternalLogImportFileGenerator;
import org.jboss.pnc.causeway.config.CausewayConfig;
import static org.jboss.pnc.causeway.ctl.PncImportControllerImpl.messageMissingTag;

import org.jboss.pnc.causeway.metrics.MetricsConfiguration;
import org.jboss.pnc.causeway.rest.BrewBuild;
import org.jboss.pnc.causeway.rest.BrewNVR;
import org.jboss.pnc.causeway.rest.CallbackMethod;
import org.jboss.pnc.causeway.rest.CallbackTarget;
import org.jboss.pnc.causeway.rest.model.Build;
import org.jboss.pnc.causeway.rest.model.MavenBuild;
import org.jboss.pnc.causeway.rest.model.MavenBuiltArtifact;
import org.jboss.pnc.causeway.rest.model.response.ArtifactImportError;
import org.junit.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.*;

import static org.mockito.Mockito.*;
import org.mockito.InjectMocks;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.charset.Charset;
import java.util.stream.Collectors;

import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.tomakehurst.wiremock.client.WireMock;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.redhat.red.build.koji.model.json.util.KojiObjectMapper;

public class ImportControllerTest {

    @Rule
    public WireMockRule wireMockRule = (new WireMockRule(8081));

    private static final String USERNAME = "joe";
    private static final String TAG_PREFIX = "pnc-foo-0.1";
    private static final String BUILD_VERSION = "1.1.1";
    private static final String ARTIFACTS_VERSION = "1.1.1.redhat_1";
    private static final String BUILD_NAME = "org.apache.geronimo.specs:geronimo-annotation_1.0_spec";
    private static final String CALLBACK_URL = "http://localhost:8081/callback";
    private static final CallbackTarget CALLBACK_TARGET = new CallbackTarget(CALLBACK_URL, CallbackMethod.POST);
    private static final String KOJI_URL = "http://koji.example.com/koji";
    private static final String KOJI_BUILD_URL = KOJI_URL + "/build?id=";

    private static final BrewNVR NVR = new BrewNVR(BUILD_NAME, BUILD_VERSION, "1");

    private static final ExternalLogImportFileGenerator IMPORT_FILE_GENERATOR = mock(
            ExternalLogImportFileGenerator.class);
    private static final KojiImport KOJI_IMPORT = mock(KojiImport.class);

    private static final ObjectMapper mapper = new KojiObjectMapper();

    @Mock
    private BrewClient brewClient;
    @Mock
    private CausewayConfig causewayConfig;

    @Mock
    public BuildTranslatorImpl translator;

    @Mock
    public MetricsConfiguration metricsConfiguration;

    @Mock
    public MetricRegistry metricRegistry;

    @InjectMocks
    private ImportControllerImpl importController;

    @Before
    public void before() throws Exception {
        MockitoAnnotations.initMocks(this);
        when(causewayConfig.getKojiURL()).thenReturn(KOJI_URL);
        when(causewayConfig.getKojiWebURL()).thenReturn(KOJI_BUILD_URL);
        when(metricsConfiguration.getMetricRegistry()).thenReturn(metricRegistry);
        when(metricRegistry.meter(anyString())).thenReturn(mock(Meter.class));
        Timer timer = mock(Timer.class);
        when(metricRegistry.timer(anyString())).thenReturn(timer);
        when(timer.time()).thenReturn(mock(Timer.Context.class));

        mapper.registerSubtypes(MavenBuild.class, MavenBuiltArtifact.class);

        stubFor(post(urlEqualTo("/callback")).willReturn(aResponse().withStatus(200)));
    }

    private Build getBuild() throws IOException {
        String json = readResponseBodyFromTemplate("build.json");
        return mapper.readValue(json, Build.class);
    }

    private void mockBrew() throws CausewayException {
        doReturn(true).when(brewClient).tagsExists(eq(TAG_PREFIX));
        doReturn(KOJI_BUILD_URL + "11").when(brewClient).getBuildUrl(11);
        doNothing().when(brewClient).tagBuild(TAG_PREFIX, NVR);
    }

    private void mockTranslator() throws CausewayException {
        doReturn(KOJI_IMPORT).when(translator).translate(eq(NVR), any(), any());
        doReturn(IMPORT_FILE_GENERATOR).when(translator).getImportFiles(any());
    }

    @Test
    public void testImportBuildWhenExistingBrewBuildIsImported() throws Exception {
        // Test setup
        mockBrew();

        // Mock existing Brew build
        doReturn(new BrewBuild(11, NVR)).when(brewClient).findBrewBuildOfNVR(eq(NVR));

        // Run import
        importController.importBuild(getBuild(), CALLBACK_TARGET, USERNAME);

        // Verify
        verifySuccess("Build was already imported with id 11");
    }

    @Test
    public void testImportBuild() throws Exception {
        // Test setup
        mockBrew();
        mockTranslator();

        // Mock Brew import
        BrewBuild brewBuild = new BrewBuild(11, NVR);
        doReturn(brewBuild).when(brewClient).importBuild(eq(NVR), same(KOJI_IMPORT), same(IMPORT_FILE_GENERATOR));

        // Run import
        importController.importBuild(getBuild(), CALLBACK_TARGET, USERNAME);

        // Verify
        verifySuccess("Build imported with id 11");
    }

    @Test
    public void testImportBuildWithEmptyArtifacts() throws Exception {
        // Test setup
        mockBrew();

        // Mock no builds in milestone
        Build build = getBuild();
        build.getBuiltArtifacts().clear();

        // Run import
        importController.importBuild(build, CALLBACK_TARGET, USERNAME);

        // Verify
        verifyFailure("Build doesn't contain any artifacts");
    }

    @Test
    public void testImportBuildWhereImportBuildThrowsException() throws Exception {
        String exceptionMessage = "Import build failed";

        // Test setup
        mockBrew();

        // Mock exception from Brew Client
        doThrow(new CausewayException(exceptionMessage)).when(brewClient).findBrewBuildOfNVR(eq(NVR));

        // Run import
        importController.importBuild(getBuild(), CALLBACK_TARGET, USERNAME);

        // Verify
        verifyError(exceptionMessage);
    }

    @Test
    public void testImportBuildWithArtifactImportErrors() throws Exception {
        String errorMessage = "Artifact import error";
        final String exceptionMessage = "Failure while importing artifacts";

        // Test setup
        mockBrew();
        mockTranslator();

        List<ArtifactImportError> artifactImportErrors = new ArrayList<>();
        ArtifactImportError importError = ArtifactImportError.builder().artifactId(123).errorMessage(errorMessage)
                .build();
        artifactImportErrors.add(importError);
        doThrow(new CausewayFailure(artifactImportErrors, exceptionMessage)).when(brewClient).importBuild(eq(NVR),
                same(KOJI_IMPORT), same(IMPORT_FILE_GENERATOR));

        // Run import
        importController.importBuild(getBuild(), CALLBACK_TARGET, USERNAME);

        // Verify
        verifyFailure(exceptionMessage, artifactImportErrors);
    }

    @Test
    public void testImportBuildWhenTagDoesNotExistInBrew() throws Exception {

        // Test setup
        mockBrew();
        doReturn(false).when(brewClient).tagsExists(TAG_PREFIX);

        // Run import
        importController.importBuild(getBuild(), CALLBACK_TARGET, USERNAME);

        // Verify
        verifyFailure(messageMissingTag(TAG_PREFIX, KOJI_URL).replace("\n", "\\n"));
    }

    @Test
    public void testGetNVR() throws IOException, CausewayException, ReflectiveOperationException {
        Build build = getBuild();
        BrewNVR nvr = importController.getNVR(build);
        assertEquals(BUILD_NAME, nvr.getName());
        assertEquals(BUILD_VERSION, nvr.getVersion());

        setFinalField(build, Build.class.getDeclaredField("buildVersion"), null);
        nvr = importController.getNVR(build);
        assertEquals(BUILD_NAME, nvr.getName());
        assertEquals(ARTIFACTS_VERSION, nvr.getVersion());
    }

    static void setFinalField(Object obj, Field field, Object newValue) throws ReflectiveOperationException {
        field.setAccessible(true);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        field.set(obj, newValue);
    }

    private void verifySuccess(String log) {

        String result = "{" + "\"id\":null," + "\"buildRecordId\":61," + "\"status\":\"SUCCESS\"," + "\"log\":\""
                + log + "\"," + "\"artifactImportErrors\":null," + "\"brewBuildId\":11," + "\"brewBuildUrl\":\""
                + KOJI_BUILD_URL + "11\"" + "}";

        WireMock.verify(postRequestedFor(urlEqualTo("/callback")).withRequestBody(WireMock.equalToJson(result)));
    }

    private void verifyFailure(String log) {
        verifyFailure(log, Collections.emptyList());
    }

    private void verifyFailure(String log, List<ArtifactImportError> artifactImportErrors) {
        String artifacts = "null";
        if (!artifactImportErrors.isEmpty()) {
            artifacts = artifactImportErrors.stream().map(a -> "{" + "\"artifactId\":" + a.getArtifactId() + ","
                    + "\"errorMessage\":\"" + a.getErrorMessage() + "\"" + "}")
                    .collect(Collectors.joining(",", "[", "]"));
        }

        String result = "{" + "\"id\":null," + "\"buildRecordId\":61," + "\"status\":\"FAILED\"," + "\"log\":\""
                + log + "\"," + "\"artifactImportErrors\":" + artifacts + "," + "\"brewBuildId\":null,"
                + "\"brewBuildUrl\":null" + "}";

        WireMock.verify(postRequestedFor(urlEqualTo("/callback")).withRequestBody(WireMock.equalToJson(result)));
    }

    private void verifyError(String log) {
        String result = "{" + "\"id\":null," + "\"buildRecordId\":61," + "\"status\":\"SYSTEM_ERROR\","
                + "\"log\":\"" + log + "\"," + "\"artifactImportErrors\":null," + "\"brewBuildId\":null,"
                + "\"brewBuildUrl\":null" + "}";

        WireMock.verify(postRequestedFor(urlEqualTo("/callback")).withRequestBody(WireMock.equalToJson(result)));
    }

    private String readResponseBodyFromTemplate(String name) throws IOException {
        String folderName = getClass().getPackage().getName().replace(".", "/");
        try (InputStream inputStream = getContextClassLoader().getResourceAsStream(folderName + "/" + name)) {
            return StringUtils.join(IOUtils.readLines(inputStream, Charset.forName("utf-8")), "\n");
        }
    }

    private ClassLoader getContextClassLoader() {
        return Thread.currentThread().getContextClassLoader();
    }
}