// Copyright 2015 The Bazel Authors. All rights reserved.
//
// Licensed 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 com.google.devtools.build.lib.actions;

import static com.google.common.truth.Truth.assertThat;

import com.google.common.testing.GcFinalization;
import com.google.devtools.build.lib.concurrent.AbstractQueueVisitor;
import com.google.devtools.build.lib.concurrent.ErrorClassifier;
import com.google.devtools.build.lib.testutil.TestThread;
import com.google.devtools.build.lib.testutil.TestUtils;
import java.lang.ref.WeakReference;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
 * Tests for ConcurrentMultimapWithHeadElement.
 */
@RunWith(JUnit4.class)
public class ConcurrentMultimapWithHeadElementTest {
  @Test
  public void testSmoke() {
    ConcurrentMultimapWithHeadElement<String, String> multimap =
        new ConcurrentMultimapWithHeadElement<>();
    assertThat(multimap.putAndGet("key", "val")).isEqualTo("val");
    assertThat(multimap.get("key")).isEqualTo("val");
    assertThat(multimap.putAndGet("key", "val2")).isEqualTo("val");
    assertThat(multimap.keySize()).isEqualTo(1);
    assertThat(multimap.putAndGet("key2", "val")).isEqualTo("val");
    assertThat(multimap.keySize()).isEqualTo(2);
    multimap.remove("key", "val2");
    assertThat(multimap.get("key")).isEqualTo("val");
    assertThat(multimap.putAndGet("key", "val2")).isEqualTo("val");
    multimap.remove("key", "val");
    assertThat(multimap.get("key")).isEqualTo("val2");
  }

  @Test
  public void testDuplicate() {
    ConcurrentMultimapWithHeadElement<String, String> multimap =
        new ConcurrentMultimapWithHeadElement<>();
    assertThat(multimap.putAndGet("key", "val")).isEqualTo("val");
    assertThat(multimap.get("key")).isEqualTo("val");
    assertThat(multimap.putAndGet("key", "val")).isEqualTo("val");
    multimap.remove("key", "val");
    assertThat(multimap.get("key")).isNull();
  }

  @Test
  public void testDuplicateWithEqualsObject() {
    ConcurrentMultimapWithHeadElement<String, String> multimap =
        new ConcurrentMultimapWithHeadElement<>();
    assertThat(multimap.putAndGet("key", "val")).isEqualTo("val");
    assertThat(multimap.get("key")).isEqualTo("val");
    assertThat(multimap.putAndGet("key", "val")).isEqualTo("val");
    multimap.remove("key", "val");
    assertThat(multimap.get("key")).isNull();
  }

  @Test
  public void testFailedRemoval() {
    ConcurrentMultimapWithHeadElement<String, String> multimap =
        new ConcurrentMultimapWithHeadElement<>();
    assertThat(multimap.putAndGet("key", "val")).isEqualTo("val");
    multimap.remove("key", "val2");
    assertThat(multimap.get("key")).isEqualTo("val");
  }

  @Test
  public void testKeyRemoved() {
    String key = new String("key");
    ConcurrentMultimapWithHeadElement<String, String> multimap =
        new ConcurrentMultimapWithHeadElement<>();
    assertThat(multimap.putAndGet(key, "val")).isEqualTo("val");
    WeakReference<String> weakKey = new WeakReference<>(key);
    multimap.remove(key, "val");
    key = null;
    GcFinalization.awaitClear(weakKey);
  }

  @Test
  public void testKeyRemovedAndAddedConcurrently() throws Exception {
    final ConcurrentMultimapWithHeadElement<String, String> multimap =
        new ConcurrentMultimapWithHeadElement<>();
    // Because we have two threads racing, run the test many times. Before fixed, there was a 90%
    // chance of failure in 10,000 runs.
    for (int i = 0; i < 10000; i++) {
      assertThat(multimap.putAndGet("key", "val")).isEqualTo("val");
      final CountDownLatch threadStart = new CountDownLatch(1);
      TestThread testThread =
          new TestThread(
              () -> {
                threadStart.countDown();
                multimap.remove("key", "val");
              });
      testThread.start();
      assertThat(threadStart.await(TestUtils.WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS)).isTrue();
      assertThat(multimap.putAndGet("key", "val2"))
          .isNotNull(); // Removal may not have happened yet.
      assertThat(multimap.get("key")).isNotNull(); // If put failed, this will be null.
      testThread.joinAndAssertState(2000);
      multimap.clear();
    }
  }

  private static class StressTester extends AbstractQueueVisitor {
    private final ConcurrentMultimapWithHeadElement<Boolean, Integer> multimap =
        new ConcurrentMultimapWithHeadElement<>();
    private final AtomicInteger actionCount = new AtomicInteger(0);

    private StressTester() {
      super(
          200,
          1,
          TimeUnit.SECONDS,
          /*failFastOnException=*/ true,
          "action-graph-test",
          ErrorClassifier.DEFAULT);
    }

    private void addAndRemove(final Boolean key, final Integer add, final Integer remove) {
      execute(
          () -> {
            assertThat(multimap.putAndGet(key, add)).isNotNull();
            multimap.remove(key, remove);
            doRandom();
          });
    }

    private Integer getRandomInt() {
      return (int) Math.round(Math.random() * 3.0);
    }

    private void doRandom() {
      if (actionCount.incrementAndGet() > 100000) {
        return;
      }
      Boolean key = Math.random() < 0.5;
      addAndRemove(key, getRandomInt(), getRandomInt());
    }

    private void work() throws InterruptedException {
      awaitQuiescence(/*interruptWorkers=*/ true);
    }
  }

  @Test
  public void testStressTest() throws Exception {
    StressTester stressTester = new StressTester();
    stressTester.doRandom();
    stressTester.work();
  }

}
