/* Test mutable and persistent configurations. */
  @Test
  public void testPersistentAndMutableConfigs() throws Exception {

    final String dbName = "foo";

    EnvironmentConfig envConfig = TestUtils.initEnvConfig();
    envConfig.setAllowCreate(true);
    envConfig.setTransactional(true);
    env = create(envHome, envConfig);

    DbConfigManager configMgr = DbInternal.getEnvironmentImpl(env).getConfigManager();
    int defaultNodeMaxEntries = configMgr.getInt(EnvironmentParams.NODE_MAX);
    int defaultNodeDupTreeMaxEntries = configMgr.getInt(EnvironmentParams.NODE_MAX_DUPTREE);

    /* Check the default node max entries setting. */
    assertEquals(defaultNodeMaxEntries, 128);
    assertEquals(defaultNodeDupTreeMaxEntries, 128);

    DatabaseConfig dbConfig = new DatabaseConfig();
    dbConfig.setAllowCreate(true);
    dbConfig.setTransactional(true);

    /* Do updates on each persistent and mutable config. */

    /* Check whether BtreeComparator setting is persisted. */
    dbConfig.setOverrideBtreeComparator(true);
    dbConfig.setBtreeComparator(TestComparator.class);
    DatabaseConfig newConfig = setAndGetDbConfig(env, dbConfig, dbName);
    assertTrue(newConfig.getBtreeComparator() instanceof TestComparator);

    /* Check whether DuplicateComparator setting is persisted. */
    dbConfig.setOverrideDuplicateComparator(true);
    dbConfig.setDuplicateComparator(new TestSerialComparator());
    newConfig = setAndGetDbConfig(env, dbConfig, dbName);
    assertTrue(newConfig.getDuplicateComparator() instanceof TestSerialComparator);

    /* Check whether KeyPrefixing setting is persisted. */
    dbConfig.setKeyPrefixing(true);
    newConfig = setAndGetDbConfig(env, dbConfig, dbName);
    assertTrue(newConfig.getKeyPrefixing());

    /* Check whether NodeMaxEntries setting is persisted. */
    dbConfig.setNodeMaxEntries(512);
    newConfig = setAndGetDbConfig(env, dbConfig, dbName);
    assertTrue(newConfig.getNodeMaxEntries() == 512);

    close(env);
  }
  @Test
  public void testConfigMatching() throws Throwable {

    try {
      /* DatabaseConfig matching. */

      DatabaseConfig confA = new DatabaseConfig();
      DatabaseConfig confB = new DatabaseConfig();

      try {
        confA.validate(confB);
      } catch (Exception E) {
        fail("expected valid match");
      }

      try {
        confB.validate(confA);
      } catch (Exception E) {
        fail("expected valid match");
      }

      try {
        confA.validate(null); // uses the DEFAULT config
      } catch (Exception E) {
        fail("expected valid match");
      }

      confA.setReadOnly(true);
      try {
        confA.validate(confB);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }

      confA.setReadOnly(false);
      confA.setSortedDuplicates(true);
      try {
        confA.validate(confB);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }
      confA.setSortedDuplicates(false);

      confA.setOverrideBtreeComparator(true);
      confA.setBtreeComparator(TestComparator.class);
      confB.setOverrideBtreeComparator(true);
      confB.setBtreeComparator(TestComparator2.class);
      try {
        confA.validate(confB);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }
      confA.setBtreeComparator((Class) null);
      confA.setOverrideBtreeComparator(false);
      confB.setBtreeComparator((Class) null);
      confB.setOverrideBtreeComparator(false);

      confA.setOverrideDuplicateComparator(true);
      confA.setDuplicateComparator(TestComparator.class);
      confB.setOverrideDuplicateComparator(true);
      confB.setDuplicateComparator(TestComparator2.class);
      try {
        confA.validate(confB);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }

      /* Same tests as above but for serialized comparators. */

      confA.setOverrideBtreeComparator(true);
      confA.setBtreeComparator(new TestSerialComparator());
      confB.setOverrideBtreeComparator(true);
      confB.setBtreeComparator(new TestSerialComparator2());
      try {
        confA.validate(confB);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }
      confA.setBtreeComparator((Comparator) null);
      confA.setOverrideBtreeComparator(false);
      confB.setBtreeComparator((Comparator) null);
      confB.setOverrideBtreeComparator(false);

      confA.setOverrideDuplicateComparator(true);
      confA.setDuplicateComparator(new TestSerialComparator());
      confB.setOverrideDuplicateComparator(true);
      confB.setDuplicateComparator(new TestSerialComparator2());
      try {
        confA.validate(confB);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }

      /* SecondaryConfig matching. */

      SecondaryConfig confC = new SecondaryConfig();
      SecondaryConfig confD = new SecondaryConfig();
      confC.setKeyCreator(new SecKeyCreator1());
      confD.setKeyCreator(new SecKeyCreator1());

      try {
        confC.validate(confD);
      } catch (Exception E) {
        E.printStackTrace();
        fail("expected valid match");
      }

      try {
        confD.validate(confC);
      } catch (Exception E) {
        fail("expected valid match");
      }

      try {
        confC.validate(null);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }

      confD.setKeyCreator(new SecKeyCreator2());
      try {
        confC.validate(confD);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }
      confD.setKeyCreator(new SecKeyCreator1());

      confD.setMultiKeyCreator(new SecMultiKeyCreator1());
      try {
        confC.validate(confD);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }
      confD.setMultiKeyCreator(null);

      confC.setForeignKeyDeleteAction(ForeignKeyDeleteAction.NULLIFY);
      try {
        confC.validate(confD);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }
      confC.setForeignKeyDeleteAction(ForeignKeyDeleteAction.ABORT);

      confC.setForeignKeyNullifier(new ForeignKeyNullifier1());
      try {
        confC.validate(confD);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }
      confC.setForeignKeyNullifier(null);

      confC.setForeignMultiKeyNullifier(new ForeignMultiKeyNullifier1());
      try {
        confC.validate(confD);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }
      confC.setForeignMultiKeyNullifier(null);

      confC.setImmutableSecondaryKey(true);
      try {
        confC.validate(confD);
        fail("expected exception");
      } catch (IllegalArgumentException E) {
        // ok
      }
      confC.setImmutableSecondaryKey(false);
    } catch (Throwable t) {
      t.printStackTrace();
      throw t;
    }
  }
  /**
   * Test that any conflicts between configuration object settings and the underlying impl object
   * are detected.
   */
  @Test
  public void testConfigConflict() throws Throwable {

    try {
      EnvironmentConfig envConfig = TestUtils.initEnvConfig();
      envConfig.setAllowCreate(true);
      env = create(envHome, envConfig);

      /*
       * Test conflicts of duplicate allowed configuration.
       */

      /* 1a. Create allowing duplicates. */
      DatabaseConfig firstConfig = new DatabaseConfig();
      firstConfig.setAllowCreate(true);
      firstConfig.setSortedDuplicates(true);
      Database firstHandle = env.openDatabase(null, "fooDups", firstConfig);
      /* 1b. Try to open w/no duplicates. */
      DatabaseConfig secondConfig = new DatabaseConfig();
      secondConfig.setSortedDuplicates(false);
      try {
        env.openDatabase(null, "fooDups", secondConfig);
        fail("Conflict in duplicates allowed should be detected.");
      } catch (IllegalArgumentException expected) {
      }

      firstHandle.close();
      env.removeDatabase(null, "fooDups");

      /* 2a. Create dis-allowing duplicates. */
      firstConfig.setSortedDuplicates(false);
      firstConfig.setKeyPrefixing(false);
      firstHandle = env.openDatabase(null, "fooDups", firstConfig);
      /* 2b. Try to open w/duplicates. */
      secondConfig.setSortedDuplicates(true);
      try {
        env.openDatabase(null, "fooDups", secondConfig);
        fail("Conflict in duplicates allowed should be detected.");
      } catch (IllegalArgumentException expected) {
      }
      firstHandle.close();

      /*
       * Test conflicts of read only. If the environment is read/write
       * we should be able to open handles in read only or read/write
       * mode. If the environment is readonly, the database handles
       * must also be read only.
       */
      DatabaseConfig readOnlyConfig = new DatabaseConfig();
      readOnlyConfig.setReadOnly(true);
      Database roHandle = env.openDatabase(null, "fooDups", readOnlyConfig);
      roHandle.close();

      /* Open the environment in read only mode. */
      close(env);
      envConfig = TestUtils.initEnvConfig();
      envConfig.setReadOnly(true);
      env = create(envHome, envConfig);

      /* Open a readOnly database handle, should succeed */
      roHandle = env.openDatabase(null, "fooDups", readOnlyConfig);
      roHandle.close();

      /* Open a read/write database handle, should not succeed. */
      try {
        env.openDatabase(null, "fooDups", null);
        fail("Should not be able to open read/write");
      } catch (IllegalArgumentException expected) {
      }
      close(env);

      /*
       * Check comparator changes.
       */
      /* 1a. Open w/a null comparator */
      env = create(envHome, null);
      firstConfig = new DatabaseConfig();
      firstConfig.setAllowCreate(true);
      firstHandle = env.openDatabase(null, "fooComparator", firstConfig);
      DatabaseConfig firstRetrievedConfig = firstHandle.getConfig();
      assertEquals(null, firstRetrievedConfig.getBtreeComparator());
      assertEquals(null, firstRetrievedConfig.getDuplicateComparator());

      /*
       * 1b. Open a db w/a different comparator, shouldn't take effect
       * because override is not set.
       */
      secondConfig = new DatabaseConfig();
      Comparator btreeComparator = new TestComparator();
      Comparator dupComparator = new TestComparator();
      secondConfig.setBtreeComparator((Class<Comparator<byte[]>>) btreeComparator.getClass());
      secondConfig.setDuplicateComparator((Class<Comparator<byte[]>>) dupComparator.getClass());
      Database secondHandle = env.openDatabase(null, "fooComparator", secondConfig);
      DatabaseConfig retrievedConfig = secondHandle.getConfig();
      assertEquals(null, retrievedConfig.getBtreeComparator());
      assertEquals(null, retrievedConfig.getDuplicateComparator());
      secondHandle.close();

      /* Same as above but with a serialized comparator. */
      secondConfig = new DatabaseConfig();
      btreeComparator = new TestSerialComparator();
      dupComparator = new TestSerialComparator();
      secondConfig.setBtreeComparator(btreeComparator);
      secondConfig.setDuplicateComparator(dupComparator);
      secondHandle = env.openDatabase(null, "fooComparator", secondConfig);
      retrievedConfig = secondHandle.getConfig();
      assertEquals(null, retrievedConfig.getBtreeComparator());
      assertEquals(null, retrievedConfig.getDuplicateComparator());
      secondHandle.close();

      /*
       * Test that update DatabaseConfig while there are open handles
       * should throw exceptions.
       */
      secondConfig.setOverrideBtreeComparator(true);
      secondConfig.setOverrideDuplicateComparator(true);
      btreeComparator = new TestComparator();
      dupComparator = new TestComparator();
      secondConfig.setBtreeComparator((Class<Comparator<byte[]>>) btreeComparator.getClass());
      secondConfig.setDuplicateComparator((Class<Comparator<byte[]>>) dupComparator.getClass());
      try {
        secondHandle = env.openDatabase(null, "fooComparator", secondConfig);
        fail("Expect exceptions here");
      } catch (IllegalStateException e) {
        /* Expected exception. */
      } catch (Exception e) {
        fail("Unexpected exception: " + e.getMessage());
      }
      secondHandle.close();

      /*
       * Open a new database handle without DatabaseConfig changes should
       * be valid.
       */
      try {
        secondHandle = env.openDatabase(null, "fooComparator", firstConfig);
      } catch (Exception e) {
        fail("Unexpected exception: " + e.getMessage());
      }

      secondHandle.close();
      firstHandle.close();
      close(env);
    } catch (Throwable t) {
      t.printStackTrace();
      close(env);
      throw t;
    }
  }