context: /*-
   * See the file LICENSE for redistribution information.
   *
   * Copyright (c) 2010, 2014 Oracle and/or its affiliates.  All rights reserved.
   *
   */
  using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Threading;
  using NUnit.Framework;
  using BerkeleyDB;
  
  namespace CsharpAPITest
  {
      [TestFixture]
      public class TransactionCommitTokenTest : CSharpTestFixture
      {
          private uint masterPort;
          private uint clientPort;
          private string ip = "127.0.0.1";
  
   	[TestFixtureSetUp]
  	public void SetUpTestFixture()
   	{
  		testFixtureName = "TransactionCommitTokenTest";
  		base.SetUpTestfixture();
  		ReplicationTest.AvailablePorts portGen = 
  		    new ReplicationTest.AvailablePorts();
  		masterPort = portGen.Current;
  		portGen.MoveNext();
  		clientPort = portGen.Current;
  	}
  
          public DatabaseEnvironment SetUpEnv(String home, uint priority, uint port, bool isMaster)
          {
              try    {
                  Configuration.ClearDir(home);
              } catch (Exception e)    {
                  Console.WriteLine(e.Message);
                  throw new TestException("Please clean the directory");
              }
  
              /* Configure and open environment with replication
               * application.
               */
              DatabaseEnvironmentConfig cfg =
                  new DatabaseEnvironmentConfig();
              cfg.UseReplication = true;
              cfg.MPoolSystemCfg = new MPoolConfig();
              cfg.MPoolSystemCfg.CacheSize =
                  new CacheInfo(0, 20485760, 1);
              cfg.UseLocking = true;
              cfg.UseTxns = true;
              cfg.UseMPool = true;
              cfg.Create = true;
              cfg.UseLogging = true;
              cfg.RunRecovery = true;
              cfg.TxnNoSync = true;
              cfg.FreeThreaded = true;
  
              cfg.RepSystemCfg = new ReplicationConfig();
              DbSiteConfig dbSiteConfig = new DbSiteConfig();
              dbSiteConfig.Host = ip;
              dbSiteConfig.Port = port;
              dbSiteConfig.LocalSite = true;
              cfg.RepSystemCfg.RepmgrSitesConfig.Add(dbSiteConfig);
              cfg.RepSystemCfg.Priority = priority;
              if (!isMaster) {
                  DbSiteConfig dbSiteConfig1 = new DbSiteConfig();
                  dbSiteConfig1.Host = ip;
                  dbSiteConfig1.Port = masterPort;
                  dbSiteConfig1.Helper = true;
                  cfg.RepSystemCfg.RepmgrSitesConfig.Add(dbSiteConfig1);
              }
              cfg.RepSystemCfg.BulkTransfer = false;
              cfg.RepSystemCfg.AckTimeout = 5000;
  
              cfg.RepSystemCfg.RepMgrAckPolicy =
                  AckPolicy.ALL_PEERS;
  
              DatabaseEnvironment env = DatabaseEnvironment.Open(
                  home, cfg);
  
              return env;
          }
  
          public BTreeDatabase Open(DatabaseEnvironment env, bool isMaster)
          {
              string dbName = "rep.db";
  
              // Set up the database.
              BTreeDatabaseConfig dbCfg = new BTreeDatabaseConfig();
              dbCfg.Env = env;
              if (isMaster)
                  dbCfg.Creation = CreatePolicy.IF_NEEDED;
  
              dbCfg.AutoCommit = true;
              dbCfg.FreeThreaded = true;
  
              /*
               * Open the database. Do not provide a txn handle. This
               * Open is autocommitted because BTreeDatabaseConfig.AutoCommit
               * is true.
               */
              return BTreeDatabase.Open(dbName, dbCfg);
          }
  
          [Test]
          public void TestCommitSuccess()
          {
              testName = "TestCommitSuccess";
              SetUpTest(true);
              string[] keys = {"key 1", "key 2", "key 3", "key 4",
                  "key 5", "key 6", "key 7", "key 8", "key 9", "key 10"};
  
              DatabaseEnvironment master = SetUpEnv(testHome + "/master", 100, masterPort, true);
              DatabaseEnvironment client = SetUpEnv(testHome + "/client", 0, clientPort, false);
  
              master.RepMgrStartMaster(2);
              Thread.Sleep(2000);
              client.RepMgrStartClient(2);
  
              BTreeDatabase db1 = Open(master, true);
              BTreeDatabase db2 = null;
              for (; ; ) {
                  if (db2 == null)
                      try {
                         db2 = Open(client, false);
                         break;
                      } catch (DatabaseException) {
                          if (db2 != null) {
                              db2.Close(true);
                              db2 = null;
                          }
                          System.Threading.Thread.Sleep(1000);
                          continue;
                      }
              }
  
              try {
                  for (int i = 0; i < 3; i++)    {
                      Transaction txn = master.BeginTransaction();
  
                      // Get the key.
                      DatabaseEntry key, data;
                      key = new DatabaseEntry(
                          ASCIIEncoding.ASCII.GetBytes(keys[i]));
  
                      data = new DatabaseEntry(
                          ASCIIEncoding.ASCII.GetBytes(keys[i]));
  
                      db1.Put(key, data, txn);
                      txn.Commit();
  
                      byte[] token = txn.CommitToken;
                      Assert.AreEqual(master.IsTransactionApplied(token, 5000), TransactionAppliedStatus.APPLIED);
                      Assert.AreEqual(client.IsTransactionApplied(token, 200000), TransactionAppliedStatus.APPLIED);
                  }
              }
              finally {
                  db1.Close();
                  db2.Close();
                  master.Close();
                  client.Close();
              }
          }
  
          [Test]
          public void TestNullArgument()
          {
              testName = "TestNullArgument";
              SetUpTest(true);
              DatabaseEnvironment master = SetUpEnv(testHome + "/master", 100, 8000, true);
              Assert.Throws<ArgumentNullException>(
                  delegate { master.IsTransactionApplied(null, 0); });
              master.Close();
          }
  
          [Test]
          public void TestValidArgument()
          {
              testName = "TestValidArgument";
              SetUpTest(true);
              DatabaseEnvironment master = SetUpEnv(testHome + "/master", 100, 8000, true);
              Assert.Throws<ArgumentOutOfRangeException>(
                  delegate { master.IsTransactionApplied(new byte[10], 0); });
              master.Close();
          }
  
          [Test]
          public void TestEmptyException() {
              testName = "TestEmptyException";
              SetUpTest(true);
              DatabaseEnvironment master = SetUpEnv(testHome + "/master", 100, 8000, true);
              Transaction txn = master.BeginTransaction();
              txn.Commit();
              byte[] token = txn.CommitToken;
              Assert.AreEqual(TransactionAppliedStatus.EMPTY_TRANSACTION,
                  master.IsTransactionApplied(token, 1000));
              master.Close();
          }
  
          [Test]
          public void TestInvalidToken() {
              testName = "TestInvalidToken";
              SetUpTest(true);
              DatabaseEntry key, data;
              DatabaseEnvironment master = SetUpEnv(testHome + "/master", 100, 8000, true);
              BTreeDatabase db = Open(master,true);
              Transaction txn = master.BeginTransaction();
              key = new DatabaseEntry(
                  ASCIIEncoding.ASCII.GetBytes("Key"));
              data = new DatabaseEntry(
                  ASCIIEncoding.ASCII.GetBytes("Data"));
              db.Put(key, data, txn);
              txn.Commit();
              byte[] token = txn.CommitToken;
              token[19] += 123;
              Assert.Throws<DatabaseException>(delegate { master.IsTransactionApplied(token, 1000); });
              db.Close();
              master.Close();
          }
  
          [Test]
          public void TestOperationOrder() {
              testName = "TestOperationOrder";
              SetUpTest(true);
              DatabaseEnvironment master = SetUpEnv(testHome + "/master", 100, 8000, true);
              Transaction txn = master.BeginTransaction();
              txn.Abort();
              byte[] token;
              Assert.Throws<InvalidOperationException>(delegate { token = txn.CommitToken; });
              master.Close();
          }
  
          [Test]
          public void TestNestedTXN() {
              testName = "TestNestedTXN";
              SetUpTest(true);
              DatabaseEntry key, data;
              DatabaseEnvironment master = SetUpEnv(testHome + "/master", 100, 8000, true);
              BTreeDatabase db = Open(master, true);
              TransactionConfig txnconfig = new TransactionConfig();
  
gt:             Transaction txn = master.BeginTransaction();