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