You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by fl...@apache.org on 2021/10/01 13:52:48 UTC
[tinkerpop] 01/01: TINKERPOP-2556 First try,
tests don't terminate for some reason
This is an automated email from the ASF dual-hosted git repository.
florianhockmann pushed a commit to branch TINKERPOP-2556
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit dad0e36cad6dffef9ab65f582a77dace27e4af1a
Author: Florian Hockmann <fh...@florian-hockmann.de>
AuthorDate: Fri Oct 1 15:52:32 2021 +0200
TINKERPOP-2556 First try, tests don't terminate for some reason
---
.../Driver/Remote/DriverRemoteConnection.cs | 35 ++++++++-
.../Driver/Remote/DriverRemoteTransaction.cs | 69 ++++++++++++++++
gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj | 5 +-
.../Process/Remote/IRemoteConnection.cs | 6 ++
.../src/Gremlin.Net/Process/Traversal/Bytecode.cs | 2 +-
.../IRemoteConnection.cs => Traversal/GraphOp.cs} | 26 +++----
.../Process/Traversal/GraphTraversalSource.cs | 32 ++++++--
.../ITransaction.cs} | 17 ++--
.../GraphTraversalModificationTests.cs | 91 ++++++++++++++++++++++
.../DriverRemoteConnection/GraphTraversalTests.cs | 2 +-
.../Driver/Remote/DriverRemoteTransactionTests.cs | 57 ++++++++++++++
11 files changed, 303 insertions(+), 39 deletions(-)
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
index 006cf8a..63649a1 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
@@ -25,10 +25,10 @@ using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Gremlin.Net.Driver.Messages;
-using Gremlin.Net.Driver;
using Gremlin.Net.Process.Remote;
using Gremlin.Net.Process.Traversal;
using Gremlin.Net.Process.Traversal.Strategy.Decoration;
+using Gremlin.Net.Structure;
namespace Gremlin.Net.Driver.Remote
{
@@ -49,6 +49,10 @@ namespace Gremlin.Net.Driver.Remote
{Tokens.ArgsEvalTimeout, "scriptEvaluationTimeout", Tokens.ArgsBatchSize,
Tokens.RequestId, Tokens.ArgsUserAgent};
+ private readonly string _sessionId;
+ private string Processor => IsSessionBound ? Tokens.ProcessorSession : Tokens.ProcessorTraversal;
+ public bool IsSessionBound => _sessionId != null;
+
/// <summary>
/// Initializes a new <see cref="IRemoteConnection" /> using "g" as the default remote TraversalSource name.
/// </summary>
@@ -91,6 +95,12 @@ namespace Gremlin.Net.Driver.Remote
_traversalSource = traversalSource ?? throw new ArgumentNullException(nameof(traversalSource));
}
+ private DriverRemoteConnection(IGremlinClient client, string traversalSource, Guid sessionId)
+ : this(client, traversalSource)
+ {
+ _sessionId = sessionId.ToString();
+ }
+
/// <summary>
/// Submits <see cref="Bytecode" /> for evaluation to a remote Gremlin Server.
/// </summary>
@@ -107,11 +117,16 @@ namespace Gremlin.Net.Driver.Remote
{
var requestMsg =
RequestMessage.Build(Tokens.OpsBytecode)
- .Processor(Tokens.ProcessorTraversal)
+ .Processor(Processor)
.OverrideRequestId(requestid)
.AddArgument(Tokens.ArgsGremlin, bytecode)
.AddArgument(Tokens.ArgsAliases, new Dictionary<string, string> {{"g", _traversalSource}});
+ if (IsSessionBound)
+ {
+ requestMsg.AddArgument(Tokens.ArgsSession, _sessionId);
+ }
+
var optionsStrategyInst = bytecode.SourceInstructions.Find(
s => s.OperatorName == "withStrategies" && s.Arguments[0] is OptionsStrategy);
if (optionsStrategyInst != null)
@@ -128,6 +143,22 @@ namespace Gremlin.Net.Driver.Remote
return await _client.SubmitAsync<Traverser>(requestMsg.Create()).ConfigureAwait(false);
}
+
+ public ITransaction Tx(GraphTraversalSource g)
+ {
+ var session = new DriverRemoteConnection(_client, _traversalSource, Guid.NewGuid());
+ return new DriverRemoteTransaction(session, g);
+ }
+
+ public async Task CommitAsync()
+ {
+ await SubmitAsync<object, object>(GraphOp.Commit).ConfigureAwait(false);
+ }
+
+ public async Task RollbackAsync()
+ {
+ await SubmitAsync<object, object>(GraphOp.Rollback).ConfigureAwait(false);
+ }
/// <inheritdoc />
public void Dispose()
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTransaction.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTransaction.cs
new file mode 100644
index 0000000..f3be21b
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTransaction.cs
@@ -0,0 +1,69 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Structure;
+
+namespace Gremlin.Net.Driver.Remote
+{
+ public class DriverRemoteTransaction : ITransaction, IDisposable
+ {
+ private readonly DriverRemoteConnection _sessionBasedConnection;
+ private GraphTraversalSource _g;
+
+ public DriverRemoteTransaction(DriverRemoteConnection connection, GraphTraversalSource g)
+ {
+ _sessionBasedConnection = connection;
+ _g = g;
+ }
+
+ public GraphTraversalSource Begin()
+ {
+ if (_g.IsSessionBound)
+ {
+ throw new InvalidOperationException("Transaction already started on this object");
+ }
+ _g = new GraphTraversalSource(_g.TraversalStrategies, _g.Bytecode, _sessionBasedConnection);
+ return _g;
+ }
+
+ public async Task CommitAsync()
+ {
+ await _sessionBasedConnection.CommitAsync().ConfigureAwait(false);
+ Dispose();
+ }
+
+ public async Task RollbackAsync()
+ {
+ await _sessionBasedConnection.RollbackAsync().ConfigureAwait(false);
+ Dispose();
+ }
+
+ public void Dispose()
+ {
+ _sessionBasedConnection.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
index 0f963bb..f9e3fc5 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
+++ b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
@@ -19,8 +19,9 @@ limitations under the License.
<PropertyGroup Label="Build">
<TargetFramework>netstandard2.0</TargetFramework>
- <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
- <GenerateDocumentationFile>true</GenerateDocumentationFile>
+<!-- <TreatWarningsAsErrors>true</TreatWarningsAsErrors>-->
+<!-- <GenerateDocumentationFile>true</GenerateDocumentationFile>-->
+ <LangVersion>8</LangVersion>
</PropertyGroup>
<PropertyGroup Label="Package">
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
index 5393bcb..9502f5d 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
@@ -23,6 +23,7 @@
using System.Threading.Tasks;
using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Structure;
namespace Gremlin.Net.Process.Remote
{
@@ -38,5 +39,10 @@ namespace Gremlin.Net.Process.Remote
/// <param name="bytecode">The <see cref="Bytecode" /> to send.</param>
/// <returns>The <see cref="ITraversal" /> with the results and optional side-effects.</returns>
Task<ITraversal<S, E>> SubmitAsync<S, E>(Bytecode bytecode);
+
+ ITransaction Tx(GraphTraversalSource graphTraversalSource);
+ bool IsSessionBound { get; }
+ Task CommitAsync();
+ Task RollbackAsync();
}
}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
index 7149e8b..cd53a1c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
@@ -38,7 +38,7 @@ namespace Gremlin.Net.Process.Traversal
/// </remarks>
public class Bytecode
{
- private static readonly object[] EmptyArray = new object[0];
+ private static readonly object[] EmptyArray = Array.Empty<object>();
/// <summary>
/// Initializes a new instance of the <see cref="Bytecode" /> class.
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphOp.cs
similarity index 55%
copy from gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
copy to gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphOp.cs
index 5393bcb..b938541 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphOp.cs
@@ -21,22 +21,18 @@
#endregion
-using System.Threading.Tasks;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.Process.Remote
+namespace Gremlin.Net.Process.Traversal
{
- /// <summary>
- /// A simple abstraction of a "connection" to a "server".
- /// </summary>
- public interface IRemoteConnection
+ public static class GraphOp
{
- /// <summary>
- /// Submits <see cref="ITraversal" /> <see cref="Bytecode" /> to a server and returns a
- /// <see cref="ITraversal" />.
- /// </summary>
- /// <param name="bytecode">The <see cref="Bytecode" /> to send.</param>
- /// <returns>The <see cref="ITraversal" /> with the results and optional side-effects.</returns>
- Task<ITraversal<S, E>> SubmitAsync<S, E>(Bytecode bytecode);
+ public static Bytecode Commit { get; } = CreateGraphOp("tx", "commit");
+ public static Bytecode Rollback { get; } = CreateGraphOp("tx", "rollback");
+
+ private static Bytecode CreateGraphOp(string name, object value)
+ {
+ var bytecode = new Bytecode();
+ bytecode.AddSource(name, value);
+ return bytecode;
+ }
}
}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
index db4c521..1dfa4f4 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
@@ -24,6 +24,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Gremlin.Net.Driver.Remote;
using Gremlin.Net.Process.Remote;
using Gremlin.Net.Process.Traversal.Strategy.Decoration;
using Gremlin.Net.Structure;
@@ -38,6 +39,10 @@ namespace Gremlin.Net.Process.Traversal
/// </summary>
public class GraphTraversalSource
{
+ private readonly IRemoteConnection _connection;
+
+ public bool IsSessionBound => _connection is { IsSessionBound: true };
+
/// <summary>
/// Gets or sets the traversal strategies associated with this graph traversal source.
/// </summary>
@@ -71,6 +76,15 @@ namespace Gremlin.Net.Process.Traversal
Bytecode = bytecode;
}
+ public GraphTraversalSource(ICollection<ITraversalStrategy> traversalStrategies, Bytecode bytecode,
+ IRemoteConnection connection)
+ : this(traversalStrategies.Where(strategy => strategy.GetType() != typeof(RemoteStrategy)).ToList(),
+ bytecode)
+ {
+ _connection = connection;
+ TraversalStrategies.Add(new RemoteStrategy(connection));
+ }
+
public GraphTraversalSource With(string key)
{
return With(key, true);
@@ -243,12 +257,19 @@ namespace Gremlin.Net.Process.Traversal
/// <see cref="GraphTraversal{SType, EType}" />.
/// </param>
/// <returns>A <see cref="GraphTraversalSource" /> configured to use the provided <see cref="IRemoteConnection" />.</returns>
- public GraphTraversalSource WithRemote(IRemoteConnection remoteConnection)
+ public GraphTraversalSource WithRemote(IRemoteConnection remoteConnection) =>
+ new GraphTraversalSource(new List<ITraversalStrategy>(TraversalStrategies),
+ new Bytecode(Bytecode), remoteConnection);
+
+ public ITransaction Tx()
{
- var source = new GraphTraversalSource(new List<ITraversalStrategy>(TraversalStrategies),
- new Bytecode(Bytecode));
- source.TraversalStrategies.Add(new RemoteStrategy(remoteConnection));
- return source;
+ // you can't do g.tx().begin().tx() - no child transactions
+ if (IsSessionBound)
+ {
+ throw new InvalidOperationException(
+ "This GraphTraversalSource is already bound to a transaction - child transactions are not supported");
+ }
+ return _connection.Tx(this);
}
/// <summary>
@@ -367,7 +388,6 @@ namespace Gremlin.Net.Process.Traversal
traversal.Bytecode.AddStep("io", file);
return traversal;
}
-
}
#pragma warning restore 1591
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/ITransaction.cs
similarity index 59%
copy from gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
copy to gremlin-dotnet/src/Gremlin.Net/Structure/ITransaction.cs
index 5393bcb..f3dc77e 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/ITransaction.cs
@@ -24,19 +24,12 @@
using System.Threading.Tasks;
using Gremlin.Net.Process.Traversal;
-namespace Gremlin.Net.Process.Remote
+namespace Gremlin.Net.Structure
{
- /// <summary>
- /// A simple abstraction of a "connection" to a "server".
- /// </summary>
- public interface IRemoteConnection
+ public interface ITransaction
{
- /// <summary>
- /// Submits <see cref="ITraversal" /> <see cref="Bytecode" /> to a server and returns a
- /// <see cref="ITraversal" />.
- /// </summary>
- /// <param name="bytecode">The <see cref="Bytecode" /> to send.</param>
- /// <returns>The <see cref="ITraversal" /> with the results and optional side-effects.</returns>
- Task<ITraversal<S, E>> SubmitAsync<S, E>(Bytecode bytecode);
+ GraphTraversalSource Begin();
+ Task CommitAsync();
+ Task RollbackAsync();
}
}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalModificationTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalModificationTests.cs
new file mode 100644
index 0000000..341cde0
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalModificationTests.cs
@@ -0,0 +1,91 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Remote;
+using Gremlin.Net.Process.Traversal;
+using Xunit;
+
+namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
+{
+ public class GraphTraversalModificationTests : IDisposable
+ {
+ private readonly IRemoteConnection _connection = new RemoteConnectionFactory().CreateRemoteConnection("g");
+
+ [Fact]
+ public async Task ShouldSupportRemoteTransactionsCommit()
+ {
+ var g = AnonymousTraversalSource.Traversal().WithRemote(_connection);
+ var tx = g.Tx();
+ var gtx = tx.Begin();
+ await gtx.AddV("person").Property("name", "florian").Promise(t => t.Iterate()).ConfigureAwait(false);
+ await gtx.AddV("person").Property("name", "josh").Promise(t => t.Iterate()).ConfigureAwait(false);
+
+ // Assert within the transaction
+ var count = await gtx.V().Count().Promise(t => t.Next()).ConfigureAwait(false);
+ Assert.Equal(2, count);
+
+ // Now commit changes to test outside of the transaction
+ await tx.CommitAsync().ConfigureAwait(false);
+
+ count = await g.V().Count().Promise(t => t.Next()).ConfigureAwait(false);
+ Assert.Equal(2, count);
+
+ g.V().Count().Next();
+ }
+
+ [Fact]
+ public async Task ShouldSupportRemoteTransactionsRollback()
+ {
+ var g = AnonymousTraversalSource.Traversal().WithRemote(_connection);
+ var tx = g.Tx();
+ var gtx = tx.Begin();
+ await gtx.AddV("person").Property("name", "florian").Promise(t => t.Iterate()).ConfigureAwait(false);
+ await gtx.AddV("person").Property("name", "josh").Promise(t => t.Iterate()).ConfigureAwait(false);
+
+ // Assert within the transaction
+ var count = await gtx.V().Count().Promise(t => t.Next()).ConfigureAwait(false);
+ Assert.Equal(2, count);
+
+ // Now rollback changes to test outside of the transaction
+ await tx.RollbackAsync().ConfigureAwait(false);
+
+ count = await g.V().Count().Promise(t => t.Next()).ConfigureAwait(false);
+ Assert.Equal(2, count);
+
+ g.V().Count().Next();
+ }
+
+ public void Dispose()
+ {
+ EmptyGraph();
+ }
+
+ private void EmptyGraph()
+ {
+ var g = AnonymousTraversalSource.Traversal().WithRemote(_connection);
+ g.V().Drop().Iterate();
+ }
+ }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
index 89597a3..b0347bc 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
@@ -247,4 +247,4 @@ namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
Assert.Equal(6, count);
}
}
-}
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Remote/DriverRemoteTransactionTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Remote/DriverRemoteTransactionTests.cs
new file mode 100644
index 0000000..51f2fc3
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Remote/DriverRemoteTransactionTests.cs
@@ -0,0 +1,57 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using Gremlin.Net.Driver;
+using Gremlin.Net.Driver.Remote;
+using Gremlin.Net.Process.Traversal;
+using Moq;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Driver.Remote
+{
+ public class DriverRemoteTransactionTests
+ {
+ [Fact]
+ public void ShouldNotAllowBeginMoreThanOnce()
+ {
+ var g = AnonymousTraversalSource.Traversal()
+ .WithRemote(new DriverRemoteConnection(Mock.Of<IGremlinClient>()));
+ var tx = g.Tx();
+ tx.Begin();
+
+ Assert.Throws<InvalidOperationException>(() => tx.Begin());
+ }
+
+ [Fact]
+ public void ShouldNotSupportChildTransactions()
+ {
+ var g = AnonymousTraversalSource.Traversal()
+ .WithRemote(new DriverRemoteConnection(Mock.Of<IGremlinClient>()));
+ var tx = g.Tx();
+
+ var gtx = tx.Begin();
+ Assert.Throws<InvalidOperationException>(() => gtx.Tx());
+ }
+ }
+}
\ No newline at end of file