package org.jgroups.tests.byteman;

import org.jboss.byteman.contrib.bmunit.BMNGRunner;
import org.jboss.byteman.contrib.bmunit.BMScript;
import org.jgroups.Global;
import org.jgroups.JChannel;
import org.jgroups.blocks.locking.LockService;
import org.jgroups.protocols.CENTRAL_LOCK;
import org.jgroups.util.Util;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * Tests current access to the locks provided by {@link org.jgroups.blocks.locking.LockService}
 * @author Bela Ban
 * @since  3.4
 */
@Test(groups={Global.BYTEMAN,Global.EAP_EXCLUDED},singleThreaded=true)
public class LockServiceConcurrencyTest extends BMNGRunner {
    protected JChannel    ch;
    protected LockService lock_service;

    @BeforeMethod protected void init() throws Exception {
        ch=new JChannel(Util.getTestStack(new CENTRAL_LOCK())).name("A");
        lock_service=new LockService(ch);
        ch.connect("LockServiceConcurrencyTest");
    }

    @AfterMethod protected void destroy() {
        lock_service.unlockAll();
        Util.close(ch);
    }

    /** Tests JIRA https://issues.jboss.org/browse/JGRP-1679 */
    @BMScript(dir="scripts/LockServiceConcurrencyTest", value="testConcurrentClientLocks")
    public void testConcurrentClientLocks() throws InterruptedException {
        Lock lock=lock_service.getLock("L");

        // we're suppressing (via byteman) the LOCK-GRANTED response (until the rendezvous later), so
        // this lock acquisition must fail
        boolean success=lock.tryLock(1, TimeUnit.MILLISECONDS);
        assert !success : "the lock acquisition should have failed";


        // the spurious LOCK-GRANTED response is received, so the lock can be acquired successfully, which is incorrect
        // as we're dropping the LOCK-GRANTED request
        // tryLock() works the same, with or without timeout
        success=lock.tryLock(10, TimeUnit.MILLISECONDS); // timeout needs to be greater than 1 (byteman rule fires on this) !
        assert !success : "lock was acquired successfully - this is incorrect";
    }
}
