ddf.metrics.reporting.internal.rest.MetricsEndpointTest.java Source code

Java tutorial

Introduction

Here is the source code for ddf.metrics.reporting.internal.rest.MetricsEndpointTest.java

Source

/**
 * Copyright (c) Codice Foundation
 * <p>
 * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or any later version.
 * <p>
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License
 * is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package ddf.metrics.reporting.internal.rest;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Calendar;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;

import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.codice.ddf.configuration.SystemBaseUrl;
import org.codice.ddf.configuration.SystemInfo;
import org.custommonkey.xmlunit.XMLTestCase;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.ContainerFactory;
import org.json.simple.parser.JSONParser;
import org.junit.Test;
import org.rrd4j.ConsolFun;
import org.rrd4j.DsType;
import org.rrd4j.core.FetchData;
import org.rrd4j.core.FetchRequest;
import org.rrd4j.core.RrdDb;
import org.rrd4j.core.RrdDbPool;
import org.rrd4j.core.RrdDef;
import org.rrd4j.core.Sample;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ddf.metrics.reporting.internal.MetricsEndpointException;
import ddf.metrics.reporting.internal.MetricsGraphException;
import ddf.metrics.reporting.internal.rrd4j.RrdMetricsRetriever;

public class MetricsEndpointTest extends XMLTestCase {
    private static final Logger LOGGER = LoggerFactory.getLogger(MetricsEndpointTest.class);

    private static final String TEST_DIR = "target/";

    private static final String ENDPOINT_ADDRESS = "http://localhost:8181/services/internal/metrics";

    private static final String MONTHS[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
            "Nov", "Dec" };

    private RrdDb rrdDb;

    private String rrdPath;

    @Test
    public void testParseDate() {
        long time = getEndpoint().parseDate("1998-07-09T09:00:00-07:00");
        assertThat(time, equalTo(900000000L));
    }

    @SuppressWarnings("rawtypes")
    @Test
    // @Ignore
    public void testGetMetricsList() throws Exception {
        // Delete all .rrd files in test directory to ensure starting with clean directory
        File testDir = new File(TEST_DIR);
        File[] fileList = testDir.listFiles();
        if (fileList != null) {
            for (File file : fileList) {
                if (file.isFile()) {
                    file.delete();
                }
            }
        }

        // Create RRD file that Metrics Endpoint will detect
        rrdPath = TEST_DIR + "uptime.rrd";
        RrdDef def = new RrdDef(rrdPath, 1);
        def.addDatasource("uptime", DsType.COUNTER, 90, 0, Double.NaN);
        def.addArchive(ConsolFun.TOTAL, 0.5, 1, 60);
        rrdDb = RrdDbPool.getInstance().requestRrdDb(def);

        UriInfo uriInfo = createUriInfo();

        // Get the metrics list from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);
        Response response = endpoint.getMetricsList(uriInfo);
        String metricsList = (String) response.getEntity();
        LOGGER.debug("metricsList = {}", metricsList);

        cleanupRrd();

        // Useful class for simple JSON to handle collections when parsing
        // (Called internally by the simple JSON parser.parse(...) method)
        ContainerFactory containerFactory = new ContainerFactory() {
            public List creatArrayContainer() {
                return new LinkedList();
            }

            public Map createObjectContainer() {
                return new LinkedHashMap();
            }
        };

        // Parse the returned JSON text
        JSONParser parser = new JSONParser();
        Map json = (Map) parser.parse(metricsList, containerFactory);
        Set<String> metricNames = (Set<String>) json.keySet();
        assertThat(metricNames.size(), equalTo(1));
        assertThat(metricNames, hasItem("uptime"));

        Iterator metricsIter = json.entrySet().iterator();

        // For each metric, a list of associated hyperlinks and their display
        // text is provided, e.g., "1h" and its associated hyperlink with the
        // corresponding dateOffset (in seconds) from current time
        // http://<host>:<port>/services/internal/metrics?dateOffset=3600
        while (metricsIter.hasNext()) {
            Map.Entry entry = (Map.Entry) metricsIter.next();
            Map metricTimeRangeLinks = (Map) entry.getValue();
            LOGGER.debug("metricTimeRangeLinks = {}", metricTimeRangeLinks);

            // Verify each metric name, e.g., "uptime", has all of the time ranges represented
            assertThat(metricTimeRangeLinks.containsKey("15m"), is(true));
            assertThat(metricTimeRangeLinks.containsKey("1h"), is(true));
            // assertThat(metricTimeRangeLinks.containsKey("4h"), is(true));
            // assertThat(metricTimeRangeLinks.containsKey("12h"), is(true));
            assertThat(metricTimeRangeLinks.containsKey("1d"), is(true));
            // assertThat(metricTimeRangeLinks.containsKey("3d"), is(true));
            assertThat(metricTimeRangeLinks.containsKey("1w"), is(true));
            assertThat(metricTimeRangeLinks.containsKey("1M"), is(true));
            assertThat(metricTimeRangeLinks.containsKey("3M"), is(true));
            assertThat(metricTimeRangeLinks.containsKey("6M"), is(true));
            assertThat(metricTimeRangeLinks.containsKey("1y"), is(true));

            Iterator timeRangeLinksIter = metricTimeRangeLinks.entrySet().iterator();

            // Verify for each time range that the associated hyperlinks are present for all
            // supported formats and that the correct dateOffset is specified in the hyperlinks
            while (timeRangeLinksIter.hasNext()) {
                Map.Entry timeRangeLinkEntry = (Map.Entry) timeRangeLinksIter.next();
                String timeRange = (String) timeRangeLinkEntry.getKey();
                Map<String, String> metricHyperlinks = (Map<String, String>) timeRangeLinkEntry.getValue();
                Long dateOffset = MetricsEndpoint.TIME_RANGES.get(timeRange);
                assertThat(metricHyperlinks.containsKey("PNG"), is(true));
                assertThat(metricHyperlinks.get("PNG"), endsWith("dateOffset=" + dateOffset));
                assertThat(metricHyperlinks.containsKey("CSV"), is(true));
                assertThat(metricHyperlinks.get("CSV"), endsWith("dateOffset=" + dateOffset));
                assertThat(metricHyperlinks.containsKey("XLS"), is(true));
                assertThat(metricHyperlinks.get("XLS"), endsWith("dateOffset=" + dateOffset));
            }
        }
    }

    @Test
    public void testGetMetricsGraphPositiveCase() throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        int dateOffset = 900; // 15 minutes in seconds
        createRrdFile(dateOffset);

        UriInfo uriInfo = createUriInfo();

        // Get the metrics graph from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);
        Response response = endpoint.getMetricsData("uptime", "png", "2013-03-25T06:00:00-07:00",
                "2013-03-25T07:10:00-07:00", null, "my label", "my title", uriInfo);

        cleanupRrd();

        assertThat(response.getEntity(), not(nullValue()));

        // NOTE: There are other branches in MetricsEndpoint that could/should be tested, e.g.,
        // when startDate specified and no endDate is specified (which is valid) - unfortunately,
        // RRD provides no methods to get info on the graph other than the byte[] it returns.
        // Hence, only could verify that a non null graph is returned. These tests seem not
        // to be worth writing at this time.
    }

    @Test
    public void testGetMetricsGraphPositiveCaseWithDefaults() throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        int dateOffset = 900; // 15 minutes in seconds
        createRrdFile(dateOffset);

        UriInfo uriInfo = createUriInfo();

        // Get the metrics graph from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);
        Response response = endpoint.getMetricsData("uptime", "png", null, null, null, null, null, uriInfo);

        cleanupRrd();

        assertThat(response.getEntity(), not(nullValue()));
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected = MetricsEndpointException.class)
    public void testGetMetricsGraphWithDateOffsetAndDates() throws Exception {
        UriInfo uriInfo = createUriInfo();

        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);
        try {
            endpoint.getMetricsData("uptime", "png", "2013-03-25T06:00:00-07:00", "2013-03-25T07:10:00-07:00",
                    "3600", "my label", "my title", uriInfo);
            fail();
        } catch (MetricsEndpointException e) {
        }
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected = MetricsEndpointException.class)
    public void testGetMetricsGraphWithIOException() throws Exception {
        UriInfo uriInfo = createUriInfo();

        RrdMetricsRetriever metricsRetriever = mock(RrdMetricsRetriever.class);
        when(metricsRetriever.createGraph(anyString(), anyString(), anyLong(), anyLong(), anyString(), anyString()))
                .thenThrow(IOException.class);

        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);
        endpoint.setMetricsRetriever(metricsRetriever);

        try {
            endpoint.getMetricsData("uptime", "png", "2013-03-25T06:00:00-07:00", "2013-03-25T07:10:00-07:00", null,
                    "my label", "my title", uriInfo);
            fail();
        } catch (MetricsEndpointException e) {
        }
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected = MetricsEndpointException.class)
    public void testGetMetricsGraphWithMetricsGraphException() throws Exception {
        UriInfo uriInfo = createUriInfo();

        RrdMetricsRetriever metricsRetriever = mock(RrdMetricsRetriever.class);
        when(metricsRetriever.createGraph(anyString(), anyString(), anyLong(), anyLong(), anyString(), anyString()))
                .thenThrow(MetricsGraphException.class);

        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);
        endpoint.setMetricsRetriever(metricsRetriever);

        try {
            endpoint.getMetricsData("uptime", "png", "2013-03-25T06:00:00-07:00", "2013-03-25T07:10:00-07:00", null,
                    "my label", "my title", uriInfo);
            fail();
        } catch (MetricsEndpointException e) {
        }
    }

    @Test
    public void testGetMetricsDataAsXml() throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        int dateOffset = 900; // 15 minutes in seconds
        createRrdFile(dateOffset);

        UriInfo uriInfo = createUriInfo();

        // Get the metrics data from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);

        Response response = endpoint.getMetricsData("uptime", "xml", null, null, Integer.toString(dateOffset),
                "my label", "my title", uriInfo);

        cleanupRrd();

        String xml = (String) response.getEntity();
        LOGGER.debug("xml = {}", xml);

        // Requires XmlUnit, but when this class extends XMLTestCase causes test case
        // testGetMetricsGraphWithDateOffsetAndDates to fail (exception is thrown but
        // unit test does not see it)
        assertXpathExists("/uptime", xml);
        assertXpathExists("/uptime/title", xml);
        assertXpathExists("/uptime/data", xml);
        assertXpathExists("/uptime/data/sample", xml);
        assertXpathExists("/uptime/data/sample/timestamp", xml);
        assertXpathExists("/uptime/data/sample/value", xml);
        assertXpathExists("/uptime/data/totalCount", xml);
    }

    @Test
    public void testGetMetricsDataAsCsv() throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        int dateOffset = 900; // 15 minutes in seconds
        createRrdFile(dateOffset);

        UriInfo uriInfo = createUriInfo();

        // Get the metrics data from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);

        Response response = endpoint.getMetricsData("uptime", "csv", null, null, Integer.toString(dateOffset),
                "my label", "my title", uriInfo);

        cleanupRrd();

        String csv = (String) response.getEntity();
        LOGGER.debug("csv = {}", csv);

        // Break up CSV data into its individual lines
        // Each line should have 2 parts (cells)
        // The first line should be the column headers
        String[] csvLines = csv.split("\n");

        // Verify that number of lines should be the column headers + (number of samples - 1)
        // Since 3 samples were taken, but only 2 are added to the RRD file due to averaging,
        // expect 2 lines of data and the one line of column headers.
        assertThat(csvLines.length, equalTo(3));
        assertThat(csvLines[0], equalTo("Timestamp,Value")); // column headers
        String[] cells = csvLines[1].split(",");
        assertThat(cells.length, equalTo(2)); // each line of data has the 2 values
    }

    @Test
    public void testGetMetricsDataAsXls() throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        int dateOffset = 900; // 15 minutes in seconds
        createRrdFile(dateOffset);

        UriInfo uriInfo = createUriInfo();

        // Get the metrics data from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);

        Response response = endpoint.getMetricsData("uptime", "xls", null, null, Integer.toString(dateOffset),
                "my label", "my title", uriInfo);

        cleanupRrd();

        InputStream xls = (InputStream) response.getEntity();
        assertThat(xls, not(nullValue()));

        HSSFWorkbook wb = new HSSFWorkbook(xls);
        assertThat(wb.getNumberOfSheets(), equalTo(1));
        HSSFSheet sheet = wb.getSheet("Uptime");
        assertThat(sheet, not(nullValue()));

        // Expect 7 rows: title + blank + column headers + 2 rows of samples + blank +
        // totalQueryCount
        assertThat(sheet.getPhysicalNumberOfRows(), equalTo(7));

        // first row should have title in first cell
        HSSFRow row = sheet.getRow(0);
        assertThat(row, not(nullValue()));
        assertThat(row.getCell(0).getStringCellValue(), startsWith("Uptime for"));

        // third row should have column headers in first and second cells
        row = sheet.getRow(2);
        assertThat(row.getCell(0).getStringCellValue(), equalTo("Timestamp"));
        assertThat(row.getCell(1).getStringCellValue(), equalTo("Value"));

        // should have 2 rows of samples' data
        row = sheet.getRow(3);
        assertThat(row.getCell(0).getStringCellValue(), not(nullValue()));
        assertThat(row.getCell(1).getNumericCellValue(), not(nullValue()));
        row = sheet.getRow(4);
        assertThat(row.getCell(0).getStringCellValue(), not(nullValue()));
        assertThat(row.getCell(1).getNumericCellValue(), not(nullValue()));

        // last row should have totalQueryCount in first cell
        row = sheet.getRow(sheet.getLastRowNum());
        assertThat(row.getCell(0).getStringCellValue(), startsWith("Total Count:"));
        assertThat(row.getCell(1).getNumericCellValue(), not(nullValue()));
    }

    @Test
    public void testGetMetricsDataAsPpt() throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        int dateOffset = 900; // 15 minutes in seconds
        createRrdFile(dateOffset);

        UriInfo uriInfo = createUriInfo();

        // Get the metrics data from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);

        Response response = endpoint.getMetricsData("uptime", "ppt", null, null, Integer.toString(dateOffset),
                "my label", "my title", uriInfo);

        cleanupRrd();

        InputStream is = (InputStream) response.getEntity();
        assertThat(is, not(nullValue()));

        SlideShow ppt = new SlideShow(is);
        Slide[] slides = ppt.getSlides();
        assertThat(slides.length, equalTo(1));
    }

    @Test
    public void testGetMetricsDataAsJson() throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        int dateOffset = 900; // 15 minutes in seconds
        createRrdFile(dateOffset);

        UriInfo uriInfo = createUriInfo();

        // Get the metrics data from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);

        Response response = endpoint.getMetricsData("uptime", "json", null, null, Integer.toString(dateOffset),
                "my label", "my title", uriInfo);

        cleanupRrd();

        String json = (String) response.getEntity();
        LOGGER.debug("json = {}", json);

        JSONParser parser = new JSONParser();
        JSONObject jsonObj = (JSONObject) parser.parse(json);

        // Verify the title, totalCount, and data (i.e., samples) are present
        assertThat(jsonObj.size(), equalTo(3));
        assertThat(jsonObj.get("title"), not(nullValue()));
        assertThat(jsonObj.get("totalCount"), not(nullValue()));

        // Verify 2 samples were retrieved from the RRD file and put in the JSON fetch results
        JSONArray samples = (JSONArray) jsonObj.get("data");
        assertThat(samples.size(), equalTo(2));

        // Verify each retrieved sample has a timestamp and value
        for (int i = 0; i < samples.size(); i++) {
            JSONObject sample = (JSONObject) samples.get(i);
            LOGGER.debug("timestamp = {},   value = {}", (String) sample.get("timestamp"), sample.get("value"));
            assertThat(sample.get("timestamp"), not(nullValue()));
            assertThat(sample.get("value"), not(nullValue()));
        }
    }

    @Test
    public void testGetMetricsReportAsXls() throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        int dateOffset = 900; // 15 minutes in seconds
        createRrdFile(dateOffset, "uptime");

        UriInfo uriInfo = createUriInfo();

        // Get the metrics data from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);

        Response response = endpoint.getMetricsReport("xls", null, null, Integer.toString(dateOffset), "minute",
                uriInfo);

        cleanupRrd();

        MultivaluedMap<String, Object> headers = response.getHeaders();
        assertTrue(headers.getFirst("Content-Disposition").toString().contains("attachment; filename="));

        InputStream is = (InputStream) response.getEntity();
        assertThat(is, not(nullValue()));

        HSSFWorkbook wb = new HSSFWorkbook(is);
        assertThat(wb.getNumberOfSheets(), equalTo(1));
        HSSFSheet sheet = wb.getSheetAt(0);
        assertThat(sheet, not(nullValue()));
    }

    @Test
    public void testGetMetricsReportAsPpt() throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        int dateOffset = 900; // 15 minutes in seconds
        createRrdFile(dateOffset, "uptime");

        UriInfo uriInfo = createUriInfo();

        // Get the metrics data from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);

        Response response = endpoint.getMetricsReport("ppt", null, null, Integer.toString(dateOffset), null,
                uriInfo);

        cleanupRrd();

        MultivaluedMap<String, Object> headers = response.getHeaders();
        assertTrue(headers.getFirst("Content-Disposition").toString().contains("attachment; filename="));

        InputStream is = (InputStream) response.getEntity();
        assertThat(is, not(nullValue()));

        SlideShow ppt = new SlideShow(is);
        Slide[] slides = ppt.getSlides();
        assertThat(slides.length, equalTo(1));
    }

    @Test
    public void testSummaryFormat() throws URISyntaxException {
        boolean pass = false;
        try {
            MetricsEndpoint endpoint = getEndpoint();
            endpoint.setMetricsDir(TEST_DIR);

            Response response = endpoint.getMetricsReport("ppt", null, null, "3600", "minute", createUriInfo());
        } catch (MetricsEndpointException e) {
            pass = true;
        }
        assertThat("Format not rejected", pass, is(true));
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected=MetricsEndpointException.class)
    public void testGetMetricsDataAsJsonWithIOException() throws Exception {
        verifyException("json", IOException.class);
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected=MetricsEndpointException.class)
    public void testGetMetricsDataAsJsonWithMetricsGraphException() throws Exception {
        verifyException("json", MetricsGraphException.class);
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected=MetricsEndpointException.class)
    public void testGetMetricsDataAsCsvWithIOException() throws Exception {
        verifyException("csv", IOException.class);
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected=MetricsEndpointException.class)
    public void testGetMetricsDataAsCsvWithMetricsGraphException() throws Exception {
        verifyException("csv", MetricsGraphException.class);
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected=MetricsEndpointException.class)
    public void testGetMetricsDataAsXmlWithIOException() throws Exception {
        verifyException("xml", IOException.class);
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected=MetricsEndpointException.class)
    public void testGetMetricsDataAsXmlWithMetricsGraphException() throws Exception {
        verifyException("xml", MetricsGraphException.class);
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected=MetricsEndpointException.class)
    public void testGetMetricsDataAsXlsWithIOException() throws Exception {
        verifyException("xls", IOException.class);
    }

    // NOTE: "expected" annotation does not work when test case extends XMLTestCase,
    // hence the usage of the try/catch/fail approach for the expected exception
    @Test
    // (expected=MetricsEndpointException.class)
    public void testGetMetricsDataAsXlsWithMetricsGraphException() throws Exception {
        verifyException("xls", MetricsGraphException.class);
    }

    /*******************************************************************************/

    private void createRrdFile(int dateOffset) throws Exception {
        createRrdFile(dateOffset, "uptime");
    }

    private void createRrdFile(int dateOffset, String metricName) throws Exception {
        // Create RRD file that Metrics Endpoint will detect
        rrdPath = TEST_DIR + metricName + ".rrd";
        int rrdStep = 60;
        RrdDef def = new RrdDef(rrdPath, rrdStep);
        long startTime = System.currentTimeMillis() / 1000 - dateOffset;
        def.setStartTime(startTime - rrdStep);
        def.addDatasource("data", DsType.COUNTER, 90, 0, Double.NaN);
        def.addArchive(ConsolFun.TOTAL, 0.5, 1, 5);
        rrdDb = RrdDbPool.getInstance().requestRrdDb(def);

        // Add enough samples to get one averaged sample stored into the RRD file
        long endTime = startTime;
        Sample sample = rrdDb.createSample();
        sample.setTime(endTime);
        sample.setValue("data", 100);
        sample.update();
        endTime += rrdStep;
        sample.setTime(endTime);
        sample.setValue("data", 200);
        sample.update();
        endTime += rrdStep;
        sample.setTime(endTime);
        sample.setValue("data", 100);
        sample.update();
        endTime += rrdStep;

        LOGGER.debug(rrdDb.dump());

        FetchRequest fetchRequest = rrdDb.createFetchRequest(ConsolFun.TOTAL, startTime, endTime);
        FetchData fetchData = fetchRequest.fetchData();

        LOGGER.debug(fetchData.dump());
        long[] timestamps = fetchData.getTimestamps();
        double[] values = fetchData.getValues(0);
        for (int i = 0; i < timestamps.length; i++) {
            LOGGER.debug("{}:  {}", getCalendarTime(timestamps[i]), values[i]);
        }

        rrdDb.close();
    }

    protected UriInfo createUriInfo() throws URISyntaxException {
        UriInfo info = mock(UriInfo.class);
        when(info.getBaseUri()).thenReturn(new URI(ENDPOINT_ADDRESS));
        when(info.getRequestUri()).thenReturn(new URI(ENDPOINT_ADDRESS));
        when(info.getAbsolutePath()).thenReturn(new URI(ENDPOINT_ADDRESS));

        UriBuilder builder = mock(UriBuilder.class);

        when(info.getAbsolutePathBuilder()).thenReturn(builder);

        when(builder.path("/uptime.png")).thenReturn(builder);

        when(builder.build()).thenReturn(new URI(ENDPOINT_ADDRESS + "/uptime.png"));

        return info;
    }

    private void verifyException(String format, Class exceptionClass) throws Exception {
        UriInfo uriInfo = createUriInfo();

        RrdMetricsRetriever metricsRetriever = mock(RrdMetricsRetriever.class);
        when(metricsRetriever.createJsonData(anyString(), anyString(), anyLong(), anyLong()))
                .thenThrow(exceptionClass);
        when(metricsRetriever.createCsvData(anyString(), anyLong(), anyLong())).thenThrow(exceptionClass);
        when(metricsRetriever.createXlsData(anyString(), anyString(), anyLong(), anyLong()))
                .thenThrow(exceptionClass);
        when(metricsRetriever.createXmlData(anyString(), anyString(), anyLong(), anyLong()))
                .thenThrow(exceptionClass);

        // Get the metrics data from the endpoint
        MetricsEndpoint endpoint = getEndpoint();
        endpoint.setMetricsDir(TEST_DIR);
        endpoint.setMetricsRetriever(metricsRetriever);

        try {
            Response response = endpoint.getMetricsData("uptime", format, null, null, "900", "my label", "my title",
                    uriInfo);
            fail();
        } catch (MetricsEndpointException e) {
        }
    }

    private void cleanupRrd() throws IOException {
        if (!rrdDb.isClosed()) {
            rrdDb.close();
        }
        RrdDbPool.getInstance().release(rrdDb);

        File rrdFile = new File(rrdPath);
        if (rrdFile.exists()) {
            boolean status = rrdFile.delete();
            if (status) {
                LOGGER.debug("Successfully deleted rrdFile {}", rrdPath);
            } else {
                LOGGER.debug("Unable to delete rrdFile {}", rrdPath);
            }
        } else {
            LOGGER.debug("rrdFile {} does not exist - cannot delete", rrdPath);
        }
    }

    private String getCalendarTime(long timestamp) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(timestamp * 1000);

        String calTime = MONTHS[calendar.get(Calendar.MONTH)] + " " + calendar.get(Calendar.DATE) + " "
                + calendar.get(Calendar.YEAR) + " ";

        calTime += addLeadingZero(calendar.get(Calendar.HOUR_OF_DAY)) + ":";
        calTime += addLeadingZero(calendar.get(Calendar.MINUTE)) + ":";
        calTime += addLeadingZero(calendar.get(Calendar.SECOND));

        return calTime;
    }

    private String addLeadingZero(int value) {
        if (value < 10) {
            return "0" + String.valueOf(value);
        }

        return String.valueOf(value);
    }

    private MetricsEndpoint getEndpoint() {
        MetricsEndpoint me = new MetricsEndpoint();
        System.setProperty(SystemBaseUrl.ROOT_CONTEXT, "/services");
        System.setProperty(SystemInfo.SITE_NAME, "siteName");
        return me;
    }
}