/*
 * Copyright (c) 2000, 2022, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * https://oss.oracle.com/licenses/upl.
 */

package extend;


import com.tangosol.net.cache.NearCache;

import com.oracle.coherence.testing.TestMapListener;
import com.oracle.coherence.testing.TestNCDListener;
import com.oracle.coherence.testing.TestSynchronousMapListener;
import com.oracle.coherence.testing.CustomBackMap;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.tangosol.net.NamedCache;

import com.tangosol.util.MapEvent;

import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;


/**
* A collection of functional tests for Coherence*Extend that use the
* "dist-extend-near-present" cache.
*
* @author jh  2005.11.29
*/
public class DistExtendNearPresentTests
        extends AbstractExtendTests
    {
    // ----- constructors ---------------------------------------------------

    /**
    * Default constructor.
    */
    public DistExtendNearPresentTests()
        {
        super(CACHE_DIST_EXTEND_NEAR_PRESENT);
        }


    // ----- test lifecycle -------------------------------------------------

    /**
    * Initialize the test class.
    */
    @BeforeClass
    public static void startup()
        {
        startCacheServerWithProxy("DistExtendNearPresentTests", "extend", FILE_SERVER_CFG_CACHE);
        }

    /**
    * Shutdown the test class.
    */
    @AfterClass
    public static void shutdown()
        {
        stopCacheServer("DistExtendNearPresentTests");
        }

    /**
    * Test the behavior of {@link com.tangosol.net.NamedCache#truncate()}.
    */
    @Test
    public void testTruncate()
        {
        NamedCache cache = getNamedCache();
        TestNCDListener listener = new TestNCDListener();
        cache.addMapListener(listener);

        assertTrue(cache.isActive());
        cache.put("key", "value");
        assertEquals("value", cache.get("key"));

        cache.truncate();
        assertNull("Front map should be cleared ", cache.get("key"));
        MapEvent evt = listener.waitForEvent();
        assertNotNull("Missing event ", evt);

        // cache should still be active
        assertTrue(cache.isActive());

        // the listener should still be registered with the cache
        cache.put("key1", "value1");
        cache.truncate();
        assertNull("Front map should be cleared ", cache.get("key1"));
        evt = listener.waitForEvent();
        assertNotNull("Missing event", evt);
        assertTrue(cache.isActive());
        }

    /**
    * Test events generated by NearCache priming from
    * {@link com.tangosol.net.NamedCache#get(Object)} should be ignored.
    * See COH-18376.
    */
    @Test
    public void testListenerEvents()
        {
        NamedCache      cache    = getNamedCache();
        TestMapListener listener = new TestMapListener();

        cache.clear();
        assertTrue(cache.isEmpty());
        cache.addMapListener(listener, getKeyObject("Key"), false);

        cache.put(getKeyObject("Key"), "Value");
        MapEvent evt = listener.waitForEvent();
        assertEquals(1, listener.getCount());
        assertNotNull(evt);
        assertEquals(MapEvent.ENTRY_INSERTED, evt.getId());
        assertEquals(getKeyObject("Key"), evt.getKey());

        String v = (String) cache.get("Key");

        cache.put(getKeyObject("Key"), "Value1");
        evt = listener.waitForEvent();
        assertEquals(2, listener.getCount());
        assertNotNull(evt);
        assertEquals(MapEvent.ENTRY_UPDATED, evt.getId());
        assertEquals(getKeyObject("Key"), evt.getKey());

        v = (String) cache.get("Key");

        evt = listener.waitForEvent();
        assertEquals(2, listener.getCount());
        assertEquals(null, evt);
        }

    /**
    * This is a partial port of the .Net {@code $ROOT/tests/Coherence.Tests/Net/Cache/NearCacheTests.cs} in order
    * to validate the fixes for 30149416 and 30397658.
    */
    @Test
    public void testListeners()
        {
        NamedCache cache = getNamedCache();

        TestSynchronousMapListener listen = new TestSynchronousMapListener();

        cache.addMapListener(listen);

        MapEvent evt = listen.waitForEvent();
        assertNull(evt);

        cache.put("Global", "yes");
        evt = listen.waitForEvent();
        assertNotNull(evt);
        assertEquals(MapEvent.ENTRY_INSERTED, evt.getId());
        cache.removeMapListener(listen);

        cache.addMapListener(listen, "test", false);
        evt = listen.waitForEvent();
        assertNull(evt);

        cache.put("t", "a");
        evt = listen.waitForEvent();
        assertNull(evt);

        cache.put("tes", "b");
        evt = listen.waitForEvent();
        assertNull(evt);

        cache.put("test", "c");
        evt = listen.waitForEvent();
        assertNotNull(evt);
        assertEquals(MapEvent.ENTRY_INSERTED, evt.getId());

        cache.put("test", "d");
        evt = listen.waitForEvent();
        assertNotNull(evt);
        assertEquals(MapEvent.ENTRY_UPDATED, evt.getId());

        Object result = cache.get("test");
        assertEquals("d", result);
        evt = listen.waitForEvent();
        assertNull(evt);

        cache.remove("test");
        evt = listen.waitForEvent();
        assertNotNull(evt);
        assertEquals(MapEvent.ENTRY_DELETED, evt.getId());
        }

    /**
     * This test validates the fix for bug 32415967.
     */
    @Test
    public void testNearCacheCustom()
        {
        NamedCache    cache     = getNamedCache("dist-extend-near-present-custom-cache");
        CustomBackMap mapCustom = (CustomBackMap) ((NearCache) cache).getBackCache();

        cache.clear();
        assertTrue(cache.isEmpty());

        cache.put("Key", "Value");

        assertEquals("Value", cache.get("Key"));
        assertEquals(0, mapCustom.f_atomicCounter.get());
        }
    }
