[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/lmdbjava/lmdbjava/master/src/test/java/org/lmdbjava/DbiTest.java [Back]  [Original]

/*
 * Copyright  2016-2025 The LmdbJava Open Source Project
 *
 * 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 org.lmdbjava;

import static java.lang.Long.MAX_VALUE;
import static java.lang.System.getProperty;
import static java.nio.ByteBuffer.allocateDirect;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.nCopies;
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.stream.Collectors.toList;
import static java.util.stream.IntStream.range;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.lmdbjava.ByteArrayProxy.PROXY_BA;
import static org.lmdbjava.ByteBufferProxy.PROXY_OPTIMAL;
import static org.lmdbjava.DbiFlags.MDB_CREATE;
import static org.lmdbjava.DbiFlags.MDB_DUPSORT;
import static org.lmdbjava.DbiFlags.MDB_INTEGERKEY;
import static org.lmdbjava.DbiFlags.MDB_REVERSEKEY;
import static org.lmdbjava.Env.create;
import static org.lmdbjava.EnvFlags.MDB_NOSUBDIR;
import static org.lmdbjava.GetOp.MDB_SET_KEY;
import static org.lmdbjava.KeyRange.atMost;
import static org.lmdbjava.PutFlags.MDB_NODUPDATA;
import static org.lmdbjava.PutFlags.MDB_NOOVERWRITE;
import static org.lmdbjava.TestUtils.DB_1;
import static org.lmdbjava.TestUtils.ba;
import static org.lmdbjava.TestUtils.bb;
import static org.lmdbjava.TestUtils.fromBa;

import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.function.IntFunction;
import java.util.function.Supplier;
import java.util.function.ToIntFunction;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.lmdbjava.CursorIterable.KeyVal;
import org.lmdbjava.Dbi.DbFullException;
import org.lmdbjava.Env.AlreadyClosedException;
import org.lmdbjava.Env.MapFullException;
import org.lmdbjava.LmdbNativeException.ConstantDerivedException;

/** Test {@link Dbi}. */
public final class DbiTest {

  private TempDir tempDir;
  private Env env;
  private Env envBa;

  @BeforeEach
  void beforeEach() {
    tempDir = new TempDir();
    final Path file = tempDir.createTempFile();
    env =
        create()
            .setMapSize(64, ByteUnit.MEBIBYTES)
            .setMaxReaders(2)
            .setMaxDbs(2)
            .setEnvFlags(MDB_NOSUBDIR)
            .open(file);
    final Path fileBa = tempDir.createTempFile();
    envBa =
        create(PROXY_BA)
            .setMapSize(64, ByteUnit.MEBIBYTES)
            .setMaxReaders(2)
            .setMaxDbs(2)
            .setEnvFlags(MDB_NOSUBDIR)
            .open(fileBa);
  }

  @AfterEach
  void afterEach() {
    env.close();
    envBa.close();
    tempDir.cleanup();
  }

  @Test
  void close() {
    assertThatThrownBy(
            () -> {
              final Dbi db =
                  env.createDbi()
                      .setDbName(DB_1)
                      .withDefaultComparator()
                      .addDbiFlag(MDB_CREATE)
                      .open();
              db.put(bb(1), bb(42));
              db.close();
              db.put(bb(2), bb(42)); // error
            })
        .isInstanceOf(ConstantDerivedException.class);
  }

  @Test
  void constructorArgsNullEnv() {
    assertThatThrownBy(
            () -> {
              try (Txn txn = env.txnWrite()) {
                new Dbi(
                    null,
                    txn,
                    "foo".getBytes(Env.DEFAULT_NAME_CHARSET),
                    PROXY_OPTIMAL,
                    DbiFlagSet.EMPTY);
              }
            })
        .isInstanceOf(NullPointerException.class);
  }

  @Test
  void constructorArgsNullTxn() {
    assertThatThrownBy(
            () -> {
              new Dbi(
                  env,
                  null,
                  "foo".getBytes(Env.DEFAULT_NAME_CHARSET),
                  PROXY_OPTIMAL,
                  DbiFlagSet.EMPTY);
            })
        .isInstanceOf(NullPointerException.class);
  }

  @Test
  void constructorArgsNullProxy() {
    assertThatThrownBy(
            () -> {
              try (Txn txn = env.txnWrite()) {
                new Dbi(
                    env, txn, "foo".getBytes(Env.DEFAULT_NAME_CHARSET), null, DbiFlagSet.EMPTY);
              }
            })
        .isInstanceOf(NullPointerException.class);
  }

  @Test
  void constructorArgsNullFlags() {
    assertThatThrownBy(
            () -> {
              try (Txn txn = env.txnWrite()) {
                new Dbi(env, txn, "foo".getBytes(Env.DEFAULT_NAME_CHARSET), PROXY_OPTIMAL, null);
              }
            })
        .isInstanceOf(NullPointerException.class);
  }

  @Test
  void constructorArgsNullNativeCallbackComparator() {
    assertThatThrownBy(
            () -> {
              try (Txn txn = env.txnWrite()) {
                new Dbi(
                    env,
                    txn,
                    "foo".getBytes(Env.DEFAULT_NAME_CHARSET),
                    null,
                    true,
                    PROXY_OPTIMAL,
                    DbiFlagSet.EMPTY);
              }
            })
        .isInstanceOf(IllegalArgumentException.class)
        .hasMessageContaining("Is nativeCb is true, you must supply a comparator");
  }

  @Test
  void customComparator() {
    final Comparator reverseOrder =
        (o1, o2) -> {
          final int lexical = PROXY_OPTIMAL.getComparator().compare(o1, o2);
          if (lexical == 0) {
            return 0;
          }
          return lexical * -1;
        };
    doCustomComparator(env, reverseOrder, TestUtils::bb, ByteBuffer::getInt);
  }

  @Test
  void customComparatorByteArray() {
    final Comparator reverseOrder =
        (o1, o2) -> {
          final int lexical = PROXY_BA.getComparator().compare(o1, o2);
          if (lexical == 0) {
            return 0;
          }
          return lexical * -1;
        };
    doCustomComparator(envBa, reverseOrder, TestUtils::ba, TestUtils::fromBa);
  }

  private  void doCustomComparator(
      Env env,
      Comparator comparator,
      IntFunction serializer,
      ToIntFunction deserializer) {
    final Dbi db =
        env.createDbi()
            .setDbName(DB_1)
            .withCallbackComparator(ignored -> comparator)
            .setDbiFlags(MDB_CREATE)
            .open();
    try (Txn txn = env.txnWrite()) {
      assertThat(db.put(txn, serializer.apply(2), serializer.apply(3))).isTrue();
      assertThat(db.put(txn, serializer.apply(4), serializer.apply(6))).isTrue();
      assertThat(db.put(txn, serializer.apply(6), serializer.apply(7))).isTrue();
      assertThat(db.put(txn, serializer.apply(8), serializer.apply(7))).isTrue();
      txn.commit();
    }
    try (Txn txn = env.txnRead();
        CursorIterable ci = db.iterate(txn, atMost(serializer.apply(4)))) {
      final Iterator iter = ci.iterator();
      assertThat(deserializer.applyAsInt(iter.next().key())).isEqualTo(8);
      assertThat(deserializer.applyAsInt(iter.next().key())).isEqualTo(6);
      assertThat(deserializer.applyAsInt(iter.next().key())).isEqualTo(4);
    }
  }

  @Test
  void dbOpenMaxDatabases() {
    assertThatThrownBy(
            () -> {
              env.createDbi()
                  .setDbName("db1 is OK")
                  .withDefaultComparator()
                  .setDbiFlags(MDB_CREATE)
                  .open();
              env.createDbi()
                  .setDbName("db2 is OK")
                  .withDefaultComparator()
                  .setDbiFlags(MDB_CREATE)
                  .open();
              env.createDbi()
                  .setDbName("db3 fails")
                  .withDefaultComparator()
                  .setDbiFlags(MDB_CREATE)
                  .open();
            })
        .isInstanceOf(DbFullException.class);
  }

  @Test
  void dbiWithComparatorThreadSafety() {
    doDbiWithComparatorThreadSafety(
        env, PROXY_OPTIMAL::getComparator, TestUtils::bb, ByteBuffer::getInt);
  }

  @Test
  void dbiWithComparatorThreadSafetyByteArray() {
    doDbiWithComparatorThreadSafety(
        envBa, PROXY_BA::getComparator, TestUtils::ba, TestUtils::fromBa);
  }

  private  void doDbiWithComparatorThreadSafety(
      Env env,
      Supplier comparatorSupplier,
      IntFunction serializer,
      ToIntFunction deserializer) {
    final DbiFlagSet flags = DbiFlagSet.of(MDB_CREATE, MDB_INTEGERKEY);
    final Comparator comparator = comparatorSupplier.get();
    final Dbi db =
        env.createDbi()
            .setDbName(DB_1)
            .withCallbackComparator(ignored -> comparator)
            .setDbiFlags(flags)
            .open();

    final List keys = range(0, 1_000).boxed().collect(toList());

    // TODO surround with try-with-resources in J19+
    //noinspection resource // Not in J8
    ExecutorService pool = Executors.newCachedThreadPool();
    final AtomicBoolean proceed = new AtomicBoolean(true);
    final Future reader =
        pool.submit(
            () -> {
              while (proceed.get()) {
                try (Txn txn = env.txnRead()) {
                  db.get(txn, serializer.apply(50));
                }
              }
            });

    for (final Integer key : keys) {
      try (Txn txn = env.txnWrite()) {
        db.put(txn, serializer.apply(key), serializer.apply(3));
        txn.commit();
      }
    }

    try (Txn txn = env.txnRead();
        CursorIterable ci = db.iterate(txn)) {
      final Iterator iter = ci.iterator();
      final List result = new ArrayList();
      while (iter.hasNext()) {
        result.add(deserializer.applyAsInt(iter.next().key()));
      }

      assertThat(result).contains(keys.toArray(new Integer[0]));
    }

    proceed.set(false);
    try {
      reader.get(1, SECONDS);
      pool.shutdown();
      pool.awaitTermination(1, SECONDS);
    } catch (ExecutionException | InterruptedException | TimeoutException e) {
      throw new IllegalStateException(e);
    }
  }

  @Test
  void drop() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    try (Txn txn = env.txnWrite()) {
      db.put(txn, bb(1), bb(42));
      db.put(txn, bb(2), bb(42));
      assertThat(db.get(txn, bb(1))).isNotNull();
      assertThat(db.get(txn, bb(2))).isNotNull();
      db.drop(txn);
      assertThat(db.get(txn, bb(1))).isNull(); // data gone
      assertThat(db.get(txn, bb(2))).isNull();
      db.put(txn, bb(1), bb(42)); // ensure DB still works
      db.put(txn, bb(2), bb(42));
      assertThat(db.get(txn, bb(1))).isNotNull();
      assertThat(db.get(txn, bb(2))).isNotNull();
    }
  }

  @Test
  void dropAndDelete() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    final Dbi nameDb =
        env.createDbi()
            .setDbName((byte[]) null)
            .withDefaultComparator()
            .setDbiFlags(DbiFlagSet.EMPTY)
            .open();
    final byte[] dbNameBytes = DB_1.getBytes(UTF_8);
    final ByteBuffer dbNameBuffer = allocateDirect(dbNameBytes.length);
    dbNameBuffer.put(dbNameBytes).flip();

    try (Txn txn = env.txnWrite()) {
      assertThat(nameDb.get(txn, dbNameBuffer)).isNotNull();
      db.drop(txn, true);
      assertThat(nameDb.get(txn, dbNameBuffer)).isNull();
      txn.commit();
    }
  }

  @Test
  void dropAndDeleteAnonymousDb() {
    env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    final Dbi nameDb = env.createDbi().withoutDbName().withDefaultComparator().open();
    final byte[] dbNameBytes = DB_1.getBytes(UTF_8);
    final ByteBuffer dbNameBuffer = allocateDirect(dbNameBytes.length);
    dbNameBuffer.put(dbNameBytes).flip();

    try (Txn txn = env.txnWrite()) {
      assertThat(nameDb.get(txn, dbNameBuffer)).isNotNull();
      nameDb.drop(txn, true);
      assertThat(nameDb.get(txn, dbNameBuffer)).isNull();
      txn.commit();
    }

    nameDb.close(); // explicit close after drop is OK
  }

  @Test
  void getName() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    assertThat(db.getName()).isEqualTo(DB_1.getBytes(UTF_8));
  }

  @Test
  void getNamesWhenDbisPresent() {
    final byte[] dbHello = new byte[] {'h', 'e', 'l', 'l', 'o'};
    final byte[] dbWorld = new byte[] {'w', 'o', 'r', 'l', 'd'};
    env.createDbi().setDbName(dbHello).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    env.createDbi().setDbName(dbWorld).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    final List dbiNames = env.getDbiNames();
    assertThat(dbiNames).hasSize(2);
    assertThat(dbiNames.get(0)).isEqualTo(dbHello);
    assertThat(dbiNames.get(1)).isEqualTo(dbWorld);
  }

  @Test
  void getNamesWhenEmpty() {
    final List dbiNames = env.getDbiNames();
    assertThat(dbiNames).isEmpty();
  }

  @Test
  void listsFlags() {
    final Dbi dbi =
        env.createDbi()
            .setDbName(DB_1)
            .withDefaultComparator()
            .setDbiFlags(MDB_CREATE, MDB_DUPSORT, MDB_REVERSEKEY)
            .open();

    try (Txn txn = env.txnRead()) {
      final List flags = dbi.listFlags(txn);
      assertThat(flags).containsExactlyInAnyOrder(MDB_DUPSORT, MDB_REVERSEKEY);
    }
  }

  @Test
  void putAbortGet() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();

    try (Txn txn = env.txnWrite()) {
      db.put(txn, bb(5), bb(5));
      txn.abort();
    }

    try (Txn txn = env.txnWrite()) {
      assertThat(db.get(txn, bb(5))).isNull();
    }
  }

  @Test
  void putAndGetAndDeleteWithInternalTx() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();

    db.put(bb(5), bb(5));
    try (Txn txn = env.txnRead()) {
      final ByteBuffer found = db.get(txn, bb(5));
      assertThat(found).isNotNull();
      assertThat(txn.val().getInt()).isEqualTo(5);
    }
    assertThat(db.delete(bb(5))).isTrue();
    assertThat(db.delete(bb(5))).isFalse();

    try (Txn txn = env.txnRead()) {
      assertThat(db.get(txn, bb(5))).isNull();
    }
  }

  @Test
  void putCommitGet() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    try (Txn txn = env.txnWrite()) {
      db.put(txn, bb(5), bb(5));
      txn.commit();
    }

    try (Txn txn = env.txnWrite()) {
      final ByteBuffer found = db.get(txn, bb(5));
      assertThat(found).isNotNull();
      assertThat(txn.val().getInt()).isEqualTo(5);
    }
  }

  @Test
  void putCommitGetByteArray() {
    final Path file = tempDir.createTempFile();
    try (Env envBa =
        create(PROXY_BA)
            .setMapSize(64, ByteUnit.MEBIBYTES)
            .setMaxReaders(1)
            .setMaxDbs(2)
            .setEnvFlags(MDB_NOSUBDIR)
            .open(file)) {
      final Dbi db =
          envBa.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
      try (Txn txn = envBa.txnWrite()) {
        db.put(txn, ba(5), ba(5));
        txn.commit();
      }
      try (Txn txn = envBa.txnWrite()) {
        final byte[] found = db.get(txn, ba(5));
        assertThat(found).isNotNull();
        assertThat(fromBa(txn.val())).isEqualTo(5);
      }
    }
  }

  @Test
  void putDelete() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();

    try (Txn txn = env.txnWrite()) {
      db.put(txn, bb(5), bb(5));
      assertThat(db.delete(txn, bb(5))).isTrue();

      assertThat(db.get(txn, bb(5))).isNull();
      txn.abort();
    }
  }

  @Test
  void putDuplicateDelete() {
    final Dbi db =
        env.createDbi()
            .setDbName(DB_1)
            .withDefaultComparator()
            .setDbiFlags(MDB_CREATE, MDB_DUPSORT)
            .open();

    try (Txn txn = env.txnWrite()) {
      db.put(txn, bb(5), bb(5));
      db.put(txn, bb(5), bb(6));
      db.put(txn, bb(5), bb(7));
      assertThat(db.delete(txn, bb(5), bb(6))).isTrue();
      assertThat(db.delete(txn, bb(5), bb(6))).isFalse();
      assertThat(db.delete(txn, bb(5), bb(5))).isTrue();
      assertThat(db.delete(txn, bb(5), bb(5))).isFalse();

      try (Cursor cursor = db.openCursor(txn)) {
        final ByteBuffer key = bb(5);
        cursor.get(key, MDB_SET_KEY);
        assertThat(cursor.count()).isEqualTo(1L);
      }
      txn.abort();
    }
  }

  @Test
  void putReserve() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();

    final ByteBuffer key = bb(5);
    try (Txn txn = env.txnWrite()) {
      assertThat(db.get(txn, key)).isNull();
      final ByteBuffer val = db.reserve(txn, key, 32, MDB_NOOVERWRITE);
      val.putLong(MAX_VALUE);
      assertThat(db.get(txn, key)).isNotNull();
      txn.commit();
    }
    try (Txn txn = env.txnWrite()) {
      final ByteBuffer val = db.get(txn, key);
      assertThat(val).isNotNull();
      assertThat(val.capacity()).isEqualTo(32);
      assertThat(val.getLong()).isEqualTo(MAX_VALUE);
      assertThat(val.getLong(8)).isEqualTo(0L);
    }
  }

  @Test
  void putZeroByteValueForNonMdbDupSortDatabase() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    try (Txn txn = env.txnWrite()) {
      final ByteBuffer val = allocateDirect(0);
      db.put(txn, bb(5), val);
      txn.commit();
    }

    try (Txn txn = env.txnRead()) {
      final ByteBuffer found = db.get(txn, bb(5));
      assertThat(found).isNotNull();
      assertThat(txn.val().capacity()).isEqualTo(0);
    }
  }

  @Test
  void returnValueForNoDupData() {
    final Dbi db =
        env.createDbi()
            .setDbName(DB_1)
            .withDefaultComparator()
            .setDbiFlags(MDB_CREATE, MDB_DUPSORT)
            .open();
    try (Txn txn = env.txnWrite()) {
      // ok
      assertThat(db.put(txn, bb(5), bb(6), MDB_NODUPDATA)).isTrue();
      assertThat(db.put(txn, bb(5), bb(7), MDB_NODUPDATA)).isTrue();
      assertThat(db.put(txn, bb(5), bb(6), MDB_NODUPDATA)).isFalse();
    }
  }

  @Test
  void returnValueForNoOverwrite() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    try (Txn txn = env.txnWrite()) {
      // ok
      assertThat(db.put(txn, bb(5), bb(6), MDB_NOOVERWRITE)).isTrue();
      // fails, but gets exist val
      assertThat(db.put(txn, bb(5), bb(8), MDB_NOOVERWRITE)).isFalse();
      assertThat(txn.val().getInt(0)).isEqualTo(6);
    }
  }

  @Test
  void stats() {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();
    db.put(bb(1), bb(42));
    db.put(bb(2), bb(42));
    db.put(bb(3), bb(42));
    final Stat stat;
    try (Txn txn = env.txnRead()) {
      stat = db.stat(txn);
    }
    assertThat(stat).isNotNull();
    assertThat(stat.branchPages).isEqualTo(0L);
    assertThat(stat.depth).isEqualTo(1);
    assertThat(stat.entries).isEqualTo(3L);
    assertThat(stat.leafPages).isEqualTo(1L);
    assertThat(stat.overflowPages).isEqualTo(0L);
    assertThat(stat.pageSize % 4_096).isEqualTo(0);
  }

  @Test
  void testMapFullException() {
    assertThatThrownBy(
            () -> {
              final Dbi db =
                  env.createDbi()
                      .setDbName(DB_1)
                      .withDefaultComparator()
                      .setDbiFlags(MDB_CREATE)
                      .open();
              try (Txn txn = env.txnWrite()) {
                final ByteBuffer v;
                try {
                  v = allocateDirect(1_024 * 1_024 * 1_024);
                } catch (final OutOfMemoryError e) {
                  // Travis CI OS X build cannot allocate this much memory, so assume OK
                  throw new MapFullException();
                }
                db.put(txn, bb(1), v);
              }
            })
        .isInstanceOf(MapFullException.class);
  }

  @Test
  void testParallelWritesStress() {
    if (getProperty("os.name").startsWith("Windows")) {
      return; // Windows VMs run this test too slowly
    }

    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();

    // Travis CI has 1.5 cores for legacy builds
    nCopies(2, null).parallelStream()
        .forEach(
            ignored -> {
              for (int i = 0; i < 15_000; i++) {
                db.put(bb(i), bb(i));
              }
            });
  }

  @Test
  void closedEnvRejectsOpenCall() {
    assertThatThrownBy(
            () -> {
              env.close();
              env.createDbi()
                  .setDbName(DB_1)
                  .withDefaultComparator()
                  .setDbiFlags(MDB_CREATE)
                  .open();
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsCloseCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(null, (db, txn) -> db.close());
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsGetCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(
                  (db, txn) -> {
                    final ByteBuffer valBuf = db.get(txn, bb(1));
                    assertThat(valBuf).isNotNull();
                    assertThat(valBuf.getInt()).isEqualTo(10);
                  },
                  (db, txn) -> db.get(txn, bb(2)));
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsPutCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(null, (db, txn) -> db.put(bb(5), bb(50)));
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsPutWithTxnCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(
                  null,
                  (db, txn) -> {
                    db.put(txn, bb(5), bb(50));
                  });
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsIterateCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(null, Dbi::iterate);
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsDropCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(null, Dbi::drop);
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsDropAndDeleteCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(null, (db, txn) -> db.drop(txn, true));
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsOpenCursorCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(null, Dbi::openCursor);
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsReserveCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(null, (db, txn) -> db.reserve(txn, bb(1), 32, MDB_NOOVERWRITE));
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  @Test
  void closedEnvRejectsStatCall() {
    assertThatThrownBy(
            () -> {
              doEnvClosedTest(null, Dbi::stat);
            })
        .isInstanceOf(AlreadyClosedException.class);
  }

  private void doEnvClosedTest(
      final BiConsumer workBeforeEnvClosed,
      final BiConsumer workAfterEnvClose) {
    final Dbi db =
        env.createDbi().setDbName(DB_1).withDefaultComparator().setDbiFlags(MDB_CREATE).open();

    db.put(bb(1), bb(10));
    db.put(bb(2), bb(20));
    db.put(bb(2), bb(30));
    db.put(bb(4), bb(40));

    try (Txn txn = env.txnWrite()) {

      if (workBeforeEnvClosed != null) {
        workBeforeEnvClosed.accept(db, txn);
      }

      env.close();

      if (workAfterEnvClose != null) {
        workAfterEnvClose.accept(db, txn);
      }
    }
  }

  @Test
  void getNameBytes() {
    //noinspection ConstantValue
    assertThat(Dbi.getNameBytes(null)).isNull();
    ;
    assertThat(Dbi.getNameBytes("foo")).isEqualTo("foo".getBytes(Env.DEFAULT_NAME_CHARSET));
  }
}

Web Proxy Viewer  |  New URL  |  Original Page