You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2023/01/13 02:16:13 UTC
[skywalking-python] branch master updated: Add hbase happy plugin (#266)
This is an automated email from the ASF dual-hosted git repository.
wusheng 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 889700b Add hbase happy plugin (#266)
889700b is described below
commit 889700b681be2db89e14c786b362ad83ec2f7e1e
Author: alidisi <24...@qq.com>
AuthorDate: Fri Jan 13 10:16:08 2023 +0800
Add hbase happy plugin (#266)
---
CHANGELOG.md | 1 +
docs/en/setup/Plugins.md | 1 +
poetry.lock | 56 ++++++++-
pyproject.toml | 1 +
skywalking/__init__.py | 1 +
skywalking/plugins/sw_happybase.py | 129 +++++++++++++++++++++
tests/plugin/data/sw_happybase/__init__.py | 16 +++
tests/plugin/data/sw_happybase/docker-compose.yml | 58 +++++++++
tests/plugin/data/sw_happybase/expected.data.yml | 88 ++++++++++++++
.../plugin/data/sw_happybase/services/__init__.py | 16 +++
.../plugin/data/sw_happybase/services/consumer.py | 51 ++++++++
tests/plugin/data/sw_happybase/test_happybase.py | 36 ++++++
12 files changed, 449 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a636a6..321ba94 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@
- Plugins:
- Add aioredis, aiormq, amqp, asyncpg, aio-pika, kombu RMQ plugins (#230 Missing test coverage)
- Add Confluent Kafka plugin (#233 Missing test coverage)
+ - Add HBase plugin Python HappyBase model (#266)
- Fixes:
- Allow RabbitMQ BlockingChannel.basic_consume() to link with outgoing spans (#224)
diff --git a/docs/en/setup/Plugins.md b/docs/en/setup/Plugins.md
index b0faa37..99826fa 100644
--- a/docs/en/setup/Plugins.md
+++ b/docs/en/setup/Plugins.md
@@ -26,6 +26,7 @@ Library | Python Version - Lib Version | Plugin Name
| [hug](https://falcon.readthedocs.io/en/stable/) | Python >=3.10 - ['2.5', '2.6']; Python >=3.7 - ['2.4.1', '2.5', '2.6']; | `sw_falcon` |
| [fastapi](https://fastapi.tiangolo.com) | Python >=3.7 - ['0.70.1']; | `sw_fastapi` |
| [flask](https://flask.palletsprojects.com) | Python >=3.7 - ['2.0']; | `sw_flask` |
+| [happybase](https://happybase.readthedocs.io) | Python >=3.7 - ['1.2.0']; | `sw_happybase` |
| [http_server](https://docs.python.org/3/library/http.server.html) | Python >=3.7 - ['*']; | `sw_http_server` |
| [werkzeug](https://werkzeug.palletsprojects.com/) | Python >=3.7 - ['1.0.1', '2.0']; | `sw_http_server` |
| [kafka-python](https://kafka-python.readthedocs.io) | Python >=3.7 - ['2.0']; | `sw_kafka` |
diff --git a/poetry.lock b/poetry.lock
index 60356ec..35e2233 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1204,6 +1204,21 @@ files = [
[package.dependencies]
typing-extensions = {version = "*", markers = "python_version < \"3.8\""}
+[[package]]
+name = "happybase"
+version = "1.2.0"
+description = "A developer-friendly Python library to interact with Apache HBase"
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
+ {file = "happybase-1.2.0.tar.gz", hash = "sha256:850b4ee651128588a57e1e152dd1252e5ec39776a5d3d14ee892b8bac0fa9e1a"},
+]
+
+[package.dependencies]
+six = "*"
+thriftpy2 = ">=0.4"
+
[[package]]
name = "httptools"
version = "0.5.0"
@@ -1766,6 +1781,18 @@ importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"]
+[[package]]
+name = "ply"
+version = "3.11"
+description = "Python Lex & Yacc"
+category = "dev"
+optional = false
+python-versions = "*"
+files = [
+ {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"},
+ {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"},
+]
+
[[package]]
name = "prompt-toolkit"
version = "3.0.36"
@@ -2379,18 +2406,18 @@ files = [
[[package]]
name = "setuptools"
-version = "65.6.3"
+version = "65.7.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
- {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"},
- {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"},
+ {file = "setuptools-65.7.0-py3-none-any.whl", hash = "sha256:8ab4f1dbf2b4a65f7eec5ad0c620e84c34111a68d3349833494b9088212214dd"},
+ {file = "setuptools-65.7.0.tar.gz", hash = "sha256:4d3c92fac8f1118bb77a22181355e29c239cabfe2b9effdaa665c66b711136d7"},
]
[package.extras]
-docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
@@ -2495,6 +2522,25 @@ rabbitmq = ["pika"]
redis = ["redis"]
selenium = ["selenium"]
+[[package]]
+name = "thriftpy2"
+version = "0.4.16"
+description = "Pure python implementation of Apache Thrift."
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "thriftpy2-0.4.16.tar.gz", hash = "sha256:2aa67ecda99a948e4146341d388260b48ee7da5dfb9a951c4151988e2ed2fb4c"},
+]
+
+[package.dependencies]
+ply = ">=3.4,<4.0"
+six = ">=1.15,<2.0"
+
+[package.extras]
+dev = ["cython (>=0.28.4)", "flake8 (>=2.5)", "pytest (>=2.8)", "pytest (>=6.1.1)", "sphinx (>=1.3)", "sphinx-rtd-theme (>=0.1.9)", "tornado (>=4.0,<6.0)"]
+tornado = ["tornado (>=4.0,<6.0)"]
+
[[package]]
name = "tomli"
version = "2.0.1"
@@ -3226,4 +3272,4 @@ kafka = ["kafka-python"]
[metadata]
lock-version = "2.0"
python-versions = ">=3.7, <3.11"
-content-hash = "df1bcb5a7f7176c713cced331295819711b0d6dd54ab9f0f8cda84d14613f515"
+content-hash = "90f60beeb8815258bb9fc26dc8c1da7b96403907da9c14c544d95f878bdb1680"
diff --git a/pyproject.toml b/pyproject.toml
index 75dfc53..e0871cf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -124,6 +124,7 @@ bottle = "0.12.21"
aioredis = "^2.0.1"
aiormq = "^6.4.2"
asyncpg = "^0.27.0"
+happybase = "1.2.0"
[tool.poetry.group.lint.dependencies]
flake8 = "^5.0.4"
diff --git a/skywalking/__init__.py b/skywalking/__init__.py
index 602c22b..43034f2 100644
--- a/skywalking/__init__.py
+++ b/skywalking/__init__.py
@@ -37,6 +37,7 @@ class Component(Enum):
RabbitmqProducer = 52
RabbitmqConsumer = 53
Elasticsearch = 47
+ HBase = 94
Urllib3 = 7006
Sanic = 7007
AioHttp = 7008
diff --git a/skywalking/plugins/sw_happybase.py b/skywalking/plugins/sw_happybase.py
new file mode 100644
index 0000000..0df76ae
--- /dev/null
+++ b/skywalking/plugins/sw_happybase.py
@@ -0,0 +1,129 @@
+#
+# 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 skywalking import Layer, Component
+from skywalking.trace.context import get_context
+from skywalking.trace.tags import TagDbType, TagDbStatement
+
+link_vector = ['https://happybase.readthedocs.io']
+support_matrix = {
+ 'happybase': {
+ '>=3.7': ['1.2.0'],
+ }
+}
+note = """"""
+
+
+def install():
+ from happybase import Table
+ from happybase import Connection
+ _row = Table.row
+ _rows = Table.rows
+ _cells = Table.cells
+ _scan = Table.scan
+ _put = Table.put
+ _delete = Table.delete
+ _create_table = Connection.create_table
+
+ def bytes2str(value):
+ if isinstance(value, bytes):
+ return value.decode()
+ return value
+
+ def _sw_create_table(this, name, families):
+ context = get_context()
+ peer = ','.join([f'{this.host}:{str(this.port)}'])
+ table_name = name
+ with context.new_exit_span(op=f'HBase/create/{table_name}', peer=peer,
+ component=Component.HBase) as span:
+ span.layer = Layer.Database
+ span.tag(TagDbType('HBase'))
+ span.tag(TagDbStatement(''))
+ _create_table(this, name, families)
+
+ def _sw_hbase_opt(table, name, fun, row, is_return=True):
+ context = get_context()
+ peer = ','.join([f'{table.connection.host}:{str(table.connection.port)}'])
+ table_name = bytes2str(table.name)
+ row = bytes2str(row)
+ with context.new_exit_span(op=f'HBase/{name}/{table_name}/{row}', peer=peer,
+ component=Component.HBase) as span:
+ span.layer = Layer.Database
+ span.tag(TagDbType('HBase'))
+ span.tag(TagDbStatement(''))
+ if is_return:
+ return fun()
+ else:
+ fun()
+
+ def _sw_row(this, row, columns=None, timestamp=None, include_timestamp=False):
+ def __sw_row():
+ return _row(this, row, columns, timestamp, include_timestamp)
+
+ res = _sw_hbase_opt(this, 'row', __sw_row, row)
+ return res
+
+ def _sw_rows(this, rows, columns=None, timestamp=None, include_timestamp=False):
+ def __sw_rows():
+ return _rows(this, rows, columns, timestamp, include_timestamp)
+
+ row = ''
+ if rows and isinstance(rows, list):
+ row = rows[0]
+
+ res = _sw_hbase_opt(this, 'rows', __sw_rows, row)
+ return res
+
+ def _sw_cells(this, row, column, versions=None, timestamp=None, include_timestamp=False):
+ def __sw_cells():
+ return _cells(this, row, column, versions, timestamp, include_timestamp)
+
+ res = _sw_hbase_opt(this, 'cells', __sw_cells, row)
+ return res
+
+ def _sw_scan(this, row_start=None, row_stop=None, row_prefix=None,
+ columns=None, filter=None, timestamp=None,
+ include_timestamp=False, batch_size=1000, scan_batching=None,
+ limit=None, sorted_columns=False, reverse=False):
+ def __sw_scan():
+ return _scan(this, row_start, row_stop, row_prefix,
+ columns, filter, timestamp,
+ include_timestamp, batch_size, scan_batching,
+ limit, sorted_columns, reverse)
+
+ res = _sw_hbase_opt(this, 'scan', __sw_scan, row_start)
+ return res
+
+ def _sw_put(this, row, data, timestamp=None, wal=True):
+ def __sw_put():
+ return _put(this, row, data, timestamp, wal)
+
+ _sw_hbase_opt(this, 'put', __sw_put, row, False)
+
+ def _sw_delete(this, row, columns=None, timestamp=None, wal=True):
+ def __sw_delete():
+ return _delete(this, row, columns, timestamp, wal)
+
+ _sw_hbase_opt(this, 'delete', __sw_delete, row, False)
+
+ Table.row = _sw_row
+ Table.rows = _sw_rows
+ Table.cells = _sw_cells
+ Table.scan = _sw_scan
+ Table.put = _sw_put
+ Table.delete = _sw_delete
+ Connection.create_table = _sw_create_table
diff --git a/tests/plugin/data/sw_happybase/__init__.py b/tests/plugin/data/sw_happybase/__init__.py
new file mode 100644
index 0000000..b1312a0
--- /dev/null
+++ b/tests/plugin/data/sw_happybase/__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_happybase/docker-compose.yml b/tests/plugin/data/sw_happybase/docker-compose.yml
new file mode 100644
index 0000000..ee683df
--- /dev/null
+++ b/tests/plugin/data/sw_happybase/docker-compose.yml
@@ -0,0 +1,58 @@
+#
+# 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
+
+ hbase:
+ image: harisekhon/hbase:latest
+ hostname: hbase
+ expose:
+ - 9090
+ healthcheck:
+ test: ["CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/9090"]
+ interval: 5s
+ timeout: 60s
+ retries: 120
+ networks:
+ - beyond
+
+ consumer:
+ extends:
+ service: agent
+ file: ../../docker-compose.base.yml
+ ports:
+ - 9090:9090
+ volumes:
+ - .:/app
+ command: ['bash', '-c', 'pip install flask && pip install -r /app/requirements.txt && sw-python run python3 /app/services/consumer.py']
+ depends_on:
+ collector:
+ condition: service_healthy
+ hbase:
+ condition: service_healthy
+ environment:
+ SW_AGENT_NAME: consumer
+ SW_AGENT_LOGGING_LEVEL: DEBUG
+ SW_ELASTICSEARCH_TRACE_DSL: 'True'
+networks:
+ beyond:
diff --git a/tests/plugin/data/sw_happybase/expected.data.yml b/tests/plugin/data/sw_happybase/expected.data.yml
new file mode 100644
index 0000000..039132a
--- /dev/null
+++ b/tests/plugin/data/sw_happybase/expected.data.yml
@@ -0,0 +1,88 @@
+#
+# 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: consumer
+ segmentSize: 1
+ segments:
+ - segmentId: not null
+ spans:
+ - operationName: HBase/create/test
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Database
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 94
+ isError: false
+ spanType: Exit
+ peer: hbase:9090
+ skipAnalysis: false
+ tags:
+ - key: db.type
+ value: HBase
+ - key: db.statement
+ value: ''
+ - operationName: HBase/put/test/row_key
+ parentSpanId: 0
+ spanId: 2
+ spanLayer: Database
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 94
+ isError: false
+ spanType: Exit
+ peer: hbase:9090
+ skipAnalysis: false
+ tags:
+ - key: db.type
+ value: HBase
+ - key: db.statement
+ value: ''
+ - operationName: HBase/row/test/row_key
+ parentSpanId: 0
+ spanId: 3
+ spanLayer: Database
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 94
+ isError: false
+ spanType: Exit
+ peer: hbase:9090
+ skipAnalysis: false
+ tags:
+ - key: db.type
+ value: HBase
+ - key: db.statement
+ value: ''
+ - operationName: /users
+ 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: 7001
+ spanType: Entry
+ peer: not null
+ skipAnalysis: false
diff --git a/tests/plugin/data/sw_happybase/services/__init__.py b/tests/plugin/data/sw_happybase/services/__init__.py
new file mode 100644
index 0000000..b1312a0
--- /dev/null
+++ b/tests/plugin/data/sw_happybase/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_happybase/services/consumer.py b/tests/plugin/data/sw_happybase/services/consumer.py
new file mode 100644
index 0000000..46cc04e
--- /dev/null
+++ b/tests/plugin/data/sw_happybase/services/consumer.py
@@ -0,0 +1,51 @@
+#
+# 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 happybase
+
+
+if __name__ == '__main__':
+ from flask import Flask, jsonify
+
+ app = Flask(__name__)
+ connection = happybase.Connection('hbase', port=9090)
+ connection.open()
+ row = b'row_key'
+ info = {b'INFO:data': b'value'}
+ table_name = 'test'
+
+ def create_table():
+ families = {'INFO': {}}
+ connection.create_table(table_name, families)
+
+ def save_table():
+ table = connection.table(table_name)
+ table.put(row, info)
+
+ def get_row():
+ table = connection.table(table_name)
+ table.row(row)
+
+ @app.route('/users', methods=['POST', 'GET'])
+ def application():
+ create_table()
+ save_table()
+ get_row()
+ return jsonify({'INFO:data': 'value'})
+
+ PORT = 9090
+ app.run(host='0.0.0.0', port=PORT, debug=True)
diff --git a/tests/plugin/data/sw_happybase/test_happybase.py b/tests/plugin/data/sw_happybase/test_happybase.py
new file mode 100644
index 0000000..8fe2ba9
--- /dev/null
+++ b/tests/plugin/data/sw_happybase/test_happybase.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_happybase import support_matrix
+from tests.orchestrator import get_test_vector
+from tests.plugin.base import TestPluginBase
+
+
+@pytest.fixture
+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='happybase', support_matrix=support_matrix))
+ def test_plugin(self, docker_compose, version):
+ self.validate()