public void CurrentInternalTransaction_ReturnsNullWhenEmpty()
        {
            using (var testHarness = new RestTestHarness())
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                client.Connect();

                var tm = new Neo4jClient.Transactions.TransactionManager(client)
                {
                    ScopedTransactions = new Stack<TransactionScopeProxy>()
                };
                Assert.AreEqual(0, tm.ScopedTransactions.Count);
                Assert.IsNull(tm.CurrentInternalTransaction);
            }
        }
        public void CannotJoinAfterClosedTransaction()
        {
            using (var testHarness = new RestTestHarness())
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var tran = client.BeginTransaction())
                {
                    tran.Commit();

                    Assert.IsFalse(tran.IsOpen);
                    // should fail here

                    Assert.That(() => client.BeginTransaction(), Throws.TypeOf<ClosedTransactionException>());
                }
            }
        }
        public void CannotJoinAfterClosedTransaction()
        {
            using (var testHarness = new RestTestHarness())
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var tran = client.BeginTransaction())
                {
                    tran.Commit();

                    Assert.IsFalse(tran.IsOpen);
                    // should fail here
                    using (var tran2 = client.BeginTransaction())
                    {
                    }
                }
            }
        }
        public void CommitInRequiresNewDoesntAffectParentScope()
        {
            using (var testHarness = new RestTestHarness())
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var tran = client.BeginTransaction())
                {
                    using (var tran2 = client.BeginTransaction(TransactionScopeOption.RequiresNew))
                    {
                        tran2.Commit();
                        Assert.IsFalse(tran2.IsOpen);
                    }

                    Assert.IsTrue(tran.IsOpen);
                }
                Assert.IsFalse(client.InTransaction);
            }
        }
 private void ExecuteRestMethodUnderTransaction(
     Action<IGraphClient> restAction,
     TransactionScopeOption option = TransactionScopeOption.Join,
     IEnumerable<KeyValuePair<MockRequest, MockResponse>> requests = null)
 {
     requests = requests ?? Enumerable.Empty<KeyValuePair<MockRequest, MockResponse>>();
     using (var testHarness = new RestTestHarness())
     {
         foreach (var request in requests)
         {
             testHarness.Add(request.Key, request.Value);
         }
         var client = testHarness.CreateAndConnectTransactionalGraphClient();
         using (var transaction = client.BeginTransaction(option))
         {
             restAction(client);
         }
     }
 }
 public void CommitWithoutRequestsShouldNotGenerateMessage()
 {
     var initTransactionRequest = MockRequest.PostJson("/transaction", @"{'statements': []}");
     var commitTransactionRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");
     using (var testHarness = new RestTestHarness
     {
         {
             initTransactionRequest, MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
         },
         {
             commitTransactionRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
         }
     }.ShouldNotBeCalled(initTransactionRequest, commitTransactionRequest))
     {
         var client = testHarness.CreateAndConnectTransactionalGraphClient();
         using (var transaction = client.BeginTransaction())
         {
             // no requests
             transaction.Commit();
         }
     }
 }
        public void CommitWithoutRequestsShouldNotGenerateMessage()
        {
            var initTransactionRequest   = MockRequest.PostJson("/transaction", @"{'statements': []}");
            var commitTransactionRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");

            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest, MockResponse.Json(201, GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    commitTransactionRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            }.ShouldNotBeCalled(initTransactionRequest, commitTransactionRequest))
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var transaction = client.BeginTransaction())
                {
                    // no requests
                    transaction.Commit();
                }
            }
        }
 public void JoinTransactionAfterSuppressCreatesNewTransaction()
 {
     using (var testHarness = new RestTestHarness())
     {
         var client = testHarness.CreateAndConnectTransactionalGraphClient();
         using (var tran = client.BeginTransaction())
         {
             using (var tran2 = client.BeginTransaction(TransactionScopeOption.Suppress))
             {
                 Assert.AreNotSame(tran2, tran);
                 Assert.IsFalse(client.InTransaction);
                 using (var tran3 = client.BeginTransaction(TransactionScopeOption.Join))
                 {
                     Assert.AreNotSame(GetRealTransaction(tran2), GetRealTransaction(tran3));
                     Assert.AreNotSame(GetRealTransaction(tran3), GetRealTransaction(tran2));
                     Assert.IsTrue(client.InTransaction);
                 }
             }
             Assert.IsTrue(client.InTransaction);
         }
         Assert.IsFalse(client.InTransaction);
     }
 }
Пример #9
0
                public async Task ThrowsClosedTransactionException_WhenTransactionAlreadyClosed()
                {
                    const string database = "neo4jclient";

                    var initTransactionRequest     = MockRequest.PostJson($"/db/{database}/tx", "{'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
                    var rollbackTransactionRequest = MockRequest.Delete($"/db/{database}/tx/1");
                    var commitTransactionRequest   = MockRequest.PostJson($"/db/{database}/tx/1/commit", EmptyStatements);

                    using (var testHarness = new RestTestHarness(false, "http://foo:7474")
                    {
                        {
                            initTransactionRequest,
                            MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1), $"http://foo:7474/db/{database}/tx/1")
                        },
                        { commitTransactionRequest, EmptyOkResponse },
                        { rollbackTransactionRequest, EmptyOkResponse }
                    })
                    {
                        var client = await testHarness.CreateAndConnectTransactionalGraphClient(RestTestHarness.Neo4jVersion.Neo40);

                        using (var transaction = client.BeginTransaction(TransactionScopeOption.Join, null, database))
                        {
                            // dummy query to generate request
                            await client.Cypher
                            .Match("n")
                            .Return(n => n.Count())
                            .ExecuteWithoutResultsAsync().ConfigureAwait(false);

                            await transaction.CommitAsync().ConfigureAwait(false);

                            var ex = await Assert.ThrowsAsync <ClosedTransactionException>(async() => await transaction.RollbackAsync());

                            ex.Should().NotBeNull();
                        }
                    }
                }
        public async Task ShouldPromoteBadQueryResponseToNiceException()
        {
            // Arrange
            const string queryText      = @"broken query";
            var          cypherQuery    = new CypherQuery(queryText, new Dictionary <string, object>(), CypherResultMode.Projection, "neo4j");
            var          cypherApiQuery = new CypherStatementList {
                new CypherTransactionStatement(cypherQuery)
            };

            using (var testHarness = new RestTestHarness
            {
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherApiQuery),
                    MockResponse.Json(HttpStatusCode.OK, @"{'results':[], 'errors': [{
    'code' : 'Neo.ClientError.Statement.InvalidSyntax',
    'message' : 'Invalid input b: expected SingleStatement (line 1, column 1)\nThis is not a valid Cypher Statement.\n ^'
  }]}")
                }
            })
            {
                var graphClient = await testHarness.CreateAndConnectTransactionalGraphClient();

                var rawClient = (IRawGraphClient)graphClient;

                using (graphClient.BeginTransaction())
                {
                    var ex = await Assert.ThrowsAsync <NeoException>(async() => await rawClient.ExecuteCypherAsync(cypherQuery));

                    Assert.Equal("InvalidSyntax: Invalid input b: expected SingleStatement (line 1, column 1)\nThis is not a valid Cypher Statement.\n ^", ex.Message);
                    Assert.Equal("Invalid input b: expected SingleStatement (line 1, column 1)\nThis is not a valid Cypher Statement.\n ^", ex.NeoMessage);
                    Assert.Equal("InvalidSyntax", ex.NeoExceptionName);
                    Assert.Equal("Neo.ClientError.Statement.InvalidSyntax", ex.NeoFullName);
                    Assert.Equal(new String[] {}, ex.NeoStackTrace);
                }
            }
        }
        public void ExecuteAsyncRequestInTransaction()
        {
            const string queryText = @"MATCH (n) RETURN count(n) as Total";
            const string resultColumn = @"{'columns':['Total'], 'data':[{'row':[1]}]}";

            var cypherQuery = new CypherQuery(queryText, new Dictionary<string, object>(), CypherResultMode.Projection);
            var cypherApiQuery = new CypherStatementList { new CypherTransactionStatement(cypherQuery, false) };
            var commitRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");
            using (var testHarness = new RestTestHarness
            {
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherApiQuery),
                    MockResponse.Json(201, GenerateInitTransactionResponse(1, resultColumn), "http://foo/db/data/transaction/1")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                var rawClient = (IRawGraphClient) client;
                using (var tran = client.BeginTransaction())
                {
                    var totalObj = rawClient.ExecuteGetCypherResultsAsync<DummyTotal>(cypherQuery).Result.Single();
                    Assert.AreEqual(1, totalObj.Total);
                    tran.Commit();
                }

            }
        }
        public void TwoThreadsShouldNotHaveTheSameTransactionObject()
        {
            // if thread support is not well implemented then the t2's BeginTransaction will fail with NotSupportedException
            ITransaction transactionFromThread1 = null;
            ITransaction transactionFromThread2 = null;
            using (var testHarness = new RestTestHarness())
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                var firstTransactionSet = new EventWaitHandle(false, EventResetMode.AutoReset);
                var secondTransactionSet = new EventWaitHandle(false, EventResetMode.AutoReset);
                var t1 = new Task(() =>
                {
                    try
                    {
                        using (var transaction = client.BeginTransaction())
                        {
                            transactionFromThread1 = transaction;
                            firstTransactionSet.Set();
                            secondTransactionSet.WaitOne();
                        }
                    }
                    catch (Exception e)
                    {
                        firstTransactionSet.Set();
                        throw;
                    }
                });

                var t2 = new Task(() =>
                {
                    firstTransactionSet.WaitOne();
                    try
                    {
                        using (var transaction = client.BeginTransaction())
                        {
                            transactionFromThread2 = transaction;
                            secondTransactionSet.Set();
                        }
                    }
                    catch (Exception e)
                    {
                        secondTransactionSet.Set();
                        throw;
                    }
                });

                t1.Start();
                t2.Start();
                Task.WaitAll(t1, t2);
                Assert.IsNotNull(transactionFromThread1);
                Assert.IsNotNull(transactionFromThread2);
                Assert.AreNotEqual(transactionFromThread1, transactionFromThread2);

            }
        }
        public void DeserializeResultsFromTransaction()
        {
            var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
            var deserializationRequest = MockRequest.PostJson("/transaction/1", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
            var rollbackTransactionRequest = MockRequest.Delete("/transaction/1");
            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    deserializationRequest,
                    MockResponse.Json(200, @"{'results':[{'columns': ['count(n)'], 'data': [{'row': [0]}]}]}")
                },
                {
                    rollbackTransactionRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var transaction = client.BeginTransaction())
                {
                    // dummy query to generate request
                    client.Cypher
                        .Match("n")
                        .Return(n => n.Count())
                        .ExecuteWithoutResults();

                    // this query will hit the deserializer
                    var count = client.Cypher
                        .Match("n")
                        .Return(n => n.Count())
                        .Results;

                    Assert.AreEqual(count.First(), 0);
                }
            }
        }
        public void TransactionCommit()
        {
            var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
            var commitRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");
            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var transaction = client.BeginTransaction())
                {
                    // dummy query to generate request
                    client.Cypher
                        .Match("n")
                        .Return(n => n.Count())
                        .ExecuteWithoutResults();

                    transaction.Commit();
                }
            }
        }
        public void UpdateTransactionEndpointAfterFirstRequest()
        {
            var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
            var rollbackTransactionRequest = MockRequest.Delete("/transaction/1");
            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    rollbackTransactionRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var transaction = client.BeginTransaction())
                {
                    // dummy query to generate request
                    client.Cypher
                        .Match("n")
                        .Return(n => n.Count())
                        .ExecuteWithoutResults();

                    Assert.AreEqual(
                        new Uri("http://foo/db/data/transaction/1"),
                        ((INeo4jTransaction)((TransactionScopeProxy) transaction).TransactionContext).Endpoint);
                }
            }
        }
        public void NestedTransactionWithTransactionScopeQueryFirst()
        {
            const string queryTextMsTransaction = @"MATCH (n) RETURN count(n)";
            const string queryTextTx = @"MATCH (t) RETURN count(t)";
            const string resultColumn = @"{'columns':['count(n)'], 'data':[{'row':[1]}]}";
            var cypherQueryMsTx = new CypherQuery(queryTextMsTransaction, new Dictionary<string, object>(), CypherResultMode.Projection);
            var cypherQueryMsTxStatement = new CypherStatementList { new CypherTransactionStatement(cypherQueryMsTx, false) };
            var cypherQueryTx = new CypherQuery(queryTextTx, new Dictionary<string, object>(), CypherResultMode.Projection);
            var cypherQueryTxStatement = new CypherStatementList { new CypherTransactionStatement(cypherQueryTx, false) };
            var deleteRequest = MockRequest.Delete("/transaction/1");
            var commitRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");
            var commitRequestTx = MockRequest.PostJson("/transaction/2/commit", @"{'statements': []}");

            using (var testHarness = new RestTestHarness
            {
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherQueryMsTxStatement),
                    MockResponse.Json(201, GenerateInitTransactionResponse(1, resultColumn), "http://foo/db/data/transaction/1")
                },
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherQueryTxStatement),
                    MockResponse.Json(201, GenerateInitTransactionResponse(2, resultColumn), "http://foo/db/data/transaction/2")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                },
                {
                    commitRequestTx, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                },
                {
                    deleteRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            }.ShouldNotBeCalled(commitRequest))
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var msTransaction = new TransactionScope())
                {
                    Assert.IsTrue(client.InTransaction);

                    long totalMsTx = client.Cypher
                        .Match("(n)")
                        .Return(n => n.Count())
                        .Results
                        .SingleOrDefault();
                    Assert.AreEqual(1, totalMsTx);

                    using (var tx = client.BeginTransaction())
                    {
                        long total = client.Cypher
                            .Match("(t)")
                            .Return(t => t.Count())
                            .Results
                            .SingleOrDefault();

                        Assert.AreEqual(1, total);

                        // should not be called
                        tx.Commit();
                    }
                }
            }
        }
        public void SuppressTransactionScopeShouldNotEmitTransactionalQuery()
        {
            var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");

            var nonTransactionalRequest = MockRequest.PostJson("/cypher", @"{'query': 'MATCH n\r\nRETURN count(n)', 'params': {}}");

            var commitTransactionRequest = MockRequest.PostJson("/transaction/1/commit", @"{
                'statements': []}");
            var deleteRequest = MockRequest.Delete("/transaction/1");
            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    commitTransactionRequest,
                    MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                },
                {
                    nonTransactionalRequest,
                    MockResponse.Json(200, @"{'columns':['count(n)'], 'data':[[0]] }")
                },
                {
                    deleteRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            }.ShouldNotBeCalled(deleteRequest))
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var tran = new TransactionScope())
                {
                    using (var tran2 = new TransactionScope(TransactionScopeOption.Suppress))
                    {
                        client.Cypher
                            .Match("n")
                            .Return(n => n.Count())
                            .ExecuteWithoutResults();

                        // no rollback should be generated
                    }

                    client.Cypher
                        .Match("n")
                        .Return(n => n.Count())
                        .ExecuteWithoutResults();

                    tran.Complete();
                }
            }
        }
Пример #18
0
        public void NestedTransactionWithTransactionScopeQueryFirst()
        {
            const string queryTextMsTransaction   = @"MATCH (n) RETURN count(n)";
            const string queryTextTx              = @"MATCH (t) RETURN count(t)";
            const string resultColumn             = @"{'columns':['count(n)'], 'data':[{'row':[1]}]}";
            var          cypherQueryMsTx          = new CypherQuery(queryTextMsTransaction, new Dictionary <string, object>(), CypherResultMode.Projection);
            var          cypherQueryMsTxStatement = new CypherStatementList {
                new CypherTransactionStatement(cypherQueryMsTx, false)
            };
            var cypherQueryTx          = new CypherQuery(queryTextTx, new Dictionary <string, object>(), CypherResultMode.Projection);
            var cypherQueryTxStatement = new CypherStatementList {
                new CypherTransactionStatement(cypherQueryTx, false)
            };
            var deleteRequest   = MockRequest.Delete("/transaction/1");
            var commitRequest   = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");
            var commitRequestTx = MockRequest.PostJson("/transaction/2/commit", @"{'statements': []}");

            using (var testHarness = new RestTestHarness
            {
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherQueryMsTxStatement),
                    MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1, resultColumn), "http://foo/db/data/transaction/1")
                },
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherQueryTxStatement),
                    MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(2, resultColumn), "http://foo/db/data/transaction/2")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                },
                {
                    commitRequestTx, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                },
                {
                    deleteRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            }.ShouldNotBeCalled(commitRequest))
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var msTransaction = new TransactionScope())
                {
                    Assert.IsTrue(client.InTransaction);

                    long totalMsTx = client.Cypher
                                     .Match("(n)")
                                     .Return(n => n.Count())
                                     .Results
                                     .SingleOrDefault();
                    Assert.AreEqual(1, totalMsTx);

                    using (var tx = client.BeginTransaction())
                    {
                        long total = client.Cypher
                                     .Match("(t)")
                                     .Return(t => t.Count())
                                     .Results
                                     .SingleOrDefault();

                        Assert.AreEqual(1, total);

                        // should not be called
                        tx.Commit();
                    }
                }
            }
        }
 public void RequiresNewCreateNewTransaction()
 {
     using (var testHarness = new RestTestHarness())
     {
         var client = testHarness.CreateAndConnectTransactionalGraphClient();
         using (var transaction = client.BeginTransaction())
         {
             using (var tran2 = client.BeginTransaction(TransactionScopeOption.RequiresNew))
             {
                 Assert.AreNotSame(GetRealTransaction(tran2), GetRealTransaction(transaction));
                 Assert.IsTrue(client.InTransaction);
             }
             Assert.IsTrue(client.InTransaction);
         }
         Assert.IsFalse(client.InTransaction);
     }
 }
 public void JoinTransactionAfterSuppressCreatesNewTransaction()
 {
     using (var testHarness = new RestTestHarness())
     {
         var client = testHarness.CreateAndConnectTransactionalGraphClient();
         using (var tran = client.BeginTransaction())
         {
             using (var tran2 = client.BeginTransaction(TransactionScopeOption.Suppress))
             {
                 Assert.AreNotSame(tran2, tran);
                 Assert.IsFalse(client.InTransaction);
                 using (var tran3 = client.BeginTransaction(TransactionScopeOption.Join))
                 {
                     Assert.AreNotSame(GetRealTransaction(tran2), GetRealTransaction(tran3));
                     Assert.AreNotSame(GetRealTransaction(tran3), GetRealTransaction(tran2));
                     Assert.IsTrue(client.InTransaction);
                 }
             }
             Assert.IsTrue(client.InTransaction);
         }
         Assert.IsFalse(client.InTransaction);
     }
 }
Пример #21
0
        public void ExecuteMultipleStatementInOneRequestHttpRequest()
        {
            const string headerName    = "MyTestHeader";
            const string headerValue   = "myTestHeaderValue";
            var          customHeaders = new NameValueCollection {
                { headerName, headerValue }
            };


            var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}, {'statement': 'MATCH t\r\nRETURN count(t)', 'resultDataContents':[], 'parameters': {}}]}");
            var commitRequest          = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");

            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var response = MockResponse.NeoRoot20();
                testHarness.Add(MockRequest.Get(""), response);
                var httpClient = testHarness.GenerateHttpClient("http://foo/db/data");
                testHarness.CreateAndConnectTransactionalGraphClient();
                ITransactionalGraphClient client = new GraphClient(new Uri("http://foo/db/data"), httpClient);
                client.Connect();
                using (var transaction = client.BeginTransaction())
                {
                    // dummy query to generate request
                    var rawClient = client as IRawGraphClient;
                    if (rawClient == null)
                    {
                        Assert.Fail("ITransactionalGraphClient is not IRawGraphClient");
                    }

                    var queries = new List <CypherQuery>()
                    {
                        client.Cypher
                        .Match("n")
                        .Return(n => n.Count())
                        .Query,
                        client.Cypher
                        .Match("t")
                        .Return(t => t.Count())
                        .Query
                    };
                    httpClient.ClearReceivedCalls();
                    rawClient.ExecuteMultipleCypherQueriesInTransaction(queries, customHeaders);
                    transaction.Commit();

                    var calls = httpClient.ReceivedCalls().ToList();
                    Assert.IsNotEmpty(calls);

                    HttpRequestMessage requestMessage = null;

                    foreach (var call in calls)
                    {
                        if (call.GetArguments().Single().GetType() == typeof(HttpRequestMessage))
                        {
                            requestMessage = (HttpRequestMessage)call.GetArguments().Single();
                        }
                    }

                    Assert.IsNotNull(requestMessage);

                    var customHeader = requestMessage.Headers.Single(h => h.Key == headerName);
                    Assert.IsNotNull(customHeader);
                    Assert.AreEqual(headerValue, customHeader.Value.Single());
                }
            }
        }
        public void JoinedTransactionsCommitAfterAllEmitVote()
        {
            using (var testHarness = new RestTestHarness())
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var tran = client.BeginTransaction())
                {
                    using (var tran2 = client.BeginTransaction())
                    {
                        tran2.Commit();
                    }

                    Assert.IsTrue(tran.IsOpen);

                    using (var tran3 = client.BeginTransaction(TransactionScopeOption.Suppress))
                    {
                        Assert.AreNotSame(GetRealTransaction(tran3), GetRealTransaction(tran));
                        Assert.IsFalse(client.InTransaction);
                    }

                    Assert.IsTrue(client.InTransaction);
                    Assert.IsTrue(tran.IsOpen);

                    tran.Commit();
                    Assert.IsFalse(tran.IsOpen);
                }
                Assert.IsFalse(client.InTransaction);
            }
        }
        public void RollbackInJoinedTransactionClosesAllJoinedScopes()
        {
            using (var testHarness = new RestTestHarness())
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var tran = client.BeginTransaction())
                {
                    using (var tran2 = client.BeginTransaction())
                    {
                        tran2.Rollback();
                    }

                    Assert.IsFalse(tran.IsOpen);
                }
                Assert.IsFalse(client.InTransaction);
            }
        }
        public void ShouldPromoteBadQueryResponseToNiceException()
        {
            // Arrange
            const string queryText = @"broken query";
            var cypherQuery = new CypherQuery(queryText, new Dictionary<string, object>(), CypherResultMode.Projection);
            var cypherApiQuery = new CypherStatementList {new CypherTransactionStatement(cypherQuery, false)};

            using (var testHarness = new RestTestHarness
                {
                    {
                        MockRequest.PostObjectAsJson("/transaction", cypherApiQuery),
                        MockResponse.Json(HttpStatusCode.OK, @"{'results':[], 'errors': [{
    'code' : 'Neo.ClientError.Statement.InvalidSyntax',
    'message' : 'Invalid input b: expected SingleStatement (line 1, column 1)\nThis is not a valid Cypher Statement.\n ^'
  }]}")
                    }
                })
            {
                var graphClient = testHarness.CreateAndConnectTransactionalGraphClient();
                var rawClient = (IRawGraphClient) graphClient;

                using (graphClient.BeginTransaction())
                {

                    var ex = Assert.Throws<NeoException>(() => rawClient.ExecuteCypher(cypherQuery));
                    Assert.AreEqual("InvalidSyntax: Invalid input b: expected SingleStatement (line 1, column 1)\nThis is not a valid Cypher Statement.\n ^", ex.Message);
                    Assert.AreEqual("Invalid input b: expected SingleStatement (line 1, column 1)\nThis is not a valid Cypher Statement.\n ^", ex.NeoMessage);
                    Assert.AreEqual("InvalidSyntax", ex.NeoExceptionName);
                    Assert.AreEqual("Neo.ClientError.Statement.InvalidSyntax", ex.NeoFullName);
                    CollectionAssert.AreEqual(new String[] {}, ex.NeoStackTrace);
                }
            }
        }
        public void ExecuteMultipleStatementInOneRequest()
        {
            var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}, {'statement': 'MATCH t\r\nRETURN count(t)', 'resultDataContents':[], 'parameters': {}}]}");
            var commitRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");
            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var transaction = client.BeginTransaction())
                {
                    // dummy query to generate request
                    var rawClient = client as IRawGraphClient;
                    if (rawClient == null)
                    {
                        Assert.Fail("ITransactionalGraphClient is not IRawGraphClient");
                    }

                    var queries = new List<CypherQuery>()
                    {
                        client.Cypher
                            .Match("n")
                            .Return(n => n.Count())
                            .Query,
                        client.Cypher
                            .Match("t")
                            .Return(t => t.Count())
                            .Query
                    };

                    rawClient.ExecuteMultipleCypherQueriesInTransaction(queries);
                    transaction.Commit();
                }
            }
        }
        public void TestTransactionScopeWithComplexDeserialization_WithCulture()
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("nb-NO");

            const string queryText = @"MATCH (dt:DummyTotal) RETURN dt";
            const string resultColumn = @"{'columns':['dt'],'data':[{'row':[{'date':'2015-07-27T22:30:35Z'}]}]}";
            var cypherQuery = new CypherQuery(queryText, new Dictionary<string, object>(), CypherResultMode.Projection);
            var cypherApiQuery = new CypherStatementList { new CypherTransactionStatement(cypherQuery, false) };
            var commitRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");

            using (var testHarness = new RestTestHarness
            {
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherApiQuery),
                    MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1, resultColumn), "http://foo/db/data/transaction/1")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                client.JsonContractResolver = new CamelCasePropertyNamesContractResolver();
                using (var msTransaction = new TransactionScope())
                {
                    Assert.IsTrue(client.InTransaction);

                    var query = client.Cypher.Match("(dt:DummyTotal)")
                        .Return(dt => dt.As<DateHolder>());

                    var eResults = query.Results;
                    var results = eResults.ToList();

                    Assert.AreEqual(1, results.Count);
                    var date = results.First().Date;

                    Assert.AreEqual(date.Kind, DateTimeKind.Utc);
                    Assert.AreEqual(new DateTime(2015,7,27,22,30,35), results.First().Date);

                    msTransaction.Complete();
                }

                Assert.IsFalse(client.InTransaction);
            }
        }
        public void NestedJoinedTransactionScope()
        {
            var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
            var secondRequest = MockRequest.PostJson("/transaction/1", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
            var deleteRequest = MockRequest.Delete("/transaction/1");
            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    secondRequest,
                    MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                },
                {
                    deleteRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var scope = new TransactionScope())
                {
                    using (var scope2 = new TransactionScope())
                    {
                        client.Cypher
                            .Match("n")
                            .Return(n => n.Count())
                            .ExecuteWithoutResults();

                        // this will not commit
                        scope2.Complete();
                    }

                    // this should generate a request to the known transaction ID
                    client.Cypher
                        .Match("n")
                        .Return(n => n.Count())
                        .ExecuteWithoutResults();
                }
            }
        }
        public void ExecuteMultipleStatementInOneRequestHttpRequest()
        {
            const string headerName = "MyTestHeader";
            const string headerValue = "myTestHeaderValue";
            var customHeaders = new NameValueCollection { {headerName, headerValue} };
            

            var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}, {'statement': 'MATCH t\r\nRETURN count(t)', 'resultDataContents':[], 'parameters': {}}]}");
            var commitRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");
            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var response = MockResponse.NeoRoot20();
                testHarness.Add(MockRequest.Get(""), response);
                var httpClient = testHarness.GenerateHttpClient("http://foo/db/data");
                testHarness.CreateAndConnectTransactionalGraphClient();
                ITransactionalGraphClient client = new GraphClient(new Uri("http://foo/db/data"), httpClient);
                client.Connect();
                using (var transaction = client.BeginTransaction())
                {
                    // dummy query to generate request
                    var rawClient = client as IRawGraphClient;
                    if (rawClient == null)
                    {
                        Assert.Fail("ITransactionalGraphClient is not IRawGraphClient");
                    }

                    var queries = new List<CypherQuery>()
                    {
                        client.Cypher
                            .Match("n")
                            .Return(n => n.Count())
                            .Query,
                        client.Cypher
                            .Match("t")
                            .Return(t => t.Count())
                            .Query
                    };
                    httpClient.ClearReceivedCalls();
                    rawClient.ExecuteMultipleCypherQueriesInTransaction(queries, customHeaders);
                    transaction.Commit();

                    var calls = httpClient.ReceivedCalls().ToList();
                    Assert.IsNotEmpty(calls);

                    HttpRequestMessage requestMessage = null;

                    foreach (var call in calls)
                    {
                        if (call.GetArguments().Single().GetType() == typeof (HttpRequestMessage))
                        {
                            requestMessage = (HttpRequestMessage) call.GetArguments().Single();
                        }
                    }

                    Assert.IsNotNull(requestMessage);

                    var customHeader = requestMessage.Headers.Single(h => h.Key == headerName);
                    Assert.IsNotNull(customHeader);
                    Assert.AreEqual(headerValue, customHeader.Value.Single());
                }
            }
        }
        public void PromoteDurableInAmbientTransaction()
        {
            // when two durables are registered they get promoted

            // this request will be made by the ForceKeepAlive() call when PSPE registration fails for the second client
            var afterPspeFailRequest = MockRequest.PostJson("/transaction", @"{'statements': []}");
            // this request will be mode in Promote() after second durable enlistment
            var promoteRequest = MockRequest.PostJson("/transaction/1", @"{'statements': []}");
            var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");

            var secondClientRequest = MockRequest.PostJson("/transaction/2", @"{
                'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");

            // there are no delete requests because those will be made in another app domain

            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    secondClientRequest,
                    MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                },
                {
                    afterPspeFailRequest,
                    MockResponse.Json(201, GenerateInitTransactionResponse(2), "http://foo/db/data/transaction/2")
                },
                {
                    promoteRequest,
                    MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                using (var scope = new TransactionScope())
                {
                    var client = testHarness.CreateAndConnectTransactionalGraphClient();

                    client.Cypher
                        .Match("n")
                        .Return(n => n.Count())
                        .ExecuteWithoutResults();

                    var client2 = testHarness.CreateAndConnectTransactionalGraphClient();

                    client2.Cypher
                        .Match("n")
                        .Return(n => n.Count())
                        .ExecuteWithoutResults();
                }

                // we sleep so that the app domain for the resource manager gets cleaned up
                Thread.Sleep(500);
            }
        }
        public void TransactionJoinedShouldBeTheSame()
        {
            using (var testHarness = new RestTestHarness())
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var transaction = client.BeginTransaction())
                {

                    using (var tran2 = client.BeginTransaction())
                    {
                        Assert.AreSame(GetRealTransaction(tran2), GetRealTransaction(transaction));
                    }
                }
            }
        }
        public void TestTransactionScopeWithSimpleDeserialization()
        {
            const string queryText = @"MATCH (n) RETURN count(n)";
            const string resultColumn = @"{'columns':['count(n)'], 'data':[{'row':[1]}]}";
            var cypherQuery = new CypherQuery(queryText, new Dictionary<string, object>(), CypherResultMode.Projection);
            var cypherApiQuery = new CypherStatementList { new CypherTransactionStatement(cypherQuery, false) };
            var commitRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");

            using (var testHarness = new RestTestHarness
            {
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherApiQuery),
                    MockResponse.Json(201, GenerateInitTransactionResponse(1, resultColumn), "http://foo/db/data/transaction/1")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                using (var msTransaction = new TransactionScope())
                {
                    Assert.IsTrue(client.InTransaction);

                    long total = client.Cypher
                        .Match("(n)")
                        .Return(n => n.Count())
                        .Results
                        .SingleOrDefault();

                    Assert.AreEqual(1, total);

                    msTransaction.Complete();
                }

                Assert.IsFalse(client.InTransaction);
            }
        }
        public void TestTransactionScopeWithComplexDeserialization()
        {
            const string queryText = @"MATCH (dt:DummyTotal) RETURN dt";
            const string resultColumn = @"{'columns':['dt'],'data':[{'row':[{'total':1234}]}]}";
            var cypherQuery = new CypherQuery(queryText, new Dictionary<string, object>(), CypherResultMode.Projection);
            var cypherApiQuery = new CypherStatementList { new CypherTransactionStatement(cypherQuery, false) };
            var commitRequest = MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}");

            using (var testHarness = new RestTestHarness
            {
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherApiQuery),
                    MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1, resultColumn), "http://foo/db/data/transaction/1")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                client.JsonContractResolver = new CamelCasePropertyNamesContractResolver();
                using (var msTransaction = new TransactionScope())
                {
                    Assert.IsTrue(client.InTransaction);

                    var results = client.Cypher.Match("(dt:DummyTotal)")
                        .Return(dt => dt.As<DummyTotal>())
                        .Results
                        .ToList();

                    Assert.AreEqual(1, results.Count());
                    Assert.AreEqual(1234, results.First().Total);

                    msTransaction.Complete();
                }

                Assert.IsFalse(client.InTransaction);
            }
        }
 public void TransactionRollbackInTransactionScope()
 {
     var initTransactionRequest = MockRequest.PostJson("/transaction", @"{
         'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
     var deleteRequest = MockRequest.Delete("/transaction/1");
     using (var testHarness = new RestTestHarness
     {
         {
             initTransactionRequest,
             MockResponse.Json(201, GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
         },
         {
             deleteRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
         }
     })
     {
         var client = testHarness.CreateAndConnectTransactionalGraphClient();
         using (var scope = new TransactionScope())
         {
             client.Cypher
                 .Match("n")
                 .Return(n => n.Count())
                 .ExecuteWithoutResults();
         }
     }
 }
        public void CommitFailsOnPendingAsyncRequests()
        {
            const string queryText = @"MATCH (n) RETURN count(n) as Total";
            const string resultColumn = @"{'columns':['Total'], 'data':[{'row':[1]}]}";

            var cypherQuery = new CypherQuery(queryText, new Dictionary<string, object>(), CypherResultMode.Projection);
            var cypherApiQuery = new CypherStatementList { new CypherTransactionStatement(cypherQuery, false) };

            using (var testHarness = new RestTestHarness(false)
            {
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherApiQuery),
                    MockResponse.Json(201, GenerateInitTransactionResponse(1, resultColumn), "http://foo/db/data/transaction/1")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                var rawClient = (IRawGraphClient) client;
                using (var tran = client.BeginTransaction())
                {
                    rawClient.ExecuteGetCypherResultsAsync<DummyTotal>(cypherQuery);
                    tran.Commit();
                }

            }
        }
        public void CommitFailsOnPendingAsyncRequests()
        {
            const string queryText = @"MATCH (n) RETURN count(n) as Total";
            const string resultColumn = @"{'columns':['Total'], 'data':[{'row':[1]}]}";

            var cypherQuery = new CypherQuery(queryText, new Dictionary<string, object>(), CypherResultMode.Projection);
            var cypherApiQuery = new CypherStatementList { new CypherTransactionStatement(cypherQuery, false) };

            using (var testHarness = new RestTestHarness(false)
            {
                {
                    MockRequest.PostObjectAsJson("/transaction", cypherApiQuery),
                    MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1, resultColumn), "http://foo/db/data/transaction/1")
                }
            })
            {
                var client = testHarness.CreateAndConnectTransactionalGraphClient();
                var rawClient = (IRawGraphClient) client;
                using (var tran = client.BeginTransaction())
                {
                    rawClient.ExecuteGetCypherResultsAsync<DummyTotal>(cypherQuery);
                    var ex = Assert.Throws<InvalidOperationException>(() => tran.Commit());
                    Assert.AreEqual("Cannot commit unless all tasks have been completed", ex.Message);
                }

            }
        }
 public void FailsForRollbackInSuppressMode()
 {
     using (var testHarness = new RestTestHarness())
     {
         var client = testHarness.CreateAndConnectTransactionalGraphClient();
         using (var tran = client.BeginTransaction(TransactionScopeOption.Suppress))
         {
             tran.Rollback();
         }
     }
 }