com.sonyericsson.jenkins.plugins.bfa.CauseManagementHudsonTest.java Source code

Java tutorial

Introduction

Here is the source code for com.sonyericsson.jenkins.plugins.bfa.CauseManagementHudsonTest.java

Source

/*
 * The MIT License
 *
 * Copyright 2014 Sony Mobile Communications Inc. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.sonyericsson.jenkins.plugins.bfa;

import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlTable;
import com.gargoylesoftware.htmlunit.html.HtmlTableRow;
import com.sonyericsson.jenkins.plugins.bfa.db.KnowledgeBase;
import com.sonyericsson.jenkins.plugins.bfa.db.MongoDBKnowledgeBase;
import com.sonyericsson.jenkins.plugins.bfa.model.FailureCause;
import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseModification;
import com.sonyericsson.jenkins.plugins.bfa.model.ScannerJobProperty;
import com.sonyericsson.jenkins.plugins.bfa.model.indication.BuildLogIndication;
import hudson.Util;
import hudson.model.FreeStyleProject;
import hudson.util.Secret;
import org.apache.commons.lang.StringUtils;
import org.jvnet.hudson.test.HudsonTestCase;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.powermock.reflect.Whitebox;

import javax.servlet.http.HttpSession;
import java.text.DateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
 * Hudson tests for {@link CauseManagement}.
 *
 * @author Robert Sandell <robert.sandell@sonyericsson.com>
 */
public class CauseManagementHudsonTest extends HudsonTestCase {

    private static final int NAME_CELL = 0;
    private static final int CATEGORY_CELL = 1;
    private static final int DESCRIPTION_CELL = 2;
    private static final int COMMENT_CELL = 3;
    private static final int MODIFIED_CELL = 4;
    private static final int LAST_SEEN_CELL = 5;

    /**
     * Tests {@link com.sonyericsson.jenkins.plugins.bfa.CauseManagement#isUnderTest()}.
     */
    public void testIsUnderTest() {
        assertTrue(CauseManagement.getInstance().isUnderTest());
    }

    /**
     * Verifies that the table on the {@link CauseManagement} page displays all causes with description and that
     * one of them can be navigated to and a valid edit page for that cause is shown.
     *
     * @throws Exception if so.
     */
    public void testTableViewNavigation() throws Exception {
        KnowledgeBase kb = PluginImpl.getInstance().getKnowledgeBase();

        //Overriding isStatisticsEnabled in order to display all fields on the management page:
        KnowledgeBase mockKb = spy(kb);
        when(mockKb.isStatisticsEnabled()).thenReturn(true);
        Whitebox.setInternalState(PluginImpl.getInstance(), "knowledgeBase", mockKb);

        List<String> myCategories = new LinkedList<String>();
        myCategories.add("myCtegory");

        //CS IGNORE MagicNumber FOR NEXT 5 LINES. REASON: TestData.
        Date endOfWorld = new Date(1356106375000L);
        Date birthday = new Date(678381175000L);
        Date millenniumBug = new Date(946681200000L);
        Date pluginReleased = new Date(1351724400000L);

        FailureCause cause = new FailureCause(null, "SomeName", "A Description", "Some comment", endOfWorld,
                myCategories, null, Collections.singletonList(new FailureCauseModification("user", birthday)));
        cause.addIndication(new BuildLogIndication("."));
        kb.addCause(cause);
        cause = new FailureCause(null, "SomeOtherName", "A Description", "Another comment", millenniumBug,
                myCategories, null,
                Collections.singletonList(new FailureCauseModification("user", pluginReleased)));
        cause.addIndication(new BuildLogIndication("."));
        kb.addCause(cause);

        WebClient web = createWebClient();
        HtmlPage page = web.goTo(CauseManagement.URL_NAME);
        HtmlTable table = (HtmlTable) page.getElementById("failureCausesTable");

        Collection<FailureCause> expectedCauses = kb.getShallowCauses();

        int rowCount = table.getRowCount();
        assertEquals(expectedCauses.size() + 1, rowCount);
        Iterator<FailureCause> causeIterator = expectedCauses.iterator();

        FailureCause firstCause = null;

        for (int i = 1; i < rowCount; i++) {
            assertTrue(causeIterator.hasNext());
            FailureCause c = causeIterator.next();
            HtmlTableRow row = table.getRow(i);
            String name = row.getCell(NAME_CELL).getTextContent();
            String categories = row.getCell(CATEGORY_CELL).getTextContent();
            String description = row.getCell(DESCRIPTION_CELL).getTextContent();
            String comment = row.getCell(COMMENT_CELL).getTextContent();
            String modified = row.getCell(MODIFIED_CELL).getTextContent();
            String lastSeen = row.getCell(LAST_SEEN_CELL).getTextContent();
            assertEquals(c.getName(), name);
            assertEquals(c.getCategoriesAsString(), categories);
            assertEquals(c.getDescription(), description);
            assertEquals(c.getComment(), comment);
            assertEquals("Modified date should be visible",
                    DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
                            .format(c.getLatestModification().getTime()) + " by user",
                    modified);
            assertEquals("Last seen date should be visible",
                    DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(c.getLastOccurred()),
                    lastSeen);
            if (i == 1) {
                firstCause = c;
            }
        }

        //The table looks ok, now lets see if we can navigate correctly.

        assertNotNull(firstCause);

        HtmlAnchor firstCauseLink = (HtmlAnchor) table.getCellAt(1, 0).getFirstChild();
        HtmlPage editPage = firstCauseLink.click();

        verifyCorrectCauseEditPage(firstCause, editPage);
    }

    /**
     * Tests that the "new cause" link on the page navigates to a correct page.
     * @throws Exception if so.
     */
    public void testNewNavigation() throws Exception {

        WebClient web = createWebClient();
        HtmlPage page = web.goTo(CauseManagement.URL_NAME);

        HtmlAnchor newLink = page.getAnchorByHref(CauseManagement.NEW_CAUSE_DYNAMIC_ID);
        HtmlPage editPage = newLink.click();

        verifyCorrectCauseEditPage(
                new FailureCause(CauseManagement.NEW_CAUSE_NAME, CauseManagement.NEW_CAUSE_DESCRIPTION, ""),
                editPage);
    }

    /**
     * Makes a modification to a {@link FailureCause} and verifies that the modification date was updated.
     * @throws Exception if something goes wrong
     */
    public void testMakeModificationUpdatesDate() throws Exception {
        List<FailureCauseModification> modifications = new LinkedList<FailureCauseModification>();
        modifications.add(new FailureCauseModification("unknown", new Date(1)));
        FailureCause cause = new FailureCause(null, "SomeName", "A Description", "Some comment", null, "", null,
                modifications);
        cause.addIndication(new BuildLogIndication("."));
        PluginImpl.getInstance().getKnowledgeBase().addCause(cause);

        WebClient web = createWebClient();
        HtmlPage page = web.goTo(CauseManagement.URL_NAME);

        HtmlTable table = (HtmlTable) page.getElementById("failureCausesTable");
        HtmlTableRow row = table.getRow(1);
        final String firstModification = row.getCell(MODIFIED_CELL).getTextContent();

        HtmlAnchor firstCauseLink = (HtmlAnchor) table.getCellAt(1, 0).getFirstChild();
        HtmlPage editPage = firstCauseLink.click();

        editPage.getElementByName("_.comment").setTextContent("new comment");

        HtmlForm form = editPage.getFormByName("causeForm");
        page = submit(form);

        table = (HtmlTable) page.getElementById("failureCausesTable");
        row = table.getRow(1);
        final String secondModification = row.getCell(MODIFIED_CELL).getTextContent();

        assertThat(secondModification, not(equalTo(firstModification)));
        assertThat(secondModification, not(equalTo(StringUtils.EMPTY)));
    }

    /**
     * Makes a modification to a {@link FailureCause} and verifies that the modification list was updated.
     * @throws Exception if something goes wrong
     */
    public void testMakeModificationUpdatesModificationList() throws Exception {
        List<FailureCauseModification> modifications = new LinkedList<FailureCauseModification>();
        modifications.add(new FailureCauseModification("unknown", new Date(1)));
        FailureCause cause = new FailureCause(null, "SomeName", "A Description", "Some comment", null, "", null,
                modifications);
        cause.addIndication(new BuildLogIndication("."));
        PluginImpl.getInstance().getKnowledgeBase().addCause(cause);

        WebClient web = createWebClient();
        HtmlPage page = web.goTo(CauseManagement.URL_NAME);

        HtmlTable table = (HtmlTable) page.getElementById("failureCausesTable");

        HtmlAnchor firstCauseLink = (HtmlAnchor) table.getCellAt(1, 0).getFirstChild();
        HtmlPage editPage = firstCauseLink.click();

        HtmlElement modList = editPage.getElementById("modifications");
        int firstNbrOfModifications = modList.getChildNodes().size();

        editPage.getElementByName("_.comment").setTextContent("new comment");

        HtmlForm form = editPage.getFormByName("causeForm");
        submit(form);

        editPage = firstCauseLink.click();
        modList = editPage.getElementById("modifications");
        int secondNbrOfModifications = modList.getChildNodes().size();

        assertEquals(firstNbrOfModifications + 1, secondNbrOfModifications);
        assertStringContains("Latest modification date should be visible", modList.getFirstChild().asText(),
                DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
                        .format(cause.getLatestModification().getTime()));
    }

    //CS IGNORE MagicNumber FOR NEXT 100 LINES. REASON: TestData.
    /**
     * Tests that an error message is shown when there is no reachable Mongo database.
     * @throws Exception if so.
     */
    public void testNoMongoDB() throws Exception {
        KnowledgeBase kb = new MongoDBKnowledgeBase("someurl", 1234, "somedb", "user", Secret.fromString("pass"),
                false, false);
        Whitebox.setInternalState(PluginImpl.getInstance(), kb);
        WebClient web = createWebClient();
        HtmlPage page = web.goTo(CauseManagement.URL_NAME);
        HtmlElement element = page.getElementById("errorMessage");
        assertNotNull(element);
    }

    /**
     * Verifies that the page is displaying the expected cause correctly.
     *
     * @param expectedCause the cause that is expected to be displayed.
     * @param editPage      the page to verify.
     * @see #testNewNavigation()
     * @see #testTableViewNavigation()
     */
    private void verifyCorrectCauseEditPage(FailureCause expectedCause, HtmlPage editPage) {
        HtmlForm form = editPage.getFormByName("causeForm");
        String actualId = form.getInputByName("_.id").getValueAttribute();
        if (Util.fixEmpty(expectedCause.getId()) == null) {
            assertNull(Util.fixEmpty(actualId));
        } else {
            assertEquals(expectedCause.getId(), actualId);
        }
        assertEquals(expectedCause.getName(), form.getInputByName("_.name").getValueAttribute());
        HtmlElement descrArea = form.getOneHtmlElementByAttribute("textarea", "name", "_.description");
        String description = descrArea.getTextContent();
        assertEquals(expectedCause.getDescription(), description);

        HtmlElement commentArea = form.getOneHtmlElementByAttribute("textarea", "name", "_.comment");
        String comment = commentArea.getTextContent();
        assertEquals(expectedCause.getComment(), comment);

        if (!expectedCause.getIndications().isEmpty()) {
            HtmlElement indicationsDiv = form.getOneHtmlElementByAttribute("div", "name", "indications");
            HtmlInput patternInput = indicationsDiv.getOneHtmlElementByAttribute("input", "name", "pattern");
            assertEquals(expectedCause.getIndications().get(0).getPattern().pattern(),
                    patternInput.getValueAttribute());
        }
    }

    /**
     * Tests {@link CauseManagement#doRemoveConfirm(String, org.kohsuke.stapler.StaplerRequest,
     * org.kohsuke.stapler.StaplerResponse)}.
     * Assumes that the default {@link com.sonyericsson.jenkins.plugins.bfa.db.LocalFileKnowledgeBase} is used.
     *
     * @throws Exception if so.
     */
    public void testDoRemoveConfirm() throws Exception {
        FailureCause cause = new FailureCause("SomeName", "A Description");
        cause.addIndication(new BuildLogIndication("."));
        FailureCause cause1 = PluginImpl.getInstance().getKnowledgeBase().addCause(cause);
        cause = new FailureCause("SomeOtherName", "A Description");
        cause.addIndication(new BuildLogIndication("."));
        FailureCause cause2 = PluginImpl.getInstance().getKnowledgeBase().addCause(cause);

        KnowledgeBase kb = spy(PluginImpl.getInstance().getKnowledgeBase());
        Whitebox.setInternalState(PluginImpl.getInstance(), KnowledgeBase.class, kb);

        StaplerRequest request = mock(StaplerRequest.class);
        HttpSession session = mock(HttpSession.class);
        when(request.getSession(anyBoolean())).thenReturn(session);
        StaplerResponse response = mock(StaplerResponse.class);

        CauseManagement.getInstance().doRemoveConfirm(cause1.getId(), request, response);

        verify(kb).removeCause(eq(cause1.getId()));
        verify(session).setAttribute(eq(CauseManagement.SESSION_REMOVED_FAILURE_CAUSE), same(cause1));

        //Check that it is gone.
        assertNull(kb.getCause(cause1.getId()));

        //Check that the other one is still there
        assertSame(cause2, kb.getCause(cause2.getId()));
    }

    /**
     * Test Cause Management project action hiding.
     * @throws Exception if so.
     */
    public void testProjectCauseManagementActionIsHiddenWhenScanningDisabled() throws Exception {
        FreeStyleProject project = createFreeStyleProject();

        PluginImpl.getInstance().setGlobalEnabled(true);
        doScan(project, true);
        assertNotNull(project.getAction(TransientCauseManagement.class));

        doScan(project, false);
        assertNull(project.getAction(TransientCauseManagement.class));

        PluginImpl.getInstance().setGlobalEnabled(false);
        doScan(project, true);
        assertNull(project.getAction(TransientCauseManagement.class));

        doScan(project, false);
        assertNull(project.getAction(TransientCauseManagement.class));
    }

    /**
     * Turn project scanning on and off.
     *
     * @param project A project.
     * @param scan Scan or not.
     * @throws Exception if so.
     */
    private void doScan(FreeStyleProject project, boolean scan) throws Exception {
        project.removeProperty(ScannerJobProperty.class);
        project.addProperty(new ScannerJobProperty(!scan));
    }

}