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()