PevfExchangesTest.java

/*
 * Copyright (c) 2020, RTE (http://www.rte-france.com)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package com.powsybl.entsoe.cgmes.balances_adjustment.data_exchange;

import com.powsybl.commons.PowsyblException;
import com.powsybl.timeseries.DoubleTimeSeries;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.io.InputStream;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;

/**
 * Pan European Verification Function.
 * Check XML parsing.
 *
 * @author Thomas Adam {@literal <tadam at silicom.fr>}
 */
class PevfExchangesTest {

    private DataExchanges exchanges;

    @BeforeEach
    void setUp() {
        exchanges = DataExchangesXml.parse(getClass().getResourceAsStream("/testPEVFMarketDocument_2-0.xml"));
    }

    @Test
    void baseTests() {
        // Getters
        assertEquals("MarketDocument_MRID", exchanges.getMRId());
        assertEquals(1, exchanges.getRevisionNumber());
        assertEquals(StandardMessageType.B19, exchanges.getType());
        assertEquals(StandardProcessType.A01, exchanges.getProcessType());
        assertEquals("SenderMarket", exchanges.getSenderId());
        assertEquals(StandardCodingSchemeType.A01, exchanges.getSenderCodingScheme());
        assertEquals(StandardRoleType.A32, exchanges.getSenderMarketRole());
        assertEquals("ReceiverMarket", exchanges.getReceiverId());
        assertEquals(StandardCodingSchemeType.A01, exchanges.getReceiverCodingScheme());
        assertEquals(StandardRoleType.A33, exchanges.getReceiverMarketRole());
        assertEquals(ZonedDateTime.parse("2020-04-05T14:30:00Z"), exchanges.getCreationDate());
        assertEquals(ZonedDateTime.parse("2020-04-05T22:00Z").toInstant(), exchanges.getPeriod().getStart());
        assertEquals(ZonedDateTime.parse("2020-04-06T22:00Z").toInstant(), exchanges.getPeriod().getEnd());
        // Optional
        assertEquals(Optional.of("PEVF CGM Export"), exchanges.getDatasetMarketDocumentMRId());
        assertEquals(Optional.of(StandardStatusType.A01), exchanges.getDocStatus());
        assertFalse(exchanges.getDomainId().isPresent());
        assertFalse(exchanges.getDomainCodingScheme().isPresent());
    }

    @ParameterizedTest
    @ValueSource(strings = {"/testPEVFMarketDocument_2-0_error_doc_status.xml",
        "/testPEVFMarketDocument_2-0_error_marketdocument.xml",
        "/testPEVFMarketDocument_2-0_error_timeseries.xml",
        "/testPEVFMarketDocument_2-0_error_period.xml",
        "/testPEVFMarketDocument_2-0_error_timeinterval.xml"})
    void testErrorInXML(String path) {
        InputStream inputStream = getClass().getResourceAsStream(path);
        assertThrows(RuntimeException.class, () -> DataExchangesXml.parse(inputStream));
    }

    @Test
    void timeSeriesTests() {
        // Time Series
        DoubleTimeSeries timeSeries1 = exchanges.getTimeSeries("TimeSeries1");
        // TimeSeries1 : Check metadata
        assertEquals("TimeSeries1", timeSeries1.getMetadata().getName());
        assertEquals("B63", timeSeries1.getMetadata().getTags().get("businessType"));
        assertEquals("8716867000016", timeSeries1.getMetadata().getTags().get("product"));
        assertEquals("Sender1", timeSeries1.getMetadata().getTags().get("in_Domain.mRID"));
        assertEquals("A01", timeSeries1.getMetadata().getTags().get("in_Domain.mRID.codingScheme"));
        assertEquals("Receiver1", timeSeries1.getMetadata().getTags().get("out_Domain.mRID"));
        assertEquals("A01", timeSeries1.getMetadata().getTags().get("out_Domain.mRID.codingScheme"));
        assertEquals("Sender1_Receiver1", timeSeries1.getMetadata().getTags().get("connectingLine_RegisteredResource.mRID"));
        assertEquals("MAW", timeSeries1.getMetadata().getTags().get("measurement_Unit.name"));
        assertEquals("A03", timeSeries1.getMetadata().getTags().get("curveType"));
        // TimeSeries1 : values
        // Single step, single value
        assertArrayEquals(new double[]{0.000d, Double.NaN}, timeSeries1.toArray(), 0.0d);

        // TimeSeries2
        // Multi steps, single value
        DoubleTimeSeries timeSeries2 = exchanges.getTimeSeries("TimeSeries2");
        assertArrayEquals(new double[]{0.020d, 0.020d, Double.NaN}, timeSeries2.toArray(), 0.0d);

        // TimeSeries3
        // Each value defined
        DoubleTimeSeries timeSeries3 = exchanges.getTimeSeries("TimeSeries3");
        assertArrayEquals(new double[]{0.000d, 0.250d, 0.500d, 0.750d, Double.NaN}, timeSeries3.toArray(), 0.0d);

        // TimeSeries4
        // Each value not defined
        DoubleTimeSeries timeSeries4 = exchanges.getTimeSeries("TimeSeries4");
        double[] timeSeries4ExpectedValues = new double[]{3939.124, 3939.124, 3939.124, 3939.124, 3939.124, 3939.124, 3926.042, 3926.042, 3926.042, 3926.042, 3926.042, 3924.460, 3924.460, 3924.460, 3924.460, Double.NaN};
        assertArrayEquals(timeSeries4ExpectedValues, timeSeries4.toArray(), 0.0d);
    }

    @Test
    void utilitiesTests() {
        assertEquals(5, exchanges.getTimeSeries().size());

        assertEquals("TimeSeries1", exchanges.getTimeSeries("TimeSeries1").getMetadata().getName());

        Map<String, Double> timeSeriesById = exchanges.getValuesAt(Instant.parse("2020-04-05T22:14:12.000Z"));
        assertEquals(5, timeSeriesById.keySet().size());
        Iterator<Double> it = timeSeriesById.values().iterator();
        assertTrue(it.hasNext());
        assertEquals(0.02d, it.next(), 0.0d);

        assertEquals(3924.46d, exchanges.getValueAt("TimeSeries4", Instant.parse("2020-04-05T22:14:00.000Z")), 0.0d);
        assertEquals(3924.46d, exchanges.getValueAt("TimeSeries4", Instant.parse("2020-04-05T22:14:59.000Z")), 0.0d);

        assertEquals(35, exchanges.getValueAt("TimeSeries5", Instant.parse("2020-04-05T22:00:00.000Z")), 0.0);
        assertEquals(35, exchanges.getValueAt("TimeSeries5", Instant.parse("2020-04-05T23:00:00.000Z")), 0.0);
        assertEquals(15, exchanges.getValueAt("TimeSeries5", Instant.parse("2020-04-06T01:00:00.000Z")), 0.0);
        assertEquals(15, exchanges.getValueAt("TimeSeries5", Instant.parse("2020-04-06T01:30:00.000Z")), 0.0);

        timeSeriesById = exchanges.getValueAt(new String[]{"TimeSeries1", "TimeSeries5"}, Instant.parse("2020-04-05T22:00:00.000Z"));
        assertEquals(2, timeSeriesById.keySet().size());
        assertEquals(0.0d, timeSeriesById.get("TimeSeries1"), 0.0d);
        assertEquals(35.0d, timeSeriesById.get("TimeSeries5"), 0.0d);
    }

    @Test
    void searchTimeSeriesByDomainIdTest() {
        assertEquals(0, exchanges.getTimeSeries("Sender1", "Invalid").size());
        assertEquals(0, exchanges.getTimeSeries("Invalid", "Receiver1").size());
        assertEquals(1, exchanges.getTimeSeries("Sender1", "Receiver1").size());
        assertThrows(NullPointerException.class, () -> exchanges.getTimeSeries(null, "Receiver1"));
        assertThrows(NullPointerException.class, () -> exchanges.getTimeSeries("Sender1", null));

        assertTrue(exchanges.getValuesAt("Sender1", "Invalid", Instant.parse("2020-04-05T22:00:00.000Z")).isEmpty());
        Map<String, Double> values = exchanges.getValuesAt("Sender1", "Receiver1", Instant.parse("2020-04-05T22:00:00.000Z"));
        assertEquals(1, values.size());
        assertTrue(values.containsKey("TimeSeries1"));
        assertEquals(0.0, values.get("TimeSeries1"), 0.0);

        assertEquals(0.0, exchanges.getNetPosition("Sender1", "Receiver1", Instant.parse("2020-04-05T22:00:00.000Z")), 0.0);
        assertEquals(0.0, exchanges.getNetPosition("Sender1", "Receiver1", Instant.parse("2020-04-05T23:00:00.000Z"), false), 0.0);

        assertEquals(0.0, exchanges.getNetPositionsWithInDomainId("Sender1", Instant.parse("2020-04-05T22:00:00.000Z")).get("Receiver1"), 0.0);
        assertEquals(0.0, exchanges.getNetPositionsWithInDomainId("Sender1", Instant.parse("2020-04-05T23:00:00.000Z"), false).get("Receiver1"), 0.0);

        assertEquals(0.0, exchanges.getNetPositionsWithInDomainId("Receiver1", Instant.parse("2020-04-05T22:00:00.000Z")).get("Sender1"), 0.0);
        assertEquals(0.0, exchanges.getNetPositionsWithInDomainId("Receiver1", Instant.parse("2020-04-05T23:00:00.000Z"), false).get("Sender1"), 0.0);
    }

    @Test
    void timeSeriesNotFoundTest() {
        PowsyblException e = assertThrows(PowsyblException.class, () -> exchanges.getTimeSeries("Unknown"));
        assertTrue(e.getMessage().contains("TimeSeries 'Unknown' not found"));
    }

    @Test
    void timeSeriesEndTest() {
        Instant instant = Instant.parse("2019-06-18T22:00:00.000Z");
        PowsyblException e = assertThrows(PowsyblException.class, () -> exchanges.getValueAt("TimeSeries5", instant));
        assertTrue(e.getMessage().contains("TimeSeries5 '2019-06-18T22:00:00Z' is out of bound [2020-04-05T22:00:00Z, 2020-04-06T22:00:00Z["));
    }

    @Test
    void timeSeriesAfterEndTest() {
        Instant instant = Instant.parse("2019-06-19T00:00:00.000Z");
        PowsyblException e = assertThrows(PowsyblException.class, () -> exchanges.getValueAt("TimeSeries5", instant));
        assertTrue(e.getMessage().contains("TimeSeries5 '2019-06-19T00:00:00Z' is out of bound [2020-04-05T22:00:00Z, 2020-04-06T22:00:00Z["));
    }

    @Test
    void invalidRevisionNumberTest() {
        ZonedDateTime dateTime = ZonedDateTime.now();
        IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> new DataExchanges("", -1, StandardMessageType.B19, StandardProcessType.A01,
                "", StandardCodingSchemeType.A01, StandardRoleType.A32,
                "", StandardCodingSchemeType.A02, StandardRoleType.A33,
                dateTime, null, "", StandardStatusType.A01, null,
                null, null));
        assertTrue(e.getMessage().contains("Bad revision number value -1"));
    }

    @Test
    void coverageTests() {
        // StandardCodingSchemeType
        assertEquals("EIC", StandardCodingSchemeType.A01.getDescription());
        assertEquals("CGM", StandardCodingSchemeType.A02.getDescription());
        // StandardMessageType
        assertEquals("Reporting information market document", StandardMessageType.B19.getDescription());
        // StandardProcessType
        assertEquals("Day ahead", StandardProcessType.A01.getDescription());
        assertEquals("Total intraday", StandardProcessType.A18.getDescription());
        // StandardRoleType
        assertEquals("Market information aggregator", StandardRoleType.A32.getDescription());
        assertEquals("Information receiver", StandardRoleType.A33.getDescription());
        assertEquals("Capacity Coordinator", StandardRoleType.A36.getDescription());
        assertEquals("Regional Security Coordinator (RSC)", StandardRoleType.A44.getDescription());
        // StandardStatusType
        assertEquals("Intermediate", StandardStatusType.A01.getDescription());
        assertEquals("Final", StandardStatusType.A02.getDescription());
        // StandardBusinessType
        assertEquals("Aggregated netted external schedule", StandardBusinessType.B63.getDescription());
        assertEquals("Netted area AC position", StandardBusinessType.B64.getDescription());
        // StandardCodeType
        assertEquals("Default Time Series applied", StandardReasonCodeType.A26.getDescription());
        assertEquals("Counterpart time series missing", StandardReasonCodeType.A28.getDescription());
        assertEquals("Imposed Time Series from nominated party���s Time Series", StandardReasonCodeType.A30.getDescription());
        assertEquals("Global position not in balance", StandardReasonCodeType.A54.getDescription());
        assertEquals("Time series matched", StandardReasonCodeType.A88.getDescription());
        assertEquals("Data not yet available", StandardReasonCodeType.B08.getDescription());
        assertEquals("Data unverified", StandardReasonCodeType.B30.getDescription());
        assertEquals("Data verified", StandardReasonCodeType.B31.getDescription());
        // StandardCurveType
        assertEquals("Sequential fixed size block", StandardCurveType.A01.getDescription());
        assertEquals("Point", StandardCurveType.A02.getDescription());
        assertEquals("Variable sized Block", StandardCurveType.A03.getDescription());
    }
}