/*
 * 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.ignite.internal.vault;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willBe;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import org.apache.ignite.internal.util.Cursor;
import org.apache.ignite.lang.ByteArray;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

/**
 * Base class for testing {@link VaultService} implementations.
 */
public abstract class VaultServiceTest {
    /** Vault. */
    private VaultService vaultService;

    /**
     * Before each.
     */
    @BeforeEach
    public void setUp() throws IOException {
        vaultService = getVaultService();

        vaultService.start();
    }

    /**
     * After each.
     */
    @AfterEach
    void tearDown() throws Exception {
        vaultService.close();
    }

    /**
     * Returns the vault service that will be tested.
     */
    protected abstract VaultService getVaultService();

    /**
     * Tests regular behaviour of the {@link VaultService#put} method.
     */
    @Test
    public void testPut() {
        ByteArray key = getKey(1);

        assertThat(vaultService.get(key), willBe(nullValue(VaultEntry.class)));

        byte[] val = getValue(1);

        assertThat(vaultService.put(key, val), willBe(nullValue(Void.class)));

        assertThat(vaultService.get(key), willBe(equalTo(new VaultEntry(key, val))));

        // test idempotency
        assertThat(vaultService.put(key, val), willBe(nullValue(Void.class)));

        assertThat(vaultService.get(key), willBe(equalTo(new VaultEntry(key, val))));
    }

    /**
     * Tests that the {@link VaultService#put} method removes the given {@code key} if {@code value} equalTo {@code null}.
     */
    @Test
    public void testPutWithNull() {
        ByteArray key = getKey(1);

        byte[] val = getValue(1);

        assertThat(vaultService.put(key, val), willBe(nullValue(Void.class)));

        assertThat(vaultService.get(key), willBe(equalTo(new VaultEntry(key, val))));

        assertThat(vaultService.put(key, null), willBe(nullValue(Void.class)));

        assertThat(vaultService.get(key), willBe(nullValue(VaultEntry.class)));
    }

    /**
     * Tests regular behaviour of the {@link VaultService#remove} method.
     */
    @Test
    public void testRemove() {
        ByteArray key = getKey(1);

        // Remove non-existent value.
        assertThat(vaultService.remove(key), willBe(nullValue(Void.class)));

        assertThat(vaultService.get(key), willBe(nullValue(VaultEntry.class)));

        byte[] val = getValue(1);

        assertThat(vaultService.put(key, val), willBe(nullValue(Void.class)));

        assertThat(vaultService.get(key), willBe(equalTo(new VaultEntry(key, val))));

        // Remove existing value.
        assertThat(vaultService.remove(key), willBe(nullValue(Void.class)));

        assertThat(vaultService.get(key), willBe(nullValue(VaultEntry.class)));
    }

    /**
     * Tests regular behaviour of the {@link VaultService#putAll} method.
     */
    @Test
    public void testPutAll() {
        Map<ByteArray, byte[]> batch = IntStream.range(0, 10)
                .boxed()
                .collect(toMap(VaultServiceTest::getKey, VaultServiceTest::getValue));

        assertThat(vaultService.putAll(batch), willBe(nullValue(Void.class)));

        batch.forEach((k, v) -> assertThat(vaultService.get(k), willBe(equalTo(new VaultEntry(k, v)))));

        assertThat(vaultService.putAll(batch), willBe(nullValue(Void.class)));

        batch.forEach((k, v) -> assertThat(vaultService.get(k), willBe(equalTo(new VaultEntry(k, v)))));
    }

    /**
     * Tests that the {@link VaultService#putAll} method will remove keys, which values are {@code null}.
     */
    @Test
    public void testPutAllWithNull() {
        Map<ByteArray, byte[]> batch = IntStream.range(0, 10)
                .boxed()
                .collect(toMap(VaultServiceTest::getKey, VaultServiceTest::getValue));

        assertThat(vaultService.putAll(batch), willBe(nullValue(Void.class)));

        batch.forEach((k, v) -> assertThat(vaultService.get(k), willBe(equalTo(new VaultEntry(k, v)))));

        Map<ByteArray, byte[]> secondBatch = new HashMap<>();

        secondBatch.put(getKey(4), getValue(3));
        secondBatch.put(getKey(8), getValue(3));
        secondBatch.put(getKey(1), null);
        secondBatch.put(getKey(3), null);

        assertThat(vaultService.putAll(secondBatch), willBe(nullValue(Void.class)));

        assertThat(vaultService.get(getKey(4)), willBe(equalTo(new VaultEntry(getKey(4), getValue(3)))));
        assertThat(vaultService.get(getKey(8)), willBe(equalTo(new VaultEntry(getKey(8), getValue(3)))));
        assertThat(vaultService.get(getKey(1)), willBe(nullValue(VaultEntry.class)));
        assertThat(vaultService.get(getKey(3)), willBe(nullValue(VaultEntry.class)));
    }

    /**
     * Tests regular behaviour of the {@link VaultService#range} method.
     */
    @Test
    public void testRange() throws Exception {
        List<VaultEntry> entries = getRange(0, 10);

        Map<ByteArray, byte[]> batch = entries.stream().collect(toMap(VaultEntry::key, VaultEntry::value));

        assertThat(vaultService.putAll(batch), willBe(nullValue(Void.class)));

        List<VaultEntry> range = range(getKey(3), getKey(7));

        assertThat(range, equalTo(getRange(3, 7)));
    }

    /**
     * Tests that the {@link VaultService#range} returns valid entries when passed a larger range, than the available data.
     */
    @Test
    public void testRangeBoundaries() throws Exception {
        List<VaultEntry> entries = getRange(3, 5);

        Map<ByteArray, byte[]> batch = entries.stream().collect(toMap(VaultEntry::key, VaultEntry::value));

        assertThat(vaultService.putAll(batch), willBe(nullValue(Void.class)));

        List<VaultEntry> range = range(getKey(0), getKey(9));

        assertThat(range, equalTo(entries));
    }

    /**
     * Tests that the {@link VaultService#range} upper bound equalTo not included.
     */
    @Test
    public void testRangeNotIncludedBoundary() throws Exception {
        List<VaultEntry> entries = getRange(3, 5);

        Map<ByteArray, byte[]> batch = entries.stream().collect(toMap(VaultEntry::key, VaultEntry::value));

        assertThat(vaultService.putAll(batch), willBe(nullValue(Void.class)));

        List<VaultEntry> range = range(getKey(3), getKey(4));

        assertThat(range, contains(new VaultEntry(getKey(3), getValue(3))));
    }

    /**
     * Tests that an empty result equalTo returned when {@link VaultService#range} contains invalid boundaries.
     */
    @Test
    public void testRangeInvalidBoundaries() throws Exception {
        Map<ByteArray, byte[]> batch = getRange(3, 5).stream().collect(toMap(VaultEntry::key, VaultEntry::value));

        assertThat(vaultService.putAll(batch), willBe(nullValue(Void.class)));

        List<VaultEntry> range = range(getKey(4), getKey(1));

        assertThat(range, is(empty()));

        range = range(getKey(4), getKey(4));

        assertThat(range, is(empty()));
    }

    /**
     * Creates a test key.
     */
    private static ByteArray getKey(int k) {
        return new ByteArray("key" + k);
    }

    /**
     * Creates a test value.
     */
    private static byte[] getValue(int v) {
        return ("val" + v).getBytes(StandardCharsets.UTF_8);
    }

    /**
     * Creates a range of test Vault entries.
     */
    private static List<VaultEntry> getRange(int from, int to) {
        return IntStream.range(from, to)
                .mapToObj(i -> new VaultEntry(getKey(i), getValue(i)))
                .collect(toList());
    }

    /**
     * Extracts the given range of values from the Vault.
     */
    private List<VaultEntry> range(ByteArray from, ByteArray to) throws Exception {
        try (Cursor<VaultEntry> cursor = vaultService.range(from, to)) {
            return cursor.stream().collect(toList());
        }
    }
}
