com.bc.fiduceo.post.PostProcessingToolTest.java Source code

Java tutorial

Introduction

Here is the source code for com.bc.fiduceo.post.PostProcessingToolTest.java

Source

/*
 * Copyright (C) 2016 Brockmann Consult GmbH
 * This code was developed for the EC project "Fidelity and Uncertainty in
 * Climate Data Records from Earth Observations (FIDUCEO)".
 * Grant Agreement: 638822
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 3 of the License, or (at your option)
 * any later version.
 * 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 General Public License for
 * more details.
 *
 * A copy of the GNU General Public License should have been supplied along
 * with this program; if not, see http://www.gnu.org/licenses/
 */

package com.bc.fiduceo.post;

import static org.hamcrest.Matchers.equalToIgnoringWhiteSpace;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import com.bc.fiduceo.log.FiduceoLogger;
import com.bc.fiduceo.post.plugin.DummyPostProcessingPlugin;
import com.bc.fiduceo.util.TimeUtils;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.hamcrest.CoreMatchers;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.junit.*;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import ucar.nc2.Attribute;
import ucar.nc2.Group;
import ucar.nc2.NetcdfFile;
import ucar.nc2.NetcdfFileWriter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Formatter;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.StreamHandler;

public class PostProcessingToolTest {

    private static final String CONFIG = PostProcessingConfig.TAG_NAME_ROOT;
    private static final String PROCESSINGS = PostProcessingConfig.TAG_NAME_POST_PROCESSINGS;
    private static final String NEW_FILES = PostProcessingConfig.TAG_NAME_NEW_FILES;
    private static final String OUTPUT_DIR = PostProcessingConfig.TAG_NAME_OUTPUT_DIR;

    private static final String DUMMY_NAME = DummyPostProcessingPlugin.DUMMY_POST_PROCESSING_NAME;
    private Element root;

    @Before
    public void setUp() throws Exception {
        root = new Element(CONFIG).addContent(Arrays.asList(
                new Element(NEW_FILES).addContent(new Element(OUTPUT_DIR).addContent("An_Output_Directory")),
                new Element(PROCESSINGS).addContent(new Element(DUMMY_NAME).addContent("C"))));
    }

    @Test
    public void testOptions() {
        final Options options = PostProcessingTool.getOptions();
        assertEquals(6, options.getOptions().size());

        Option o;

        o = options.getOption("c");
        assertNotNull(o);
        assertEquals("config", o.getLongOpt());
        assertEquals("Defines the configuration directory. Defaults to './config'.", o.getDescription());
        assertEquals(true, o.hasArg());
        assertEquals(false, o.isRequired());

        o = options.getOption("i");
        assertNotNull(o);
        assertEquals("input-dir", o.getLongOpt());
        assertEquals("Defines the path to the input mmd files directory.", o.getDescription());
        assertEquals(true, o.hasArg());
        assertEquals(true, o.isRequired());

        o = options.getOption("end");
        assertNotNull(o);
        assertEquals("end-date", o.getLongOpt());
        assertEquals("Defines the processing end-date, format 'yyyy-DDD'. DDD = Day of year.", o.getDescription());
        assertEquals(true, o.hasArg());
        assertEquals(true, o.isRequired());

        o = options.getOption("h");
        assertNotNull(o);
        assertEquals("help", o.getLongOpt());
        assertEquals("Prints the tool usage.", o.getDescription());
        assertEquals(false, o.hasArg());
        assertEquals(false, o.isRequired());

        o = options.getOption("j");
        assertNotNull(o);
        assertEquals("job-config", o.getLongOpt());
        assertEquals(
                "Defines the path to post processing job configuration file. Path is relative to the configuration directory.",
                o.getDescription());
        assertEquals(true, o.hasArg());
        assertEquals(true, o.isRequired());

        o = options.getOption("start");
        assertNotNull(o);
        assertEquals("start-date", o.getLongOpt());
        assertEquals("Defines the processing start-date, format 'yyyy-DDD'. DDD = Day of year.",
                o.getDescription());
        assertEquals(true, o.hasArg());
        assertEquals(true, o.isRequired());
    }

    @Test
    public void testPrintUsage() throws Exception {
        final ByteArrayOutputStream out = new ByteArrayOutputStream();

        PostProcessingTool.printUsageTo(out);
        //        PostProcessingTool.printUsageTo(System.out);

        final String ls = System.lineSeparator();
        final String expected = "post-processing-tool version 1.2.1-SNAPSHOT" + ls + "" + ls
                + "usage: post-processing-tool <options>" + ls + "Valid options are:" + ls
                + "   -c,--config <arg>           Defines the configuration directory. Defaults to './config'." + ls
                + "   -end,--end-date <arg>       Defines the processing end-date, format 'yyyy-DDD'. DDD = Day of year."
                + ls + "   -h,--help                   Prints the tool usage." + ls
                + "   -i,--input-dir <arg>        Defines the path to the input mmd files directory." + ls
                + "   -j,--job-config <arg>       Defines the path to post processing job configuration file. Path is relative to the"
                + ls + "                               configuration directory." + ls
                + "   -start,--start-date <arg>   Defines the processing start-date, format 'yyyy-DDD'. DDD = Day of year.";
        assertEquals(expected, out.toString().trim());
    }

    @Test
    public void testRun() throws Exception {
        final Group rootGroup = mock(Group.class);
        when(rootGroup.getShortName()).thenReturn("root");

        final NetcdfFile reader = mock(NetcdfFile.class);
        when(reader.getRootGroup()).thenReturn(rootGroup);

        final NetcdfFileWriter writer = mock(NetcdfFileWriter.class);
        final PostProcessing p1 = mock(PostProcessing.class);
        final PostProcessing p2 = mock(PostProcessing.class);

        final PostProcessingContext context = new PostProcessingContext();
        context.setProcessingConfig(getConfig());
        final PostProcessingTool tool = new PostProcessingTool(context);

        tool.run(reader, writer, Arrays.asList(p1, p2));

        final InOrder inOrder = inOrder(reader, writer, p1, p2);
        inOrder.verify(writer, times(1)).addGroup(null, "root");
        inOrder.verify(p1, times(1)).prepare(reader, writer);
        inOrder.verify(p2, times(1)).prepare(reader, writer);
        inOrder.verify(writer, times(1)).create();
        inOrder.verify(p1, times(1)).compute(same(reader), same(writer));
        inOrder.verify(p2, times(1)).compute(same(reader), same(writer));
    }

    @Test
    public void addPostProcessingConfig_newAttribute() throws Exception {
        final String attName = "post-processing-configuration";

        final NetcdfFileWriter writer = mock(NetcdfFileWriter.class);
        when(writer.findGlobalAttribute(attName)).thenReturn(null);

        final PostProcessingContext context = new PostProcessingContext();
        context.setProcessingConfig(getConfig());
        final PostProcessingTool tool = new PostProcessingTool(context);

        tool.addPostProcessingConfig(writer);

        final String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + "<post-processing-config>"
                + "  <create-new-files>" + "    <output-directory>An_Output_Directory</output-directory>"
                + "  </create-new-files>" + "  <post-processings>"
                + "    <dummy-post-processing>C</dummy-post-processing>" + "  </post-processings> "
                + "</post-processing-config>";

        final ArgumentCaptor<Attribute> attribCaptor = ArgumentCaptor.forClass(Attribute.class);
        verify(writer, times(1)).findGlobalAttribute(attName);
        verify(writer, times(1)).addGroupAttribute(isNull(Group.class), attribCaptor.capture());
        assertThat(attribCaptor.getValue().getStringValue(), equalToIgnoringWhiteSpace(expected));
        verifyNoMoreInteractions(writer);
    }

    @Test
    public void addPostProcessingConfig_existingAttribute() throws Exception {
        final String attName = "post-processing-configuration";
        final String prevoiusContent = "previous content";

        final NetcdfFileWriter writer = mock(NetcdfFileWriter.class);
        when(writer.findGlobalAttribute(attName)).thenReturn(new Attribute(attName, prevoiusContent));

        final PostProcessingContext context = new PostProcessingContext();
        context.setProcessingConfig(getConfig());
        final PostProcessingTool tool = new PostProcessingTool(context);

        tool.addPostProcessingConfig(writer);

        final String expected = prevoiusContent + " " + "<?xml version=\"1.0\" encoding=\"UTF-8\"?> "
                + "<post-processing-config>" + "  <create-new-files>"
                + "    <output-directory>An_Output_Directory</output-directory>" + "  </create-new-files>"
                + "  <post-processings>" + "    <dummy-post-processing>C</dummy-post-processing>"
                + "  </post-processings> " + "</post-processing-config>";

        final ArgumentCaptor<Attribute> attribCaptor = ArgumentCaptor.forClass(Attribute.class);
        verify(writer, times(1)).findGlobalAttribute(attName);
        verify(writer, times(1)).addGroupAttribute(isNull(Group.class), attribCaptor.capture());
        verify(writer, times(1)).deleteGroupAttribute(null, attName);
        assertThat(attribCaptor.getValue().getStringValue(), equalToIgnoringWhiteSpace(expected));
        verifyNoMoreInteractions(writer);
    }

    @Test
    public void testFilenameIsInTimeRange() throws Exception {
        final String fileStart = "2005-123";
        final String filename = "AnyCahractersBefore_" + fileStart + "_" + "anyTime" + ".nc";

        final long startTime = TimeUtils.parseDOYBeginOfDay(fileStart).getTime();
        final long endTime = startTime;

        assertTrue(PostProcessingTool.isFileInTimeRange(startTime, endTime, filename));
        assertFalse(PostProcessingTool.isFileInTimeRange(startTime + 1, endTime + 1, filename));
        assertFalse(PostProcessingTool.isFileInTimeRange(startTime - 1, endTime - 1, filename));
    }

    @Test
    public void testGetDate() throws Exception {
        final CommandLine commandLine = mock(CommandLine.class);
        when(commandLine.getOptionValue("start")).thenReturn("TheDateString");

        final String start = PostProcessingTool.getDate(commandLine, "start");

        assertEquals("TheDateString", start);
    }

    @Test
    public void testGetDate_emptyString() throws Exception {
        final CommandLine commandLine = mock(CommandLine.class);
        when(commandLine.getOptionValue("start")).thenReturn("");

        try {
            PostProcessingTool.getDate(commandLine, "start");
            fail("RuntimeException expected");
        } catch (RuntimeException expected) {
            assertEquals("Value of cmd-line parameter 'start' is missing.", expected.getMessage());
        }
    }

    @Test
    public void testGetDate_null() throws Exception {
        final CommandLine commandLine = mock(CommandLine.class);
        when(commandLine.getOptionValue("start")).thenReturn(null);

        try {
            PostProcessingTool.getDate(commandLine, "start");
            fail("RuntimeException expected");
        } catch (RuntimeException expected) {
            assertEquals("Value of cmd-line parameter 'start' is missing.", expected.getMessage());
        }
    }

    @Test
    public void testThatPostProcessingToolInCaseOfExceptionsPrintsTheErrorMessageAndContinueWithTheNextFile()
            throws Exception {
        final ArrayList<Path> mmdFiles = new ArrayList<>();
        mmdFiles.add(Paths.get("nonExistingFileOne"));
        mmdFiles.add(Paths.get("nonExistingFileTwo"));
        mmdFiles.add(Paths.get("nonExistingFileThree"));

        final Formatter formatter = new SimpleFormatter();
        final ByteArrayOutputStream stream = new ByteArrayOutputStream();
        final StreamHandler handler = new StreamHandler(stream, formatter);
        final Logger logger = FiduceoLogger.getLogger();
        FiduceoLogger.setLevelSilent();

        try {
            logger.addHandler(handler);

            final PostProcessingContext context = new PostProcessingContext();
            final PostProcessingConfig processingConfig = getConfig();
            context.setProcessingConfig(processingConfig);

            final PostProcessingTool postProcessingTool = new PostProcessingTool(context);

            postProcessingTool.computeFiles(mmdFiles);

            handler.close();
            final String string = stream.toString();
            assertThat(string, CoreMatchers.containsString("nonExistingFileOne"));
            assertThat(string, CoreMatchers.containsString("nonExistingFileTwo"));
            assertThat(string, CoreMatchers.containsString("nonExistingFileThree"));
        } finally {
            logger.removeHandler(handler);
        }
    }

    private PostProcessingConfig getConfig() throws Exception {
        final Document document = new Document(root);

        final ByteArrayOutputStream bs = new ByteArrayOutputStream();
        new XMLOutputter(Format.getPrettyFormat()).output(document, bs);
        bs.close();

        return PostProcessingConfig.load(new ByteArrayInputStream(bs.toByteArray()));
    }
}