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

yihaochen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-python.git


The following commit(s) were added to refs/heads/master by this push:
     new 6c29a96  Add Neo4j plugin. (#312)
6c29a96 is described below

commit 6c29a96423a8b0f768fb7a0a4ff1528ca818b44a
Author: Jedore <[email protected]>
AuthorDate: Mon Jun 19 00:20:22 2023 +0800

    Add Neo4j plugin. (#312)
    
    * Add Neo4j plugin.
    
    ---------
    
    Co-authored-by: 吴晟 Wu Sheng <[email protected]>
---
 CHANGELOG.md                                    |   2 +
 docs/en/setup/Plugins.md                        |   3 +
 poetry.lock                                     |  17 +++
 pyproject.toml                                  |   1 +
 skywalking/__init__.py                          |   1 +
 skywalking/plugins/sw_neo4j.py                  |  96 ++++++++++++++
 tests/plugin/data/sw_neo4j/__init__.py          |  16 +++
 tests/plugin/data/sw_neo4j/docker-compose.yml   |  84 ++++++++++++
 tests/plugin/data/sw_neo4j/expected.data.yml    | 168 ++++++++++++++++++++++++
 tests/plugin/data/sw_neo4j/services/__init__.py |  16 +++
 tests/plugin/data/sw_neo4j/services/consumer.py |  32 +++++
 tests/plugin/data/sw_neo4j/services/provider.py |  55 ++++++++
 tests/plugin/data/sw_neo4j/test_neo4j.py        |  36 +++++
 13 files changed, 527 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4f39774..453a1c2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,8 @@
 ## Change Logs
 
 ### 1.1.0
+- Plugins:
+  - Add neo4j plugin.(#312)
 
 - Fixes:
   - Fix unexpected 'No active span' IllegalStateError (#311)
diff --git a/docs/en/setup/Plugins.md b/docs/en/setup/Plugins.md
index cf4dac5..ca0fc38 100644
--- a/docs/en/setup/Plugins.md
+++ b/docs/en/setup/Plugins.md
@@ -33,6 +33,7 @@ or a limitation of SkyWalking auto-instrumentation (welcome 
to contribute!)
 | [kafka-python](https://kafka-python.readthedocs.io) | Python >=3.7 - 
['2.0'];  | `sw_kafka` |
 | [loguru](https://pypi.org/project/loguru/) | Python >=3.7 - ['0.6.0', 
'0.7.0'];  | `sw_loguru` |
 | [mysqlclient](https://mysqlclient.readthedocs.io/) | Python >=3.7 - 
['2.1.*'];  | `sw_mysqlclient` |
+| [neo4j](https://neo4j.com/docs/python-manual/5/) | Python >=3.7 - ['5.*'];  
| `sw_neo4j` |
 | [psycopg[binary]](https://www.psycopg.org/) | Python >=3.11 - ['3.1.*']; 
Python >=3.7 - ['3.0.18', '3.1.*'];  | `sw_psycopg` |
 | [psycopg2-binary](https://www.psycopg.org/) | Python >=3.10 - NOT SUPPORTED 
YET; Python >=3.7 - ['2.9'];  | `sw_psycopg2` |
 | [pymongo](https://pymongo.readthedocs.io) | Python >=3.7 - ['3.11.*'];  | 
`sw_pymongo` |
@@ -53,6 +54,8 @@ in SkyWalking currently. Celery clients can use whatever 
protocol they want.
 - While Falcon is instrumented, only Hug is tested.
 Hug is believed to be abandoned project, use this plugin with a bit more 
caution.
 Instead of Hug, plugin test should move to test actual Falcon.
+- The Neo4j plugin integrates neo4j python driver 5.x.x versions which
+support both Neo4j 5 and 4.4 DBMS.
 - The websocket instrumentation only traces client side connection handshake,
 the actual message exchange (send/recv) is not traced since injecting headers 
to socket message
 body is the only way to propagate the trace context, which requires 
customization of message structure
diff --git a/poetry.lock b/poetry.lock
index a86b6c4..ec1db06 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1958,6 +1958,23 @@ files = [
     {file = "mysqlclient-2.1.1.tar.gz", hash = 
"sha256:828757e419fb11dd6c5ed2576ec92c3efaa93a0f7c39e263586d1ee779c3d782"},
 ]
 
+[[package]]
+name = "neo4j"
+version = "5.9.0"
+description = "Neo4j Bolt driver for Python"
+optional = false
+python-versions = ">=3.7"
+files = [
+    {file = "neo4j-5.9.0.tar.gz", hash = 
"sha256:b0abc0065f616bfd8230a48b1f6c91f9aacd7e2aea76d72d09a745ae169cf4da"},
+]
+
+[package.dependencies]
+pytz = "*"
+
+[package.extras]
+numpy = ["numpy (>=1.7.0,<2.0.0)"]
+pandas = ["numpy (>=1.7.0,<2.0.0)", "pandas (>=1.1.0,<3.0.0)"]
+
 [[package]]
 name = "packaging"
 version = "23.0"
diff --git a/pyproject.toml b/pyproject.toml
index 5833e70..e353971 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -132,6 +132,7 @@ websockets = "^10.4"
 loguru = "^0.6.0"
 httpx = "^0.23.3"
 confluent-kafka = "^2.0.2"
+neo4j = "^5.9.0"
 
 [tool.poetry.group.lint.dependencies]
 pylint = '2.13.9'
diff --git a/skywalking/__init__.py b/skywalking/__init__.py
index 75b5e27..1ed0c2b 100644
--- a/skywalking/__init__.py
+++ b/skywalking/__init__.py
@@ -38,6 +38,7 @@ class Component(Enum):
     RabbitmqConsumer = 53
     Elasticsearch = 47
     HBase = 94
+    Neo4j = 112
     Urllib3 = 7006
     Sanic = 7007
     AioHttp = 7008
diff --git a/skywalking/plugins/sw_neo4j.py b/skywalking/plugins/sw_neo4j.py
new file mode 100644
index 0000000..a135bc2
--- /dev/null
+++ b/skywalking/plugins/sw_neo4j.py
@@ -0,0 +1,96 @@
+#
+# 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.
+#
+
+import json
+
+from skywalking import Layer, Component, config
+from skywalking.trace.context import get_context
+from skywalking.trace.tags import TagDbType, TagDbInstance, TagDbStatement, 
TagDbSqlParameters
+
+link_vector = ['https://neo4j.com/docs/python-manual/5/']
+support_matrix = {
+    'neo4j': {
+        '>=3.7': ['5.*'],
+    }
+}
+note = """The Neo4j plugin integrates neo4j python driver 5.x.x versions which
+support both Neo4j 5 and 4.4 DBMS."""
+
+
+def install():
+    from neo4j import AsyncSession, Session
+    from neo4j._sync.work.transaction import TransactionBase
+    from neo4j._async.work.transaction import AsyncTransactionBase
+
+    _session_run = Session.run
+    _async_session_run = AsyncSession.run
+    _transaction_run = TransactionBase.run
+    _async_transaction_run = AsyncTransactionBase.run
+
+    def _archive_span(span, database, query, parameters, **kwargs):
+        span.layer = Layer.Database
+        span.tag(TagDbType('Neo4j'))
+        span.tag(TagDbInstance(database or ''))
+        span.tag(TagDbStatement(query))
+
+        parameters = dict(parameters or {}, **kwargs)
+        if config.plugin_sql_parameters_max_length and parameters:
+            parameter = json.dumps(parameters, ensure_ascii=False)
+            max_len = config.plugin_sql_parameters_max_length
+            parameter = f'{parameter[0:max_len]}...' if len(
+                parameter) > max_len else parameter
+            span.tag(TagDbSqlParameters(f'[{parameter}]'))
+
+    def get_peer(address):
+        return f'{address.host}:{address.port}'
+
+    def _sw_session_run(self, query, parameters, **kwargs):
+        with get_context().new_exit_span(
+                op='Neo4j/Session/run',
+                peer=get_peer(self._pool.address),
+                component=Component.Neo4j) as span:
+            _archive_span(span, self._config.database, query, parameters, 
**kwargs)
+            return _session_run(self, query, parameters, **kwargs)
+
+    def _sw_transaction_run(self, query, parameters=None, **kwargs):
+        with get_context().new_exit_span(
+                op='Neo4j/Transaction/run',
+                peer=get_peer(self._connection.unresolved_address),
+                component=Component.Neo4j) as span:
+            _archive_span(span, self._database, query, parameters, **kwargs)
+            return _transaction_run(self, query, parameters, **kwargs)
+
+    async def _sw_async_session_run(self, query, parameters, **kwargs):
+        with get_context().new_exit_span(
+                op='Neo4j/AsyncSession/run',
+                peer=get_peer(self._pool.address),
+                component=Component.Neo4j) as span:
+            _archive_span(span, self._config.database, query, parameters, 
**kwargs)
+            return await _async_session_run(self, query, parameters, **kwargs)
+
+    async def _sw_async_transaction_run(self, query, parameters, **kwargs):
+        with get_context().new_exit_span(
+                op='Neo4j/AsyncTransaction/run',
+                peer=get_peer(self._connection.unresolved_address),
+                component=Component.Neo4j) as span:
+            _archive_span(span, self._database, query, parameters, **kwargs)
+            return await _async_transaction_run(self, query, parameters, 
**kwargs)
+
+    Session.run = _sw_session_run
+    AsyncSession.run = _sw_async_session_run
+    TransactionBase.run = _sw_transaction_run
+    AsyncTransactionBase.run = _sw_async_transaction_run
diff --git a/tests/plugin/data/sw_neo4j/__init__.py 
b/tests/plugin/data/sw_neo4j/__init__.py
new file mode 100644
index 0000000..b1312a0
--- /dev/null
+++ b/tests/plugin/data/sw_neo4j/__init__.py
@@ -0,0 +1,16 @@
+#
+# 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.
+#
diff --git a/tests/plugin/data/sw_neo4j/docker-compose.yml 
b/tests/plugin/data/sw_neo4j/docker-compose.yml
new file mode 100644
index 0000000..7b91649
--- /dev/null
+++ b/tests/plugin/data/sw_neo4j/docker-compose.yml
@@ -0,0 +1,84 @@
+#
+# 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.
+#
+
+version: '2.1'
+
+services:
+  collector:
+    extends:
+      service: collector
+      file: ../../docker-compose.base.yml
+
+  neo4j:
+    image:  neo4j:4.4-community
+    hostname: neo4j
+    ports:
+      - 7687:7687
+    environment:
+      - NEO4J_dbms_security_auth__enabled=false
+    healthcheck:
+      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/7687"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+    networks:
+      - beyond
+
+  provider:
+    extends:
+      service: agent
+      file: ../../docker-compose.base.yml
+    ports:
+      - 9091:9091
+    volumes:
+      - .:/app
+    command: ['bash', '-c', 'pip3 install uvicorn && pip3 install fastapi && 
pip3 install -r /app/requirements.txt && sw-python run python3 
/app/services/provider.py']
+    depends_on:
+      collector:
+        condition: service_healthy
+      neo4j:
+        condition: service_healthy
+    healthcheck:
+      test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9091"]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+    environment:
+      SW_AGENT_NAME: provider
+      SW_AGENT_LOGGING_LEVEL: DEBUG
+      SW_PLUGIN_SQL_PARAMETERS_MAX_LENGTH: 512
+
+  consumer:
+    extends:
+      service: agent
+      file: ../../docker-compose.base.yml
+    ports:
+      - 9090:9090
+    volumes:
+      - .:/app
+    command: ['bash', '-c', 'pip3 install uvicorn && pip3 install fastapi && 
pip3 install -r /app/requirements.txt && sw-python run python3 
/app/services/consumer.py']
+    depends_on:
+      collector:
+        condition: service_healthy
+      provider:
+        condition: service_healthy
+    environment:
+      SW_AGENT_NAME: consumer
+      SW_AGENT_LOGGING_LEVEL: DEBUG
+
+networks:
+  beyond:
diff --git a/tests/plugin/data/sw_neo4j/expected.data.yml 
b/tests/plugin/data/sw_neo4j/expected.data.yml
new file mode 100644
index 0000000..1bbfcc4
--- /dev/null
+++ b/tests/plugin/data/sw_neo4j/expected.data.yml
@@ -0,0 +1,168 @@
+#
+# 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.
+#
+
+segmentItems:
+  - serviceName: provider
+    segmentSize: 1
+    segments:
+      - segmentId: not null
+        spans:
+          - operationName: Neo4j/Session/run
+            parentSpanId: 0
+            spanId: 1
+            spanLayer: Database
+            tags:
+              - key: db.type
+                value: Neo4j
+              - key: db.instance
+                value: neo4j
+              - key: db.statement
+                value: 'MATCH (n: stage) WHERE n.age=$age RETURN n'
+              - key: db.sql.parameters
+                value: '[{"age": 10}]'
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 112
+            spanType: Exit
+            peer: neo4j:7687
+            skipAnalysis: false
+          - operationName: Neo4j/Transaction/run
+            parentSpanId: 0
+            spanId: 2
+            spanLayer: Database
+            tags:
+              - key: db.type
+                value: Neo4j
+              - key: db.instance
+                value: neo4j
+              - key: db.statement
+                value: 'MATCH (n: stage) WHERE n.age=$age RETURN n'
+              - key: db.sql.parameters
+                value: '[{"age": 10}]'
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 112
+            spanType: Exit
+            peer: neo4j:7687
+            skipAnalysis: false
+          - operationName: Neo4j/AsyncSession/run
+            parentSpanId: 0
+            spanId: 3
+            spanLayer: Database
+            tags:
+              - key: db.type
+                value: Neo4j
+              - key: db.instance
+                value: neo4j
+              - key: db.statement
+                value: 'MATCH (n: stage) WHERE n.age=$age RETURN n'
+              - key: db.sql.parameters
+                value: '[{"age": 10}]'
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 112
+            spanType: Exit
+            peer: neo4j:7687
+            skipAnalysis: false
+          - operationName: Neo4j/AsyncTransaction/run
+            parentSpanId: 0
+            spanId: 4
+            spanLayer: Database
+            tags:
+              - key: db.type
+                value: Neo4j
+              - key: db.instance
+                value: neo4j
+              - key: db.statement
+                value: 'MATCH (n: stage) WHERE n.age=$age RETURN n'
+              - key: db.sql.parameters
+                value: '[{"age": 10}]'
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 112
+            spanType: Exit
+            peer: neo4j:7687
+            skipAnalysis: false
+          - operationName: /users
+            operationId: 0
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
+            tags:
+              - key: http.method
+                value: GET
+              - key: http.url
+                value: http://provider:9091/users
+              - key: http.status_code
+                value: '200'
+            refs:
+              - parentEndpoint: /users
+                networkAddress: provider:9091
+                refType: CrossProcess
+                parentSpanId: 1
+                parentTraceSegmentId: not null
+                parentServiceInstance: not null
+                parentService: consumer
+                traceId: not null
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 7014
+            spanType: Entry
+            peer: not null
+            skipAnalysis: false
+
+
+  - serviceName: consumer
+    segmentSize: 1
+    segments:
+      - segmentId: not null
+        spans:
+          - operationName: /users
+            parentSpanId: 0
+            spanId: 1
+            spanLayer: Http
+            tags:
+              - key: http.method
+                value: GET
+              - key: http.url
+                value: http://provider:9091/users
+              - key: http.status_code
+                value: '200'
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 7002
+            spanType: Exit
+            peer: provider:9091
+            skipAnalysis: false
+          - operationName: /users
+            operationId: 0
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
+            tags:
+              - key: http.method
+                value: GET
+              - key: http.url
+                value: http://0.0.0.0:9090/users
+              - key: http.status_code
+                value: '200'
+            startTime: gt 0
+            endTime: gt 0
+            componentId: 7014
+            spanType: Entry
+            peer: not null
+            skipAnalysis: false
diff --git a/tests/plugin/data/sw_neo4j/services/__init__.py 
b/tests/plugin/data/sw_neo4j/services/__init__.py
new file mode 100644
index 0000000..b1312a0
--- /dev/null
+++ b/tests/plugin/data/sw_neo4j/services/__init__.py
@@ -0,0 +1,16 @@
+#
+# 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.
+#
diff --git a/tests/plugin/data/sw_neo4j/services/consumer.py 
b/tests/plugin/data/sw_neo4j/services/consumer.py
new file mode 100644
index 0000000..6ec0401
--- /dev/null
+++ b/tests/plugin/data/sw_neo4j/services/consumer.py
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+import requests
+
+if __name__ == '__main__':
+    from fastapi import FastAPI
+    import uvicorn
+
+    app = FastAPI()
+
+
+    @app.get('/users')
+    async def users():
+        requests.get('http://provider:9091/users', timeout=5)
+        return 'success'
+
+
+    uvicorn.run(app, host='0.0.0.0', port=9090)
diff --git a/tests/plugin/data/sw_neo4j/services/provider.py 
b/tests/plugin/data/sw_neo4j/services/provider.py
new file mode 100644
index 0000000..4b2f67f
--- /dev/null
+++ b/tests/plugin/data/sw_neo4j/services/provider.py
@@ -0,0 +1,55 @@
+#
+# 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.
+#
+
+
+if __name__ == '__main__':
+    from fastapi import FastAPI
+    import uvicorn
+    import neo4j
+
+    app = FastAPI()
+
+
+    @app.get('/users')
+    async def users():
+        driver = neo4j.GraphDatabase.driver('bolt://neo4j:7687/')
+        with driver.session(database='neo4j') as session:
+            session.run('MATCH (n: stage) WHERE n.age=$age RETURN n', {'age': 
10})
+
+        with driver.session(database='neo4j') as session:
+            with session.begin_transaction() as tx:
+                tx.run('MATCH (n: stage) WHERE n.age=$age RETURN n', {'age': 
10})
+
+        driver.close()
+
+        driver = neo4j.AsyncGraphDatabase.driver('bolt://neo4j:7687/')
+        async with driver.session(database='neo4j') as session:
+            await session.run('MATCH (n: stage) WHERE n.age=$age RETURN n', 
{'age': 10})
+
+        async def transaction_func(tx, query, params):
+            return await tx.run(query, params)
+
+        async with driver.session(database='neo4j') as session:
+            await session.execute_read(
+                transaction_func, 'MATCH (n: stage) WHERE n.age=$age RETURN 
n', {'age': 10})
+
+        await driver.close()
+
+        return 'success'
+
+
+    uvicorn.run(app, host='0.0.0.0', port=9091)
diff --git a/tests/plugin/data/sw_neo4j/test_neo4j.py 
b/tests/plugin/data/sw_neo4j/test_neo4j.py
new file mode 100644
index 0000000..89a70c1
--- /dev/null
+++ b/tests/plugin/data/sw_neo4j/test_neo4j.py
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+from typing import Callable
+
+import pytest
+import requests
+
+from skywalking.plugins.sw_neo4j import support_matrix
+from tests.orchestrator import get_test_vector
+from tests.plugin.base import TestPluginBase
+
+
[email protected]
+def prepare():
+    # type: () -> Callable
+    return lambda *_: requests.get('http://0.0.0.0:9090/users', timeout=5)
+
+
+class TestPlugin(TestPluginBase):
+    @pytest.mark.parametrize('version', get_test_vector(lib_name='neo4j', 
support_matrix=support_matrix))
+    def test_plugin(self, docker_compose, version):
+        self.validate()

Reply via email to