/**
 * 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.activemq.network;

import jakarta.jms.Message;
import jakarta.jms.MessageListener;
import jakarta.jms.Session;
import jakarta.jms.TopicConnection;
import jakarta.jms.TopicSession;
import jakarta.jms.TopicSubscriber;
import junit.framework.TestCase;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.broker.region.Destination;
import org.apache.activemq.command.ActiveMQTopic;

/**
 * Various Tests to show the memory leak suspect in network of brokers. This is
 * for https://issues.apache.org/activemq/browse/AMQ-2530
 *
 */
public class NetworkRemovesSubscriptionsTest extends TestCase {
    private final static String frontEndAddress = "tcp://0.0.0.0:61617";
    private final static String backEndAddress = "tcp://0.0.0.0:61616";
    private final static String TOPIC_NAME = "TEST_TOPIC";
    private BrokerService frontEnd;
    private BrokerService backEnd;
    private final ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(frontEndAddress);
    private final ActiveMQTopic topic = new ActiveMQTopic(TOPIC_NAME);

    public void testWithSessionAndSubsciberClose() throws Exception {

        TopicConnection connection = connectionFactory.createTopicConnection();
        connection.start();

        for (int i = 0; i < 100; i++) {
            TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
            TopicSubscriber subscriber = subscriberSession.createSubscriber(topic);
            DummyMessageListener listener = new DummyMessageListener();
            subscriber.setMessageListener(listener);
            subscriber.close();
            subscriberSession.close();
        }
        connection.close();
        Thread.sleep(1000);
        Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic);
        assertNotNull(dest);
        assertTrue(dest.getConsumers().isEmpty());
    }

    public void testWithSessionCloseOutsideTheLoop() throws Exception {

        TopicConnection connection = connectionFactory.createTopicConnection();
        connection.start();
        TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
        for (int i = 0; i < 100; i++) {

            TopicSubscriber subscriber = subscriberSession.createSubscriber(topic);
            DummyMessageListener listener = new DummyMessageListener();
            subscriber.setMessageListener(listener);
            subscriber.close();
        }
        subscriberSession.close();
        connection.close();
        Thread.sleep(1000);
        Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic);
        assertNotNull(dest);
        assertTrue(dest.getConsumers().isEmpty());

    }

    public void testWithOneSubscriber() throws Exception {

        TopicConnection connection = connectionFactory.createTopicConnection();
        connection.start();
        TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

        TopicSubscriber subscriber = subscriberSession.createSubscriber(topic);
        DummyMessageListener listener = new DummyMessageListener();
        subscriber.setMessageListener(listener);
        subscriber.close();
        subscriberSession.close();
        connection.close();
        Thread.sleep(1000);
        Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic);
        assertNotNull(dest);
        assertTrue(dest.getConsumers().isEmpty());
    }

    public void testWithoutSessionAndSubsciberClose() throws Exception {

        TopicConnection connection = connectionFactory.createTopicConnection();
        connection.start();

        for (int i = 0; i < 100; i++) {
            TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
            TopicSubscriber subscriber = subscriberSession.createSubscriber(topic);
            assertNotNull(subscriber);
        }

        connection.close();
        Thread.sleep(1000);
        Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic);
        assertNotNull(dest);
        assertTrue(dest.getConsumers().isEmpty());
    }

    /**
     * Running this test you can produce a leak of only 2 ConsumerInfo on BE
     * broker, NOT 200 as in other cases!
     *
     */
    public void testWithoutSessionAndSubsciberClosePlayAround() throws Exception {

        TopicConnection connection = connectionFactory.createTopicConnection();
        connection.start();

        for (int i = 0; i < 100; i++) {
            TopicSession subscriberSession = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
            TopicSubscriber subscriber = subscriberSession.createSubscriber(topic);
            DummyMessageListener listener = new DummyMessageListener();
            subscriber.setMessageListener(listener);
            if (i != 50) {
                subscriber.close();
                subscriberSession.close();
            }
        }

        connection.close();
        Thread.sleep(1000);
        Destination dest = backEnd.getRegionBroker().getDestinationMap().get(topic);
        assertNotNull(dest);
        assertTrue(dest.getConsumers().isEmpty());
    }

    class DummyMessageListener implements MessageListener {

        @Override
        public void onMessage(Message arg0) {
            // TODO Auto-generated method stub

        }
    }

    @Override
    protected void setUp() throws Exception {
        this.backEnd = new BrokerService();
        this.backEnd.setBrokerName("backEnd");
        this.backEnd.setPersistent(false);
        NetworkConnector backEndNetwork = this.backEnd.addNetworkConnector("static://" + frontEndAddress);
        backEndNetwork.setName("backEndNetwork");
        backEndNetwork.setDynamicOnly(true);
        this.backEnd.addConnector(backEndAddress);
        this.backEnd.start();

        this.frontEnd = new BrokerService();
        this.frontEnd.setBrokerName("frontEnd");
        this.frontEnd.setPersistent(false);
        NetworkConnector frontEndNetwork = this.frontEnd.addNetworkConnector("static://" + backEndAddress);
        frontEndNetwork.setName("frontEndNetwork");
        this.frontEnd.addConnector(frontEndAddress);
        this.frontEnd.start();
        Thread.sleep(2000);
    }

    @Override
    protected void tearDown() throws Exception {
        if (this.backEnd != null) {
            this.backEnd.stop();
        }
        if (this.frontEnd != null) {
            this.frontEnd.stop();
        }
    }

}
