You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by xi...@apache.org on 2023/01/11 19:41:15 UTC

[tinkerpop] branch master updated: Adds tests for user agent feature (#1923)

This is an automated email from the ASF dual-hosted git repository.

xiazcy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/master by this push:
     new f1df1a670c Adds tests for user agent feature (#1923)
f1df1a670c is described below

commit f1df1a670c9fb2cfcab27df6b8a402437cd900ff
Author: Cole Greer <11...@users.noreply.github.com>
AuthorDate: Wed Jan 11 11:41:09 2023 -0800

    Adds tests for user agent feature (#1923)
    
    Adds a test to each GLV which uses gremlin-socket-server to confirm that
    the driver is sending the correct user agent. Also adds a test which verifies
    that the user agent is not sent if it has been disabled in the driver config.
---
 gremlin-dotnet/src/Gremlin.Net/Process/Utils.cs    |  3 ++
 .../src/Gremlin.Net/Properties/AssemblyInfo.cs     |  1 +
 .../GremlinClientBehaviorIntegrationTests.cs       | 30 +++++++++++-
 .../Gremlin.Net.IntegrationTest.csproj             |  3 ++
 gremlin-go/driver/client_test.go                   | 55 ++++++++++++++++++++++
 .../javascript/gremlin-javascript/test/helper.js   | 20 ++++++--
 .../test/integration/client-behavior-tests.js      | 15 ++++++
 gremlin-python/src/main/python/tests/conftest.py   | 36 ++++++++++----
 .../driver/test_web_socket_client_behavior.py      | 26 ++++++++++
 .../socket/server/TestWSGremlinInitializer.java    |  5 +-
 10 files changed, 179 insertions(+), 15 deletions(-)

diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Utils.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Utils.cs
index 8e13b2d25a..be76feac9f 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Utils.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Utils.cs
@@ -34,6 +34,9 @@ namespace Gremlin.Net.Process
     /// </summary>
     internal static class Utils
     {
+        /// <summary>
+        /// The user agent which is sent with connection requests if enabled.
+        /// </summary>
         public static string UserAgent => _userAgent ??= GenerateUserAgent();
         private static string? _userAgent;
         
diff --git a/gremlin-dotnet/src/Gremlin.Net/Properties/AssemblyInfo.cs b/gremlin-dotnet/src/Gremlin.Net/Properties/AssemblyInfo.cs
index 4351b0e902..e6c1a7e784 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Properties/AssemblyInfo.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Properties/AssemblyInfo.cs
@@ -24,4 +24,5 @@
 using System.Runtime.CompilerServices;
 
 [assembly: InternalsVisibleTo("Gremlin.Net.UnitTest, PublicKey=00240000048000009400000006020000002400005253413100040000010001009bbf7a5b9966d9207d8abb9d3d3e98f5e387b292742cfb791dc657357221c3ac9b38ab6dab89630dc8edb3cde84a107f493d192116a934afa463355eefd58b82fd08dc2616ee6074a74bf5845652864746e285bd04e2e1a87921e8e2c383d1b302e7bee1fd7cdab5fe2bbed8c6677624d63433548d43a873ab5650ed96fb0687")]
+[assembly: InternalsVisibleTo("Gremlin.Net.IntegrationTest, PublicKey=00240000048000009400000006020000002400005253413100040000010001009bbf7a5b9966d9207d8abb9d3d3e98f5e387b292742cfb791dc657357221c3ac9b38ab6dab89630dc8edb3cde84a107f493d192116a934afa463355eefd58b82fd08dc2616ee6074a74bf5845652864746e285bd04e2e1a87921e8e2c383d1b302e7bee1fd7cdab5fe2bbed8c6677624d63433548d43a873ab5650ed96fb0687")]
 [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientBehaviorIntegrationTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientBehaviorIntegrationTests.cs
index 6fc4f16fd9..b6354d0409 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientBehaviorIntegrationTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/GremlinClientBehaviorIntegrationTests.cs
@@ -22,7 +22,6 @@
 #endregion
 
 using System;
-using System.Linq;
 using System.Threading.Tasks;
 using Gremlin.Net.Driver;
 using Gremlin.Net.Driver.Exceptions;
@@ -68,7 +67,7 @@ namespace Gremlin.Net.IntegrationTest.Driver
             var poolSettings = new ConnectionPoolSettings {PoolSize = 1};
             
             var gremlinServer = new GremlinServer(TestHost, Settings.Port);
-            var gremlinClient = new GremlinClient(gremlinServer, messageSerializer: Serializer,
+            using var gremlinClient = new GremlinClient(gremlinServer, messageSerializer: Serializer,
                 connectionPoolSettings: poolSettings, sessionId: sessionId);
 
             Assert.Equal(1, gremlinClient.NrConnections);
@@ -84,5 +83,32 @@ namespace Gremlin.Net.IntegrationTest.Driver
             Assert.NotNull(response2);
             Assert.Equal(1, gremlinClient.NrConnections);
         }
+
+        [Fact]
+        public async Task ShouldIncludeUserAgentInHandshakeRequest()
+        {
+            var gremlinServer = new GremlinServer(TestHost, Settings.Port);
+            using var gremlinClient = new GremlinClient(gremlinServer, messageSerializer: Serializer);
+
+            //verify that the server received the correct user agent during connection setup.
+            var userAgentResponse = await gremlinClient.SubmitWithSingleResultAsync<String>(RequestMessage.Build("1")
+                .OverrideRequestId(Settings.UserAgentRequestId).Create());
+            Assert.Equal(Gremlin.Net.Process.Utils.UserAgent, userAgentResponse);
+        }
+        
+        [Fact]
+        public async Task ShouldNotIncludeUserAgentInHandshakeRequestIfDisabled()
+        {
+            var poolSettings = new ConnectionPoolSettings {EnableUserAgentOnConnect = false};
+
+            var gremlinServer = new GremlinServer(TestHost, Settings.Port);
+            using var gremlinClient = new GremlinClient(gremlinServer, messageSerializer: Serializer,
+                connectionPoolSettings: poolSettings);
+
+            //verify that the server did not receive any user agent.
+            var userAgentResponse = await gremlinClient.SubmitWithSingleResultAsync<String>(RequestMessage.Build("1")
+                .OverrideRequestId(Settings.UserAgentRequestId).Create());
+            Assert.Equal("", userAgentResponse);
+        }
     }
 }
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
index 867672db45..58f670246a 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
@@ -2,6 +2,9 @@
   <PropertyGroup>
     <TargetFramework>net6.0</TargetFramework>
     <Nullable>enable</Nullable>
+    <AssemblyOriginatorKeyFile>../../build/tinkerpop.snk</AssemblyOriginatorKeyFile>
+    <SignAssembly>true</SignAssembly>
+    <PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
   </PropertyGroup>
   <ItemGroup>
     <None Update="appsettings.json">
diff --git a/gremlin-go/driver/client_test.go b/gremlin-go/driver/client_test.go
index a09506d787..fdda8eb614 100644
--- a/gremlin-go/driver/client_test.go
+++ b/gremlin-go/driver/client_test.go
@@ -133,6 +133,61 @@ func TestClientAgainstSocketServer(t *testing.T) {
 		client.Close()
 	})
 
+	/**
+	 * Tests that client is correctly sending user agent during web socket handshake by having the server return
+	 * the captured user agent.
+	 */
+	t.Run("Should include user agent in handshake request", func(t *testing.T) {
+		skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable)
+		client, err := NewClient(testSocketServerUrl)
+		assert.Nil(t, err)
+		assert.NotNil(t, client)
+
+		resultSet, err := client.Submit("1", map[string]interface{}{"requestId": settings.USER_AGENT_REQUEST_ID})
+		assert.Nil(t, err)
+		assert.NotNil(t, resultSet)
+
+		result, ok, err := resultSet.One()
+		assert.Nil(t, err)
+		assert.True(t, ok)
+		assert.NotNil(t, result)
+
+		userAgentResponse := result.GetString()
+		assert.Equal(t, userAgent, userAgentResponse)
+
+		client.Close()
+	})
+
+	/**
+	 * Tests that no user agent (other than the default one provided by gorilla) is sent to server when
+	 * that behaviour is disabled.
+	 */
+	t.Run("Should not include user agent in handshake request if disabled", func(t *testing.T) {
+		skipTestsIfNotEnabled(t, integrationTestSuiteName, testNoAuthEnable)
+		client, err := NewClient(testSocketServerUrl,
+			func(settings *ClientSettings) {
+				settings.EnableUserAgentOnConnect = false
+			})
+		assert.Nil(t, err)
+		assert.NotNil(t, client)
+
+		resultSet, err := client.Submit("1", map[string]interface{}{"requestId": settings.USER_AGENT_REQUEST_ID})
+		assert.Nil(t, err)
+		assert.NotNil(t, resultSet)
+
+		result, ok, err := resultSet.One()
+		assert.Nil(t, err)
+		assert.True(t, ok)
+		assert.NotNil(t, result)
+
+		userAgentResponse := result.GetString()
+		//If the gremlin user agent is disabled, the underlying web socket library reverts to sending its default user agent
+		//during connection requests.
+		assert.Contains(t, userAgentResponse, "Go-http-client/")
+
+		client.Close()
+	})
+
 	/**
 	 * Note: This test currently fails due to race condition check in go test and is only included for demonstration
 	 * purposes. See https://issues.apache.org/jira/browse/TINKERPOP-2845.
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
index 60040d0cbf..6232570f68 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/helper.js
@@ -78,11 +78,9 @@ exports.getSessionClient = function getSessionClient(traversalSource) {
   });
 };
 
-exports.getGremlinSocketServerClient = function getGremlinSocketServerClient(traversalSource) {
-  const settings = exports.getGremlinSocketServerSettings();
-  const url = socketServerUrl + settings.PORT + '/gremlin';
+function getMimeTypeFromSocketServerSettings(socketServerSettings) {
   let mimeType;
-  switch(settings.SERIALIZER) {
+  switch(socketServerSettings.SERIALIZER) {
     case "GraphSONV2":
       mimeType = 'application/vnd.gremlin-v2.0+json';
       break;
@@ -94,9 +92,23 @@ exports.getGremlinSocketServerClient = function getGremlinSocketServerClient(tra
       mimeType = 'application/vnd.graphbinary-v1.0';
       break;
   }
+  return mimeType;
+}
+
+exports.getGremlinSocketServerClient = function getGremlinSocketServerClient(traversalSource) {
+  const settings = exports.getGremlinSocketServerSettings();
+  const url = socketServerUrl + settings.PORT + '/gremlin';
+  let mimeType = getMimeTypeFromSocketServerSettings(settings)
   return new Client(url, { traversalSource, mimeType });
 };
 
+exports.getGremlinSocketServerClientNoUserAgent = function getGremlinSocketServerClient(traversalSource) {
+  const settings = exports.getGremlinSocketServerSettings();
+  const url = socketServerUrl + settings.PORT + '/gremlin';
+  let mimeType = getMimeTypeFromSocketServerSettings(settings)
+  return new Client(url, { traversalSource, mimeType, enableUserAgentOnConnect:false });
+};
+
 exports.getGremlinSocketServerSettings = function getGremlinSocketServerSettings() {
   const settings = yaml.load(fs.readFileSync(sockerServerConfigPath, 'utf8'));
   return settings;
diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-behavior-tests.js b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-behavior-tests.js
index 311b809a42..55236e05ad 100644
--- a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-behavior-tests.js
+++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/integration/client-behavior-tests.js
@@ -21,6 +21,7 @@
 
 const assert = require('assert');
 const helper = require('../helper');
+const {getUserAgent} = require("../../lib/utils");
 
 let client;
 let settings;
@@ -49,5 +50,19 @@ describe('Client', function () {
             console.log("result received: "+JSON.stringify(result));
             assert.ok(result);
         });
+        it('should include user agent in handshake request', async function () {
+            let result = await client.submit('1', null, {requestId: settings.USER_AGENT_REQUEST_ID});
+
+            assert.strictEqual(result.first(), getUserAgent());
+        });
+        it('should not include user agent in handshake request if disabled', async function () {
+            let noUserAgentClient = helper.getGremlinSocketServerClientNoUserAgent('gmodern');
+            let result = await noUserAgentClient.submit('1', null,
+                {requestId: settings.USER_AGENT_REQUEST_ID});
+
+            assert.strictEqual(result.first(), "");
+
+            await noUserAgentClient.close();
+        });
     });
 });
diff --git a/gremlin-python/src/main/python/tests/conftest.py b/gremlin-python/src/main/python/tests/conftest.py
index 224adcb915..9fa82852cf 100644
--- a/gremlin-python/src/main/python/tests/conftest.py
+++ b/gremlin-python/src/main/python/tests/conftest.py
@@ -93,18 +93,38 @@ def client(request):
 
 
 @pytest.fixture
-def socket_server_client(request, socket_server_settings):
-    url = gremlin_socket_server_url.format(socket_server_settings["PORT"])
+def gremlin_socket_server_serializer(socket_server_settings):
     if socket_server_settings["SERIALIZER"] == "GraphBinaryV1":
-        ser = serializer.GraphBinarySerializersV1()
+        return serializer.GraphBinarySerializersV1()
     elif socket_server_settings["SERIALIZER"] == "GraphSONV2":
-        ser = serializer.GraphSONSerializersV2d0()
+        return serializer.GraphSONSerializersV2d0()
     elif socket_server_settings["SERIALIZER"] == "GraphSONV3":
-        ser = serializer.GraphSONSerializersV3d0()
+        return serializer.GraphSONSerializersV3d0()
+    else:
+        return serializer.GraphBinarySerializersV1()
+
+
+@pytest.fixture
+def socket_server_client(request, socket_server_settings, gremlin_socket_server_serializer):
+    url = gremlin_socket_server_url.format(socket_server_settings["PORT"])
+    try:
+        client = Client(url, 'g', pool_size=1, message_serializer=gremlin_socket_server_serializer)
+    except OSError:
+        pytest.skip('Gremlin Socket Server is not running')
     else:
-        ser = serializer.GraphBinarySerializersV1()
+        def fin():
+            client.close()
+
+        request.addfinalizer(fin)
+        return client
+
+
+@pytest.fixture
+def socket_server_client_no_user_agent(request, socket_server_settings, gremlin_socket_server_serializer):
+    url = gremlin_socket_server_url.format(socket_server_settings["PORT"])
     try:
-        client = Client(url, 'g', pool_size=1, message_serializer=ser)
+        client = Client(url, 'g', pool_size=1, message_serializer=gremlin_socket_server_serializer,
+                        enable_user_agent_on_connect=False)
     except OSError:
         pytest.skip('Gremlin Socket Server is not running')
     else:
@@ -116,7 +136,7 @@ def socket_server_client(request, socket_server_settings):
 
 
 @pytest.fixture
-def socket_server_settings(request):
+def socket_server_settings():
     with open(gremlin_socket_server_config_path, mode="rb") as file:
         settings = yaml.safe_load(file)
     return settings
diff --git a/gremlin-python/src/main/python/tests/driver/test_web_socket_client_behavior.py b/gremlin-python/src/main/python/tests/driver/test_web_socket_client_behavior.py
index a6ad2c5da9..7a3c1dac53 100644
--- a/gremlin-python/src/main/python/tests/driver/test_web_socket_client_behavior.py
+++ b/gremlin-python/src/main/python/tests/driver/test_web_socket_client_behavior.py
@@ -19,6 +19,11 @@
 
 __author__ = 'Cole Greer (cole@colegreer.ca)'
 
+import re
+
+from gremlin_python.driver import useragent
+
+
 # Note: This test demonstrates different behavior in response to a server sending a close frame than the other GLV's.
 # Other GLV's will respond to this by trying to reconnect. This test is also demonstrating incorrect behavior of
 # client.is_closed() as it appears unaware that the event loop is dead.
@@ -40,3 +45,24 @@ def test_does_not_create_new_connection_if_closed_by_server(socket_server_client
         assert str(err) == "Event loop is closed"
 
     assert not socket_server_client.is_closed()
+
+
+# Tests that client is correctly sending user agent during web socket handshake by having the server return
+# the captured user agent.
+def test_should_include_user_agent_in_handshake_request(socket_server_client, socket_server_settings):
+    user_agent_response = socket_server_client.submit(
+        "1", request_options={'requestId': socket_server_settings["USER_AGENT_REQUEST_ID"]}).one()[0]
+
+    assert user_agent_response == useragent.userAgent
+
+
+# Tests that no user agent (other than the default one provided by aiohttp) is sent to server when that
+# behaviour is disabled.
+def test_should_not_include_user_agent_in_handshake_request_if_disabled(socket_server_client_no_user_agent,
+                                                                        socket_server_settings):
+    user_agent_response = socket_server_client_no_user_agent.submit(
+        "1", request_options={'requestId': socket_server_settings["USER_AGENT_REQUEST_ID"]}).one()[0]
+
+    # If the gremlin user agent is disabled, the underlying web socket library reverts to sending its default user agent
+    # during connection requests.
+    assert re.search("^Python/(\d\.)*\d aiohttp/(\d\.)*\d$", user_agent_response)
diff --git a/gremlin-tools/gremlin-socket-server/src/main/java/org/apache/tinkerpop/gremlin/socket/server/TestWSGremlinInitializer.java b/gremlin-tools/gremlin-socket-server/src/main/java/org/apache/tinkerpop/gremlin/socket/server/TestWSGremlinInitializer.java
index f1a8dde2af..2f28799122 100644
--- a/gremlin-tools/gremlin-socket-server/src/main/java/org/apache/tinkerpop/gremlin/socket/server/TestWSGremlinInitializer.java
+++ b/gremlin-tools/gremlin-socket-server/src/main/java/org/apache/tinkerpop/gremlin/socket/server/TestWSGremlinInitializer.java
@@ -162,7 +162,10 @@ public class TestWSGremlinInitializer extends TestChannelizers.TestWebSocketServ
          * @throws SerializationException
          */
         private ByteBuf returnSimpleBinaryResponse(final UUID requestID, String message) throws SerializationException {
-            return SERIALIZER.serializeResponseAsBinary(ResponseMessage.build(requestID).result(message).create(), ByteBufAllocator.DEFAULT);
+            //Need to package message in a list of size 1 as some GLV's serializers require all messages to be in a list
+            final List<String> messageList = new ArrayList<>(1);
+            messageList.add(message);
+            return SERIALIZER.serializeResponseAsBinary(ResponseMessage.build(requestID).result(messageList).create(), ByteBufAllocator.DEFAULT);
         }
 
         /**