/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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.apache.qpid.server.store;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.junit.Before;
import org.junit.Test;

import org.apache.qpid.server.configuration.CommonProperties;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.OverflowPolicy;
import org.apache.qpid.server.model.VirtualHostNode;
import org.apache.qpid.test.utils.UnitTestBase;

public class VirtualHostStoreUpgraderAndRecovererTest extends UnitTestBase
{
    private VirtualHostNode<?> _virtualHostNode;
    private VirtualHostStoreUpgraderAndRecoverer _upgraderAndRecoverer;
    private DurableConfigurationStore _store;

    @Before
    public void setUp() throws Exception
    {

        final Broker broker = mock(Broker.class);
        _virtualHostNode = mock(VirtualHostNode.class);
        when(_virtualHostNode.getParent()).thenReturn(broker);
        _store = mock(DurableConfigurationStore.class);
        _upgraderAndRecoverer = new VirtualHostStoreUpgraderAndRecoverer(_virtualHostNode);
    }

    @Test
    public void testUpgradeFlowControlFrom_6_1() throws Exception
    {
        Map<String, Object> rootAttributes = new HashMap<>();
        rootAttributes.put("modelVersion", "6.1");
        rootAttributes.put("name", "root");
        ConfiguredObjectRecord rootRecord =
                new ConfiguredObjectRecordImpl(UUID.randomUUID(), "VirtualHost", rootAttributes);
        Map<String, Object> queueAttributes = new HashMap<>();
        queueAttributes.put("name", "queue");
        queueAttributes.put("queueFlowControlSizeBytes", 1000);
        queueAttributes.put("queueFlowResumeSizeBytes", 700);
        ConfiguredObjectRecord queueRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Queue", queueAttributes,
                                                                            Collections.singletonMap(rootRecord.getType(),
                                                                                                     rootRecord.getId()));
        List<ConfiguredObjectRecord> records = Arrays.asList(rootRecord, queueRecord);
        List<ConfiguredObjectRecord> upgradedRecords =
                _upgraderAndRecoverer.upgrade(_store, records, "VirtualHost", "modelVersion");

        ConfiguredObjectRecord upgradedQueueRecord = findRecordById(queueRecord.getId(), upgradedRecords);
        assertNotNull("Upgraded queue record not found ", upgradedQueueRecord);

        Map<String, Object> upgradedAttributes = upgradedQueueRecord.getAttributes();
        assertNotNull("Upgraded attributes not found", upgradedAttributes);

        assertEquals("Unexpected maximumQueueDepthBytes", 1000, upgradedAttributes.get("maximumQueueDepthBytes"));

        NumberFormat formatter = NumberFormat.getInstance();
        formatter.setMinimumFractionDigits(2);

        assertEquals("Unexpected queue.queueFlowResumeLimit",
                            formatter.format(70L),
                            ((Map<String, String>) upgradedAttributes.get("context")).get("queue.queueFlowResumeLimit"));

        assertEquals("Unexpected overflowPolicy",
                            OverflowPolicy.PRODUCER_FLOW_CONTROL.name(),
                            String.valueOf(upgradedAttributes.get("overflowPolicy")));
    }

    @Test
    public void testUpgradeQueueAlternateExchangeFrom_6_1() throws Exception
    {
        Map<String, Object> rootAttributes = new HashMap<>();
        rootAttributes.put("modelVersion", "6.1");
        rootAttributes.put("name", "root");
        ConfiguredObjectRecord rootRecord =
                new ConfiguredObjectRecordImpl(UUID.randomUUID(), "VirtualHost", rootAttributes);
        Map<String, Object> queueAttributes = new HashMap<>();
        queueAttributes.put("name", "queue");
        queueAttributes.put("alternateExchange", "testExchange");

        ConfiguredObjectRecord queueRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Queue", queueAttributes,
                                                                            Collections.singletonMap(rootRecord.getType(),
                                                                                                     rootRecord.getId()));

        final Map<String, Object> exchangeAttributes = new HashMap<>();
        exchangeAttributes.put("name", "testExchange");
        ConfiguredObjectRecord exchangeRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Exchange", exchangeAttributes,
                                                                               Collections.singletonMap(rootRecord.getType(),
                                                                                                     rootRecord.getId()));
        List<ConfiguredObjectRecord> records = Arrays.asList(rootRecord, queueRecord, exchangeRecord);
        List<ConfiguredObjectRecord> upgradedRecords =
                _upgraderAndRecoverer.upgrade(_store, records, "VirtualHost", "modelVersion");

        ConfiguredObjectRecord upgradedQueueRecord = findRecordById(queueRecord.getId(), upgradedRecords);
        assertNotNull("Upgraded queue record not found ", upgradedQueueRecord);

        Map<String, Object> upgradedAttributes = upgradedQueueRecord.getAttributes();
        assertNotNull("Upgraded attributes not found", upgradedAttributes);

        assertTrue("Attribute 'alternateBinding' was not added",
                          upgradedAttributes.containsKey("alternateBinding"));
        assertEquals("Unexpected alternateBinding",
                            new HashMap<>(Collections.singletonMap("destination", "testExchange")),
                            new HashMap<>(((Map<String, String>) upgradedAttributes.get("alternateBinding"))));
        assertFalse("Attribute 'alternateExchange' was not removed",
                           upgradedAttributes.containsKey("alternateExchange"));

    }

    @Test
    public void testUpgradeExchangeAlternateExchangeFrom_6_1() throws Exception
    {
        Map<String, Object> rootAttributes = new HashMap<>();
        rootAttributes.put("modelVersion", "6.1");
        rootAttributes.put("name", "root");
        ConfiguredObjectRecord rootRecord =
                new ConfiguredObjectRecordImpl(UUID.randomUUID(), "VirtualHost", rootAttributes);

        final Map<String, Object> alternateExchangeAttributes = new HashMap<>();
        alternateExchangeAttributes.put("name", "testExchange");
        ConfiguredObjectRecord alternateExchangeRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Exchange", alternateExchangeAttributes,
                                                                               Collections.singletonMap(rootRecord.getType(),
                                                                                                        rootRecord.getId()));

        Map<String, Object> exchangeAttributes = new HashMap<>();
        exchangeAttributes.put("name", "exchange");
        exchangeAttributes.put("alternateExchange", "testExchange");

        ConfiguredObjectRecord exchangeRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Exchange", exchangeAttributes,
                                                                            Collections.singletonMap(rootRecord.getType(),
                                                                                                     rootRecord.getId()));

        List<ConfiguredObjectRecord> records = Arrays.asList(rootRecord, exchangeRecord, alternateExchangeRecord);
        List<ConfiguredObjectRecord> upgradedRecords =
                _upgraderAndRecoverer.upgrade(_store, records, "VirtualHost", "modelVersion");

        ConfiguredObjectRecord upgradedQueueRecord = findRecordById(exchangeRecord.getId(), upgradedRecords);
        assertNotNull("Upgraded exchange record not found ", upgradedQueueRecord);

        Map<String, Object> upgradedAttributes = upgradedQueueRecord.getAttributes();
        assertNotNull("Upgraded attributes not found", upgradedAttributes);

        assertTrue("Attribute 'alternateBinding' was not added",
                          upgradedAttributes.containsKey("alternateBinding"));
        assertEquals("Unexpected alternateBinding",
                            new HashMap<>(Collections.singletonMap("destination", "testExchange")),
                            new HashMap<>(((Map<String, String>) upgradedAttributes.get("alternateBinding"))));
        assertFalse("Attribute 'alternateExchange' was not removed",
                           upgradedAttributes.containsKey("alternateExchange"));
    }
    @Test
    public void testUpgradeExchangeAlternateExchangeSpecifiedWithUUIDFrom_6_1() throws Exception
    {
        Map<String, Object> rootAttributes = new HashMap<>();
        rootAttributes.put("modelVersion", "6.1");
        rootAttributes.put("name", "root");
        ConfiguredObjectRecord rootRecord =
                new ConfiguredObjectRecordImpl(UUID.randomUUID(), "VirtualHost", rootAttributes);

        final Map<String, Object> alternateExchangeAttributes = new HashMap<>();
        alternateExchangeAttributes.put("name", "testExchange");
        UUID alternateExchangeId = UUID.randomUUID();
        ConfiguredObjectRecord alternateExchangeRecord = new ConfiguredObjectRecordImpl(alternateExchangeId, "Exchange", alternateExchangeAttributes,
                                                                                        Collections.singletonMap(rootRecord.getType(),
                                                                                                                 rootRecord.getId()));
        Map<String, Object> exchangeAttributes = new HashMap<>();
        exchangeAttributes.put("name", "exchange");
        exchangeAttributes.put("alternateExchange", alternateExchangeId.toString());

        ConfiguredObjectRecord exchangeRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Exchange", exchangeAttributes,
                                                                               Collections.singletonMap(rootRecord.getType(),
                                                                                                        rootRecord.getId()));

        List<ConfiguredObjectRecord> records = Arrays.asList(rootRecord, exchangeRecord, alternateExchangeRecord);
        List<ConfiguredObjectRecord> upgradedRecords =
                _upgraderAndRecoverer.upgrade(_store, records, "VirtualHost", "modelVersion");

        ConfiguredObjectRecord upgradedQueueRecord = findRecordById(exchangeRecord.getId(), upgradedRecords);
        assertNotNull("Upgraded exchange record not found ", upgradedQueueRecord);

        Map<String, Object> upgradedAttributes = upgradedQueueRecord.getAttributes();
        assertNotNull("Upgraded attributes not found", upgradedAttributes);

        assertTrue("Attribute 'alternateBinding' was not added",
                          upgradedAttributes.containsKey("alternateBinding"));
        assertEquals("Unexpected alternateBinding",
                            new HashMap<>(Collections.singletonMap("destination", "testExchange")),
                            new HashMap<>(((Map<String, String>) upgradedAttributes.get("alternateBinding"))));
        assertFalse("Attribute 'alternateExchange' was not removed",
                           upgradedAttributes.containsKey("alternateExchange"));
    }

    @Test
    public void testUpgradeQueueSharedMessageGroupsFrom_6_1() throws Exception
    {
        Map<String, Object> rootAttributes = new HashMap<>();
        rootAttributes.put("modelVersion", "6.1");
        rootAttributes.put("name", "root");
        ConfiguredObjectRecord rootRecord =
                new ConfiguredObjectRecordImpl(UUID.randomUUID(), "VirtualHost", rootAttributes);
        Map<String, Object> queueAttributes = new HashMap<>();
        queueAttributes.put("messageGroupKey", "myheader");
        queueAttributes.put("messageGroupSharedGroups", true);

        ConfiguredObjectRecord queueRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Queue", queueAttributes,
                                                                            Collections.singletonMap(rootRecord.getType(),
                                                                                                     rootRecord.getId()));

        final Map<String, Object> exchangeAttributes = new HashMap<>();
        exchangeAttributes.put("name", "testExchange");
        ConfiguredObjectRecord exchangeRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Exchange", exchangeAttributes,
                                                                               Collections.singletonMap(rootRecord.getType(),
                                                                                                        rootRecord.getId()));
        List<ConfiguredObjectRecord> records = Arrays.asList(rootRecord, queueRecord, exchangeRecord);
        List<ConfiguredObjectRecord> upgradedRecords =
                _upgraderAndRecoverer.upgrade(_store, records, "VirtualHost", "modelVersion");

        ConfiguredObjectRecord upgradedQueueRecord = findRecordById(queueRecord.getId(), upgradedRecords);
        assertNotNull("Upgraded queue record not found ", upgradedQueueRecord);

        Map<String, Object> upgradedAttributes = upgradedQueueRecord.getAttributes();
        assertNotNull("Upgraded attributes not found", upgradedAttributes);

        assertFalse("Attribute 'messageGroupKey' was not removed",
                           upgradedAttributes.containsKey("messageGroupKey"));
        assertFalse("Attribute 'messageGroupSharedGroups' was not removed",
                           upgradedAttributes.containsKey("messageGroupSharedGroups"));

        assertTrue("Attribute 'messageGroupKeyOverride' was not added",
                          upgradedAttributes.containsKey("messageGroupKeyOverride"));
        assertEquals("Unexpected messageGroupKeyOverride",
                            "myheader",
                            upgradedAttributes.get("messageGroupKeyOverride"));
        assertTrue("Attribute 'messageGroupType' was not added",
                          upgradedAttributes.containsKey("messageGroupType"));
        assertEquals("Unexpected messageGroupType", "SHARED_GROUPS", upgradedAttributes.get("messageGroupType"));
    }

    @Test
    public void testUpgradeQueueStandardMessageGroupsFrom_6_1() throws Exception
    {
        Map<String, Object> rootAttributes = new HashMap<>();
        rootAttributes.put("modelVersion", "6.1");
        rootAttributes.put("name", "root");
        ConfiguredObjectRecord rootRecord =
                new ConfiguredObjectRecordImpl(UUID.randomUUID(), "VirtualHost", rootAttributes);
        Map<String, Object> queueAttributes = new HashMap<>();
        queueAttributes.put("messageGroupKey", "JMSXGroupId");
        queueAttributes.put("messageGroupSharedGroups", false);

        ConfiguredObjectRecord queueRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Queue", queueAttributes,
                                                                            Collections.singletonMap(rootRecord.getType(),
                                                                                                     rootRecord.getId()));

        final Map<String, Object> exchangeAttributes = new HashMap<>();
        exchangeAttributes.put("name", "testExchange");
        ConfiguredObjectRecord exchangeRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(), "Exchange", exchangeAttributes,
                                                                               Collections.singletonMap(rootRecord.getType(),
                                                                                                        rootRecord.getId()));
        List<ConfiguredObjectRecord> records = Arrays.asList(rootRecord, queueRecord, exchangeRecord);
        List<ConfiguredObjectRecord> upgradedRecords =
                _upgraderAndRecoverer.upgrade(_store, records, "VirtualHost", "modelVersion");

        ConfiguredObjectRecord upgradedQueueRecord = findRecordById(queueRecord.getId(), upgradedRecords);
        assertNotNull("Upgraded queue record not found ", upgradedQueueRecord);

        Map<String, Object> upgradedAttributes = upgradedQueueRecord.getAttributes();
        assertNotNull("Upgraded attributes not found", upgradedAttributes);

        assertFalse("Attribute 'messageGroupKey' was not removed",
                           upgradedAttributes.containsKey("messageGroupKey"));
        assertFalse("Attribute 'messageGroupSharedGroups' was not removed",
                           upgradedAttributes.containsKey("messageGroupSharedGroups"));
        assertFalse("Attribute 'messageGroupKeyOverride' was added",
                           upgradedAttributes.containsKey("messageGroupKeyOverride"));

        assertTrue("Attribute 'messageGroupType' was not added",
                          upgradedAttributes.containsKey("messageGroupType"));
        assertEquals("Unexpected messageGroupType", "STANDARD", upgradedAttributes.get("messageGroupType"));
    }

    @Test
    public void testContextVariableUpgradeForTLSProtocolsSetOnVirtualHost() throws Exception
    {
        final Map<String, String> context = new HashMap<>();
        context.put("qpid.security.tls.protocolWhiteList", ".*");
        context.put("qpid.security.tls.protocolBlackList", "Ssl.*");

        final Map<String, Object> rootAttributes = new HashMap<>();
        rootAttributes.put("modelVersion", "8.0");
        rootAttributes.put("name", "root");
        rootAttributes.put("context", context);
        final ConfiguredObjectRecord rootRecord = new ConfiguredObjectRecordImpl(UUID.randomUUID(),
                                                                                 "VirtualHost",
                                                                                 rootAttributes);
        final List<ConfiguredObjectRecord> upgradedRecords =
                _upgraderAndRecoverer.upgrade(_store,
                                              Collections.singletonList(rootRecord),
                                              "VirtualHost",
                                              "modelVersion");

        final Map<String, Object> newContext = getContextForRecordWithGivenId(rootRecord.getId(), upgradedRecords);
        assertEquals(".*", newContext.get(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_ALLOW_LIST));
        assertEquals("Ssl.*", newContext.get(CommonProperties.QPID_SECURITY_TLS_PROTOCOL_DENY_LIST));
    }

    @Test
    public void testContextVariableUpgradeForTLSCipherSuitesSetOnVirtualHostAccessControlProvider() throws Exception
    {
        final Map<String, Object> rootAttributes = new HashMap<>();
        rootAttributes.put("modelVersion", "8.0");
        rootAttributes.put("name", "root");
        final ConfiguredObjectRecord rootRecord =
                new ConfiguredObjectRecordImpl(UUID.randomUUID(), "VirtualHost", rootAttributes);

        final Map<String, String> context = new HashMap<>();
        context.put("qpid.security.tls.cipherSuiteWhiteList", ".*");
        context.put("qpid.security.tls.cipherSuiteBlackList", "Ssl.*");
        final ConfiguredObjectRecord accessControlProviderRecord =
                createMockRecordForGivenCategoryTypeAndContext("VirtualHostAccessControlProvider", "test", context);

        final List<ConfiguredObjectRecord> records = Arrays.asList(rootRecord, accessControlProviderRecord);
        final List<ConfiguredObjectRecord> upgradedRecords =
                _upgraderAndRecoverer.upgrade(_store, records, "VirtualHost", "modelVersion");

        final Map<String, Object> newContext =
                getContextForRecordWithGivenId(accessControlProviderRecord.getId(), upgradedRecords);
        assertEquals(".*", newContext.get(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_ALLOW_LIST));
        assertEquals("Ssl.*", newContext.get(CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_DENY_LIST));
    }

    private ConfiguredObjectRecord findRecordById(UUID id, List<ConfiguredObjectRecord> records)
    {
        for (ConfiguredObjectRecord record : records)
        {
            if (id.equals(record.getId()))
            {
                return record;
            }
        }
        return null;
    }

    private ConfiguredObjectRecord createMockRecordForGivenCategoryTypeAndContext(final String category,
                                                                                  final String type,
                                                                                  final Map<String, String> context)
    {
        final ConfiguredObjectRecord record = mock(ConfiguredObjectRecord.class);
        when(record.getId()).thenReturn(UUID.randomUUID());
        when(record.getType()).thenReturn(category);
        final Map<String, Object> attributes = new HashMap<>();
        attributes.put("name", getTestName());
        attributes.put("type", type);
        attributes.put("context", context);
        when(record.getAttributes()).thenReturn(attributes);
        return record;
    }

    private Map<String, Object> getContextForRecordWithGivenId(final UUID rootRecordId,
                                                               final List<ConfiguredObjectRecord> upgradedRecords)
    {
        final ConfiguredObjectRecord upgradedRecord = findRecordById(rootRecordId, upgradedRecords);
        assertNotNull(upgradedRecord);
        final Map<String, Object> attributes = upgradedRecord.getAttributes();
        assertNotNull(attributes);

        final Object context = attributes.get("context");
        assertTrue(context instanceof Map);
        @SuppressWarnings("unchecked")
        final Map<String, Object> contextMap = (Map<String, Object>) context;
        return contextMap;
    }

}
