/**
 * Copyright 2016 Palantir Technologies
 *
 * Licensed under the BSD-3 License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://opensource.org/licenses/BSD-3-Clause
 *
 * 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.palantir.atlasdb.keyvalue.cassandra;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;

import java.util.UUID;

import org.apache.thrift.TException;
import org.junit.Before;
import org.junit.Test;

import com.palantir.atlasdb.cassandra.CassandraKeyValueServiceConfig;
import com.palantir.atlasdb.keyvalue.api.TableReference;

public class SchemaMutationLockTablesTest {
    private SchemaMutationLockTables lockTables;
    private CassandraKeyValueServiceConfig config;
    private CassandraClientPool clientPool;

    @Before
    public void setupKVS() throws TException, InterruptedException {
        config = CassandraTestSuite.CASSANDRA_KVS_CONFIG
                .withKeyspace(UUID.randomUUID().toString().replace('-', '_'));
        clientPool = new CassandraClientPool(config);
        clientPool.runOneTimeStartupChecks();
        lockTables = new SchemaMutationLockTables(clientPool, config);
    }

    @Test
    public void startsWithNoTables() throws TException {
        assertThat(lockTables.getAllLockTables(), is(empty()));
    }

    @Test
    public void tableShouldExistAfterCreation() throws Exception {
        lockTables.createLockTable(UUID.randomUUID());
        assertThat(lockTables.getAllLockTables(), hasSize(1));
    }

    @Test
    public void multipleLockTablesExistAfterCreation() throws Exception {
        lockTables.createLockTable(UUID.randomUUID());
        lockTables.createLockTable(UUID.randomUUID());
        assertThat(lockTables.getAllLockTables(), hasSize(2));
    }

    @Test
    public void multipleSchemaMutationLockTablesObjectsShouldReturnSameLockTables() throws Exception {
        SchemaMutationLockTables lockTables2 = new SchemaMutationLockTables(clientPool, config);
        lockTables.createLockTable(UUID.randomUUID());
        assertThat(lockTables.getAllLockTables(), is(lockTables2.getAllLockTables()));
    }

    @Test
    public void shouldCreateLockTablesInTheRightFormat() throws TException {
        UUID uuid = UUID.randomUUID();
        lockTables.createLockTable(uuid);

        TableReference expectedTable = TableReference.createUnsafe("_locks_" + uuid.toString().replace('-', '_'));

        assertThat(lockTables.getAllLockTables(), contains(expectedTable));
    }
}

@@ -633,16 +633,119 @@
 andra;%0A%0A
+import static java.util.Collections.synchronizedList;%0Aimport static java.util.stream.IntStream.range;%0A%0A
 import s
@@ -789,16 +789,16 @@
 rtThat;%0A
-
 import s
@@ -878,16 +878,61 @@
 .empty;%0A
+import static org.hamcrest.Matchers.hasItem;%0A
 import s
@@ -1026,20 +1026,213 @@
 va.util.
-UUID
+ArrayList;%0Aimport java.util.List;%0Aimport java.util.Set;%0Aimport java.util.UUID;%0Aimport java.util.concurrent.Callable;%0Aimport java.util.concurrent.CyclicBarrier;%0Aimport java.util.function.IntConsumer
 ;%0A%0Aimpor
@@ -3353,11 +3353,936 @@
 );%0A    %7D
+%0A%0A    @Test%0A    public void whenTablesAreCreatedConcurrentlyAtLeastOneThreadShouldSeeBothTables() %7B%0A        CyclicBarrier barrier = new CyclicBarrier(2);%0A%0A        List%3CSet%3CTableReference%3E%3E lockTablesSeen = synchronizedList(new ArrayList%3C%3E());%0A%0A        range(0,2).parallel()%0A                .forEach(ignoringExceptions( () -%3E %7B%0A                    barrier.await();%0A                    lockTables.createLockTable(UUID.randomUUID());%0A                    lockTablesSeen.add(lockTables.getAllLockTables());%0A                    return null;%0A                %7D));%0A%0A        assertThat(%22Only one table was seen by both creation threads%22, lockTablesSeen, hasItem(hasSize(2)));%0A    %7D%0A%0A    private IntConsumer ignoringExceptions(Callable function) %7B%0A        return (i) -%3E %7B%0A            try %7B%0A                function.call();%0A            %7D catch (Exception e) %7B%0A                throw new RuntimeException(e);%0A            %7D%0A        %7D;%0A    %7D
 %0A%7D%0A

Add additional test