//https://github.com/Readify/Neo4jClient/issues/127
        public async Task ReturnsCorrectError_WhenTransactionIsAutomaticallyRolledBack_ViaNeo4j_2_2_6_Plus(RestTestHarness.Neo4jVersion version)
        {
            /* In 2.2.6 ClientErrors (Constraint Violations etc) were changed to Automatically rollback. This created a 404 error when *we* tried to rollback on an error, as the transaction no longer existed. */
            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, TransactionRestResponseHelper.GenerateCypherErrorResponse(1, "{\"code\":\"Neo.ClientError.Schema.ConstraintViolation\",\"message\":\"Node 19572 already exists with label User and property.\"}"), "http://foo/db/data/transaction/1")
                },
                {
                    rollbackTransactionRequest, MockResponse.Json(404, "{\"results\":[],\"errors\":[{\"code\":\"Neo.ClientError.Transaction.UnknownId\",\"message\":\"Unrecognized transaction id. Transaction may have timed out and been rolled back.\"}]}")
                }
            })
            {
                var client = testHarness.CreateGraphClient(version);
                await client.ConnectAsync();

                using (var transaction = client.BeginTransaction())
                {
                    await Assert.ThrowsAsync <NeoException>(async() => await client.Cypher.Match("n").Return(n => n.Count()).ExecuteWithoutResultsAsync());
                }
            }
        }
        //https://github.com/Readify/Neo4jClient/issues/127
        public async Task ReturnsThe404_WhenVersionIsLessThan_2_2_6(RestTestHarness.Neo4jVersion version)
        {
            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, TransactionRestResponseHelper.GenerateCypherErrorResponse(1, "{\"code\":\"Neo.ClientError.Schema.ConstraintViolation\",\"message\":\"Node 19572 already exists with label User and property.\"}"), "http://foo/db/data/transaction/1")
                },
                {
                    rollbackTransactionRequest, MockResponse.Json(404, "{\"results\":[],\"errors\":[{\"code\":\"Neo.ClientError.Transaction.UnknownId\",\"message\":\"Unrecognized transaction id. Transaction may have timed out and been rolled back.\"}]}")
                }
            })
            {
                var client = testHarness.CreateGraphClient(version);
                await client.ConnectAsync();

                try
                {
                    using (var transaction = client.BeginTransaction())
                    {
                        await client.Cypher.Match("n").Return(n => n.Count()).ExecuteWithoutResultsAsync();
                    }
                }
                catch (Exception ex)
                {
                    Assert.True(ex.Message.Contains("404"));
                }
            }
        }
예제 #3
0
        public async Task 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, TransactionRestResponseHelper.GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    rollbackTransactionRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = await testHarness.CreateAndConnectTransactionalGraphClient();

                using (var transaction = client.BeginTransaction())
                {
                    // dummy query to generate request
                    await client.Cypher
                    .Match("n")
                    .Return(n => n.Count())
                    .ExecuteWithoutResultsAsync();

                    Assert.Equal(
                        new Uri("http://foo/db/data/transaction/1"),
                        ((INeo4jTransaction)((TransactionScopeProxy)transaction).TransactionContext).Endpoint);
                }
            }
        }
        //https://github.com/Readify/Neo4jClient/issues/127
        public async Task ReturnsThe404_WhenVersionIs_2_2_6_Plus_WhenActuallyTimingOut(RestTestHarness.Neo4jVersion version)
        {
            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, TransactionRestResponseHelper.GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    rollbackTransactionRequest, MockResponse.Json(404, "{\"results\":[],\"errors\":[{\"code\":\"Neo.ClientError.Transaction.UnknownId\",\"message\":\"Unrecognized transaction id. Transaction may have timed out and been rolled back.\"}]}")
                }
            })
            {
                var client = testHarness.CreateGraphClient(version);
                await client.ConnectAsync();

                try
                {
                    using (var transaction = client.BeginTransaction())
                    {
                        await client.Cypher.Match("n").Return(n => n.Count()).ExecuteWithoutResultsAsync();
                    }
                    throw new Exception("Should not reach this code, as there is an expected exception.");
                }
                catch (Exception ex)
                {
                    Assert.True(ex.Message.Contains("404"));
                }
            }
        }
예제 #5
0
        public async Task 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, "neo4j");
            var cypherApiQuery = new CypherStatementList {
                new CypherTransactionStatement(cypherQuery)
            };

            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 = await testHarness.CreateAndConnectTransactionalGraphClient();

                var rawClient = (IRawGraphClient)client;
                using (var tran = client.BeginTransaction())
                {
                    await rawClient.ExecuteGetCypherResultsAsync <DummyTotal>(cypherQuery);

                    var ex = await Assert.ThrowsAsync <InvalidOperationException>(async() => await tran.CommitAsync());

                    Assert.Equal("Cannot commit unless all tasks have been completed", ex.Message);
                }
            }
        }
예제 #6
0
        public async Task RollbackWithoutRequestsShouldNotGenerateMessage()
        {
            var initTransactionRequest     = MockRequest.PostJson("/transaction", @"{'statements': []}");
            var rollbackTransactionRequest = MockRequest.Delete("/transaction/1");

            using (var testHarness = new RestTestHarness
            {
                {
                    initTransactionRequest,
                    MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    rollbackTransactionRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            }.ShouldNotBeCalled(initTransactionRequest, rollbackTransactionRequest))
            {
                var client = await testHarness.CreateAndConnectTransactionalGraphClient();

                using (var transaction = client.BeginTransaction())
                {
                    // no requests
                    await transaction.RollbackAsync();
                }
            }
        }
예제 #7
0
        public async Task 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, "neo4j");
            var cypherApiQuery = new CypherStatementList {
                new CypherTransactionStatement(cypherQuery)
            };
            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 = await testHarness.CreateAndConnectTransactionalGraphClient();

                var rawClient = (IRawGraphClient)client;
                using (var tran = client.BeginTransaction())
                {
                    var totalObj = rawClient.ExecuteGetCypherResultsAsync <DummyTotal>(cypherQuery).Result.Single();
                    Assert.Equal(1, totalObj.Total);
                    await tran.CommitAsync();
                }
            }
        }
예제 #8
0
        public async Task 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, TransactionRestResponseHelper.GenerateInitTransactionResponse(1), "http://foo/db/data/transaction/1")
                },
                {
                    commitRequest, MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                }
            })
            {
                var client = await testHarness.CreateAndConnectTransactionalGraphClient();

                using (var transaction = client.BeginTransaction())
                {
                    // dummy query to generate request
                    await client.Cypher
                    .Match("n")
                    .Return(n => n.Count())
                    .ExecuteWithoutResultsAsync();

                    await transaction.CommitAsync();
                }
            }
        }
예제 #9
0
                public async Task UsesTheSetDatabase()
                {
                    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);
                    var keepAliveTransactionRequest = MockRequest.PostJson($"/db/{database}/tx/1", 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 },
                        { keepAliveTransactionRequest, 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.KeepAliveAsync();
                        }
                    }
                }
예제 #10
0
                public async Task UsesTheDefaultDatabase_WhenNoneSet()
                {
                    const string database = "neo4j";

                    var initTransactionRequest   = MockRequest.PostJson($"/db/{database}/tx", "{'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
                    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 }
                    })
                    {
                        var client = await testHarness.CreateAndConnectTransactionalGraphClient(RestTestHarness.Neo4jVersion.Neo40);

                        using (var transaction = client.BeginTransaction())
                        {
                            // 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.CommitAsync());

                            ex.Should().NotBeNull();
                        }
                    }
                }
예제 #11
0
            public async Task QueryInTransaction_ThrowsExceptionWhen_ExecutingCypherQueryAgainstADifferentDatabaseName()
            {
                const string database = "neo4jclient";

                var initTransactionRequest   = MockRequest.PostJson($"/db/{database}/tx", "{'statements': [{'statement': 'MATCH n\r\nRETURN count(n)', 'resultDataContents':[], 'parameters': {}}]}");
                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 }
                })
                {
                    var client = await testHarness.CreateAndConnectTransactionalGraphClient(RestTestHarness.Neo4jVersion.Neo40);

                    using (var transaction = client.BeginTransaction(TransactionScopeOption.Join, null, database))
                    {
                        // dummy query to generate request
                        var ex = Assert.Throws <InvalidOperationException>(
                            () => client.Cypher
                            .WithDatabase("neo4j")
                            .Match("n")
                            .Return(n => n.Count()));

                        ex.Should().NotBeNull();
                    }
                }
            }
예제 #12
0
        public async Task 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, TransactionRestResponseHelper.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 = await testHarness.CreateAndConnectTransactionalGraphClient();

                using (var transaction = client.BeginTransaction())
                {
                    // dummy query to generate request
                    await client.Cypher
                    .Match("n")
                    .Return(n => n.Count())
                    .ExecuteWithoutResultsAsync();

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

                    Assert.Equal(count.First(), 0);
                }
            }
        }
예제 #13
0
        public async Task AsyncRequestsInTransactionShouldBeExecutedInOrder()
        {
            const string queryTextBase    = @"MATCH (n) RETURN {0} as Total";
            const string resultColumnBase = @"{{'columns':['Total'], 'data':[{{'row':[{0}]}}]}}";
            const int    asyncRequests    = 15;

            var queries     = new CypherQuery[asyncRequests];
            var apiQueries  = new CypherStatementList[asyncRequests];
            var responses   = new MockResponse[asyncRequests];
            var testHarness = new RestHarnessWithCounter();

            for (int i = 0; i < asyncRequests; i++)
            {
                queries[i] = new CypherQuery(string.Format(queryTextBase, i), new Dictionary <string, object>(),
                                             CypherResultMode.Projection, "neo4j");
                apiQueries[i] = new CypherStatementList {
                    new CypherTransactionStatement(queries[i])
                };
                responses[i] = MockResponse.Json(200,
                                                 @"{'results':[" + string.Format(resultColumnBase, i) + @"], 'errors':[] }");
                if (i > 0)
                {
                    testHarness.Add(MockRequest.PostObjectAsJson("/transaction/1", apiQueries[i]), responses[i]);
                }
            }

            testHarness.Add(
                MockRequest.PostObjectAsJson("/transaction", apiQueries[0]),
                MockResponse.Json(201, TransactionRestResponseHelper.GenerateInitTransactionResponse(1, string.Format(resultColumnBase, 0)),
                                  "http://foo/db/data/transaction/1")
                );
            testHarness.Add(
                MockRequest.PostJson("/transaction/1/commit", @"{'statements': []}"),
                MockResponse.Json(200, @"{'results':[], 'errors':[] }")
                );
            try
            {
                var client = await testHarness.CreateAndConnectTransactionalGraphClient();

                var rawClient = (IRawGraphClient)client;
                var tasks     = new Task[asyncRequests];
                using (var tran = client.BeginTransaction())
                {
                    for (int i = 0; i < asyncRequests; i++)
                    {
                        int tmpResult = i;
                        tasks[i] = rawClient.ExecuteGetCypherResultsAsync <DummyTotal>(queries[i]).ContinueWith(task =>
                        {
                            Assert.Equal(tmpResult, task.Result.Single().Total);
                        });
                    }

                    await Task.WhenAll(tasks);

                    await tran.CommitAsync();
                }
            }
            finally
            {
                testHarness.Dispose();
            }

            // check that we have a total order
            Assert.Equal(asyncRequests, testHarness.Queue.Count);
            int lastElement = -1;

            for (int i = 0; i < asyncRequests; i++)
            {
                int headItem;
                Assert.True(testHarness.Queue.TryDequeue(out headItem));
                headItem.Should().BeGreaterThan(lastElement);
                lastElement = headItem;
            }
        }