@Test
  public void shouldCommitTransactionAndTellRegistryToForgetItsHandle() throws Exception {
    // given
    KernelAPI kernel = mockKernel();
    TransitionalTxManagementKernelTransaction transactionContext =
        (TransitionalTxManagementKernelTransaction) kernel.newTransaction();

    TransactionRegistry registry = mock(TransactionRegistry.class);
    when(registry.begin()).thenReturn(1337l);

    ExecutionEngine engine = mock(ExecutionEngine.class);
    ExecutionResult result = mock(ExecutionResult.class);
    when(engine.execute("query", map())).thenReturn(result);
    TransactionHandle handle =
        new TransactionHandle(kernel, engine, registry, uriScheme, StringLogger.DEV_NULL);
    ExecutionResultSerializer output = mock(ExecutionResultSerializer.class);

    // when
    handle.commit(
        statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output);

    // then
    InOrder transactionOrder = inOrder(transactionContext, registry);
    transactionOrder.verify(transactionContext).commit();
    transactionOrder.verify(registry).forget(1337l);

    InOrder outputOrder = inOrder(output);
    outputOrder.verify(output).statementResult(result, false, (ResultDataContent[]) null);
    outputOrder.verify(output).errors(argThat(hasNoErrors()));
    outputOrder.verify(output).finish();
    verifyNoMoreInteractions(output);
  }
 @Test
 public void getNonExistentKeyReturnsNull() throws Exception {
   TransactionHandle txn = manager.beginTransaction();
   assertEquals(null, KeyColumnValueStoreUtil.get(store, txn, 0, "col0"));
   assertEquals(null, KeyColumnValueStoreUtil.get(store, txn, 0, "col1"));
   txn.commit();
 }
  @Test
  public void shouldSuspendTransactionAndReleaseForOtherRequestsAfterExecutingStatements()
      throws Exception {
    // given
    KernelAPI kernel = mockKernel();
    TransitionalTxManagementKernelTransaction transactionContext =
        (TransitionalTxManagementKernelTransaction) kernel.newTransaction();

    TransactionRegistry registry = mock(TransactionRegistry.class);
    when(registry.begin()).thenReturn(1337l);

    ExecutionEngine engine = mock(ExecutionEngine.class);
    ExecutionResult executionResult = mock(ExecutionResult.class);
    when(engine.execute("query", map())).thenReturn(executionResult);
    TransactionHandle handle =
        new TransactionHandle(kernel, engine, registry, uriScheme, StringLogger.DEV_NULL);
    ExecutionResultSerializer output = mock(ExecutionResultSerializer.class);

    // when
    handle.execute(
        statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output);

    // then
    InOrder transactionOrder = inOrder(transactionContext, registry);
    transactionOrder.verify(transactionContext).suspendSinceTransactionsAreStillThreadBound();
    transactionOrder.verify(registry).release(1337l, handle);

    InOrder outputOrder = inOrder(output);
    outputOrder.verify(output).transactionCommitUri(uriScheme.txCommitUri(1337));
    outputOrder.verify(output).statementResult(executionResult, false, (ResultDataContent[]) null);
    outputOrder.verify(output).transactionStatus(anyLong());
    outputOrder.verify(output).errors(argThat(hasNoErrors()));
    outputOrder.verify(output).finish();
    verifyNoMoreInteractions(output);
  }
  @Test
  public void shouldLogMessageIfCypherSyntaxErrorOccurs() throws Exception {
    // given
    KernelAPI kernel = mockKernel();

    ExecutionEngine executionEngine = mock(ExecutionEngine.class);
    when(executionEngine.execute("matsch (n) return n", map()))
        .thenThrow(new SyntaxException("did you mean MATCH?"));

    StringLogger log = mock(StringLogger.class);

    TransactionRegistry registry = mock(TransactionRegistry.class);
    when(registry.begin()).thenReturn(1337l);

    TransactionHandle handle =
        new TransactionHandle(kernel, executionEngine, registry, uriScheme, log);
    ExecutionResultSerializer output = mock(ExecutionResultSerializer.class);

    // when
    handle.commit(
        statements(new Statement("matsch (n) return n", map(), false, (ResultDataContent[]) null)),
        output);

    // then
    verify(registry).forget(1337l);

    InOrder outputOrder = inOrder(output);
    outputOrder.verify(output).errors(argThat(hasErrors(StatusCode.STATEMENT_SYNTAX_ERROR)));
    outputOrder.verify(output).finish();
    verifyNoMoreInteractions(output);
  }
  @Test
  public void shouldExecuteStatements() throws Exception {
    // given
    KernelAPI kernel = mockKernel();

    ExecutionEngine executionEngine = mock(ExecutionEngine.class);
    ExecutionResult executionResult = mock(ExecutionResult.class);
    when(executionEngine.execute("query", map())).thenReturn(executionResult);
    TransactionRegistry registry = mock(TransactionRegistry.class);
    when(registry.begin()).thenReturn(1337l);
    TransactionHandle handle =
        new TransactionHandle(kernel, executionEngine, registry, uriScheme, StringLogger.DEV_NULL);
    ExecutionResultSerializer output = mock(ExecutionResultSerializer.class);

    // when
    handle.execute(
        statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output);

    // then
    verify(executionEngine).execute("query", map());

    InOrder outputOrder = inOrder(output);
    outputOrder.verify(output).transactionCommitUri(uriScheme.txCommitUri(1337));
    outputOrder.verify(output).statementResult(executionResult, false, (ResultDataContent[]) null);
    outputOrder.verify(output).transactionStatus(anyLong());
    outputOrder.verify(output).errors(argThat(hasNoErrors()));
    outputOrder.verify(output).finish();
    verifyNoMoreInteractions(output);
  }
  @Test
  public void shouldRollbackTransactionIfExecutionErrorOccurs() throws Exception {
    // given
    KernelAPI kernel = mockKernel();
    TransitionalTxManagementKernelTransaction transactionContext =
        (TransitionalTxManagementKernelTransaction) kernel.newTransaction();

    TransactionRegistry registry = mock(TransactionRegistry.class);
    when(registry.begin()).thenReturn(1337l);

    ExecutionEngine executionEngine = mock(ExecutionEngine.class);
    when(executionEngine.execute("query", map())).thenThrow(new NullPointerException());

    TransactionHandle handle =
        new TransactionHandle(kernel, executionEngine, registry, uriScheme, StringLogger.DEV_NULL);
    ExecutionResultSerializer output = mock(ExecutionResultSerializer.class);

    // when
    handle.execute(
        statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output);

    // then
    verify(transactionContext).rollback();
    verify(registry).forget(1337l);

    InOrder outputOrder = inOrder(output);
    outputOrder.verify(output).transactionCommitUri(uriScheme.txCommitUri(1337));
    outputOrder
        .verify(output)
        .errors(argThat(hasErrors(StatusCode.INTERNAL_STATEMENT_EXECUTION_ERROR)));
    outputOrder.verify(output).finish();
    verifyNoMoreInteractions(output);
  }
  @Test
  public void shouldLogMessageIfCommitErrorOccurs() throws Exception {
    // given
    KernelAPI kernel = mockKernel();
    TransitionalTxManagementKernelTransaction transactionContext =
        (TransitionalTxManagementKernelTransaction) kernel.newTransaction();
    doThrow(new NullPointerException()).when(transactionContext).commit();

    StringLogger log = mock(StringLogger.class);

    TransactionRegistry registry = mock(TransactionRegistry.class);
    when(registry.begin()).thenReturn(1337l);

    ExecutionEngine engine = mock(ExecutionEngine.class);
    ExecutionResult executionResult = mock(ExecutionResult.class);
    when(engine.execute("query", map())).thenReturn(executionResult);
    TransactionHandle handle = new TransactionHandle(kernel, engine, registry, uriScheme, log);
    ExecutionResultSerializer output = mock(ExecutionResultSerializer.class);

    // when
    handle.commit(
        statements(new Statement("query", map(), false, (ResultDataContent[]) null)), output);

    // then
    verify(log).error(eq("Failed to commit transaction."), any(NullPointerException.class));
    verify(registry).forget(1337l);

    InOrder outputOrder = inOrder(output);
    outputOrder.verify(output).statementResult(executionResult, false, (ResultDataContent[]) null);
    outputOrder
        .verify(output)
        .errors(argThat(hasErrors(StatusCode.INTERNAL_COMMIT_TRANSACTION_ERROR)));
    outputOrder.verify(output).finish();
    verifyNoMoreInteractions(output);
  }
  @Test
  public void shouldRollbackTransactionAndTellRegistryToForgetItsHandle() throws Exception {
    // given
    KernelAPI kernel = mockKernel();
    TransitionalTxManagementKernelTransaction transactionContext =
        (TransitionalTxManagementKernelTransaction) kernel.newTransaction();

    TransactionRegistry registry = mock(TransactionRegistry.class);
    when(registry.begin()).thenReturn(1337l);

    TransactionHandle handle =
        new TransactionHandle(
            kernel, mock(ExecutionEngine.class), registry, uriScheme, StringLogger.DEV_NULL);
    ExecutionResultSerializer output = mock(ExecutionResultSerializer.class);

    // when
    handle.rollback(output);

    // then
    InOrder transactionOrder = inOrder(transactionContext, registry);
    transactionOrder.verify(transactionContext).rollback();
    transactionOrder.verify(registry).forget(1337l);

    InOrder outputOrder = inOrder(output);
    outputOrder.verify(output).errors(argThat(hasNoErrors()));
    outputOrder.verify(output).finish();
    verifyNoMoreInteractions(output);
  }
  @Test
  public void shouldRollbackTransactionIfDeserializationErrorOccurs() throws Exception {
    // given
    KernelAPI kernel = mockKernel();
    TransitionalTxManagementKernelTransaction transactionContext =
        (TransitionalTxManagementKernelTransaction) kernel.newTransaction();

    TransactionRegistry registry = mock(TransactionRegistry.class);
    when(registry.begin()).thenReturn(1337l);

    TransactionHandle handle =
        new TransactionHandle(
            kernel, mock(ExecutionEngine.class), registry, uriScheme, StringLogger.DEV_NULL);
    ExecutionResultSerializer output = mock(ExecutionResultSerializer.class);

    // when
    handle.execute(
        deserilizationErrors(new Neo4jError(StatusCode.INVALID_REQUEST_FORMAT, new Exception())),
        output);

    // then
    verify(transactionContext).rollback();
    verify(registry).forget(1337l);

    InOrder outputOrder = inOrder(output);
    outputOrder.verify(output).transactionCommitUri(uriScheme.txCommitUri(1337));
    outputOrder.verify(output).errors(argThat(hasErrors(StatusCode.INVALID_REQUEST_FORMAT)));
    outputOrder.verify(output).finish();
    verifyNoMoreInteractions(output);
  }
  private void rollbackSuspended(Predicate<TransactionMarker> predicate) {
    Set<Long> candidateTransactionIdsToRollback = new HashSet<Long>();

    for (Map.Entry<Long, TransactionMarker> entry : registry.entrySet()) {
      TransactionMarker marker = entry.getValue();
      if (marker.isSuspended() && predicate.accept(marker)) {
        candidateTransactionIdsToRollback.add(entry.getKey());
      }
    }

    for (long id : candidateTransactionIdsToRollback) {
      TransactionHandle handle;
      try {
        handle = acquire(id);
      } catch (TransactionLifecycleException invalidTransactionId) {
        // Allow this - someone snatched the transaction from under our feet,
        continue;
      }
      try {
        handle.forceRollback();
        log.info(format("Transaction with id %d has been automatically rolled back.", id));
      } catch (Throwable e) {
        log.error(format("Transaction with id %d failed to roll back.", id), e);
      } finally {
        forget(id);
      }
    }
  }
 @Test
 public void containsKeyReturnsFalseOnNonexistentKey() throws Exception {
   TransactionHandle txn = manager.beginTransaction();
   ByteBuffer key1 = KeyColumnValueStoreUtil.longToByteBuffer(1);
   assertFalse(store.containsKey(key1.duplicate(), txn));
   txn.commit();
 }
  @Test
  public void getSliceRespectsAllBoundsInclusionArguments() throws Exception {
    // Test case where endColumn=startColumn+1
    ByteBuffer key = KeyColumnValueStoreUtil.longToByteBuffer(0);
    ByteBuffer columnBeforeStart = KeyColumnValueStoreUtil.longToByteBuffer(776);
    ByteBuffer columnStart = KeyColumnValueStoreUtil.longToByteBuffer(777);
    ByteBuffer columnEnd = KeyColumnValueStoreUtil.longToByteBuffer(778);
    ByteBuffer columnAfterEnd = KeyColumnValueStoreUtil.longToByteBuffer(779);

    // First insert four test Entries
    TransactionHandle txn = manager.beginTransaction();
    List<Entry> entries =
        Arrays.asList(
            new Entry(columnBeforeStart, columnBeforeStart),
            new Entry(columnStart, columnStart),
            new Entry(columnEnd, columnEnd),
            new Entry(columnAfterEnd, columnAfterEnd));
    store.mutate(key, entries, null, txn);
    txn.commit();

    // getSlice() with only start inclusive
    txn = manager.beginTransaction();
    List<Entry> result = store.getSlice(key, columnStart, columnEnd, txn);
    assertEquals(1, result.size());
    assertEquals(777, result.get(0).getColumn().getLong());
    txn.commit();
  }
  @Test
  public void containsKeyColumnReturnsTrueOnExtantInput() throws Exception {
    TransactionHandle txn = manager.beginTransaction();
    KeyColumnValueStoreUtil.insert(store, txn, 1, "c", "v");
    txn.commit();

    txn = manager.beginTransaction();
    ByteBuffer key1 = KeyColumnValueStoreUtil.longToByteBuffer(1);
    ByteBuffer c = KeyColumnValueStoreUtil.stringToByteBuffer("c");
    assertTrue(store.containsKeyColumn(key1.duplicate(), c.duplicate(), txn));
    txn.commit();
  }
  // This is very very dirty, but do we have a choice?
  public GraphAwareLongRunningTransaction(TransactionHandle transactionHandle) {
    this.transactionHandle = transactionHandle;
    try {
      Field contextField = transactionHandle.getClass().getDeclaredField("context");
      contextField.setAccessible(true);
      transaction = (TransitionalTxManagementKernelTransaction) contextField.get(transactionHandle);

      Field registryField = transactionHandle.getClass().getDeclaredField("registry");
      registryField.setAccessible(true);
      registry = (TransactionRegistry) registryField.get(transactionHandle);

      Field idField = transactionHandle.getClass().getDeclaredField("id");
      idField.setAccessible(true);
      id = (long) idField.get(transactionHandle);
    } catch (IllegalAccessException | NoSuchFieldException e) {
      throw new RuntimeException(e);
    }
  }
  @Test
  public void insertingGettingAndDeletingSimpleDataWorks() throws Exception {
    TransactionHandle txn = manager.beginTransaction();
    KeyColumnValueStoreUtil.insert(store, txn, 0, "col0", "val0");
    KeyColumnValueStoreUtil.insert(store, txn, 0, "col1", "val1");
    txn.commit();

    txn = manager.beginTransaction();
    assertEquals("val0", KeyColumnValueStoreUtil.get(store, txn, 0, "col0"));
    assertEquals("val1", KeyColumnValueStoreUtil.get(store, txn, 0, "col1"));
    KeyColumnValueStoreUtil.delete(store, txn, 0, "col0");
    KeyColumnValueStoreUtil.delete(store, txn, 0, "col1");
    txn.commit();

    txn = manager.beginTransaction();
    assertEquals(null, KeyColumnValueStoreUtil.get(store, txn, 0, "col0"));
    assertEquals(null, KeyColumnValueStoreUtil.get(store, txn, 0, "col1"));
    txn.commit();
  }
  @Test
  public void getSliceRespectsColumnLimit() throws Exception {
    TransactionHandle txn = manager.beginTransaction();
    ByteBuffer key = KeyColumnValueStoreUtil.longToByteBuffer(0);

    final int cols = 1024;

    List<Entry> entries = new LinkedList<Entry>();
    for (int i = 0; i < cols; i++) {
      ByteBuffer col = KeyColumnValueStoreUtil.longToByteBuffer(i);
      entries.add(new Entry(col, col));
    }
    store.mutate(key, entries, null, txn);
    txn.commit();

    txn = manager.beginTransaction();
    ByteBuffer columnStart = KeyColumnValueStoreUtil.longToByteBuffer(0);
    ByteBuffer columnEnd = KeyColumnValueStoreUtil.longToByteBuffer(cols);
    /*
     * When limit is greater than or equal to the matching column count,
     * all matching columns must be returned.
     */
    List<Entry> result = store.getSlice(key, columnStart, columnEnd, cols, txn);
    assertEquals(cols, result.size());
    assertEquals(entries, result);
    result = store.getSlice(key, columnStart, columnEnd, cols + 10, txn);
    assertEquals(cols, result.size());
    assertEquals(entries, result);

    /*
     * When limit is less the matching column count, the columns up to the
     * limit (ordered bytewise) must be returned.
     */
    result = store.getSlice(key, columnStart, columnEnd, cols - 1, txn);
    assertEquals(cols - 1, result.size());
    entries.remove(entries.size() - 1);
    assertEquals(entries, result);
    result = store.getSlice(key, columnStart, columnEnd, 1, txn);
    assertEquals(1, result.size());
    List<Entry> firstEntrySingleton = Arrays.asList(entries.get(0));
    assertEquals(firstEntrySingleton, result);
    txn.commit();
  }
 public void close() {
   if (tx != null) tx.commit();
   store.close();
   manager.close();
 }