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

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


The following commit(s) were added to refs/heads/master by this push:
     new ac6bb535f RANGER-5833 Add Docker system tests to verify Hbase denies 
operations for users without an explicit allow policy (#1303)
ac6bb535f is described below

commit ac6bb535f3d1458a44d30b26b0f344b064def2dd
Author: Vishal Bhavsar <[email protected]>
AuthorDate: Mon Oct 12 20:16:41 2026 +0530

    RANGER-5833 Add Docker system tests to verify Hbase denies operations for 
users without an explicit allow policy (#1303)
---
 functional-tests/hbase/test_hbase_01.py           | 138 +++++++++
 functional-tests/hive/test_hive_01.py             |  10 +-
 functional-tests/pytest.ini                       |   1 +
 functional-tests/ranger_test_utils/hbase_utils.py | 357 ++++++++++++++++++++++
 functional-tests/ranger_test_utils/hive_utils.py  |  30 +-
 functional-tests/ranger_test_utils/utils.py       |  15 +-
 functional-tests/readme.md                        |  20 ++
 functional-tests/run-tests.sh                     |   2 +-
 8 files changed, 540 insertions(+), 33 deletions(-)

diff --git a/functional-tests/hbase/test_hbase_01.py 
b/functional-tests/hbase/test_hbase_01.py
new file mode 100644
index 000000000..a6739f1db
--- /dev/null
+++ b/functional-tests/hbase/test_hbase_01.py
@@ -0,0 +1,138 @@
+# 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.
+
+"""
+Authorization is asserted via HBase shell output only. Access-audit asserts 
are deferred until
+HBase plugin audits are reliably indexed in Docker — use 
ranger_test_utils.access_audit_utils
+when ready.
+
+AUDIT_FILTERS (future):
+  test_01_01: accessType=createTable, accessResult=0, aclEnforcer=ranger-acl,
+              resourceName=<table>, repoName=dev_hbase, requestUser=hrt_21
+"""
+
+import pytest
+
+from ranger_test_utils.hbase_utils import (
+    HBASE_AUTHZ_DENIED_SUBSTR,
+    HBASE_SERVICE_NAME,
+    HBASE_TEST_USER,
+    cleanup_hbase_test_table,
+    create_audit_only_policy,
+    ensure_kerberos_user,
+    preflight_hbase_stack,
+    prepare_hbase_test_table,
+    run_hbase_shell,
+    wait_for_hbase_policy_propagation,
+)
+from ranger_test_utils.hive_utils import delete_policies_by_id, 
set_all_policies_enabled
+from ranger_test_utils.utils import (
+    DOCKER_PLUGIN_TEST_USER_PASSWORD,
+    configure_test_logging,
+    create_ranger_admin_session,
+    ensure_user_exists,
+    get_test_logger,
+    log_testcase_begin_for_pytest,
+    unique_suffix,
+)
+
+pytestmark = pytest.mark.hbase
+
+logger = get_test_logger(__name__)
+
+_admin_session = None
+_audit_policy_id = None
+_audit_suffix = None
+_run_suffix = None
+_test_table = None
+
+
+def setup_module():
+    configure_test_logging(module_name=__name__)
+    logger.info("=== setup_module: start ===")
+    preflight_hbase_stack()
+
+    global _admin_session, _audit_policy_id, _audit_suffix
+    global _run_suffix, _test_table
+    _admin_session = create_ranger_admin_session()
+    _run_suffix = unique_suffix(4)
+    _test_table = "iemployee_" + _run_suffix
+    logger.info("Test table: %s", _test_table)
+
+    logger.info("Ensuring Ranger user and Kerberos principal for %s", 
HBASE_TEST_USER)
+    ensure_user_exists(
+        _admin_session,
+        HBASE_TEST_USER,
+        password=DOCKER_PLUGIN_TEST_USER_PASSWORD,
+        last_name="hive_test",
+    )
+    ensure_kerberos_user(HBASE_TEST_USER)
+
+    logger.info("HBase setup: drop table %s if present", _test_table)
+    prepare_hbase_test_table(_test_table)
+
+    logger.info(
+        "Disabling all policies on %s and creating audit-only policy",
+        HBASE_SERVICE_NAME,
+    )
+    set_all_policies_enabled(_admin_session, False, HBASE_SERVICE_NAME)
+    _audit_policy_id, _audit_suffix = create_audit_only_policy(_admin_session)
+    logger.info("Created audit policy id=%s suffix=%s", _audit_policy_id, 
_audit_suffix)
+    wait_for_hbase_policy_propagation()
+    logger.info("=== setup_module: done ===")
+
+
+def teardown_module():
+    if _admin_session is None:
+        return
+
+    logger.info("=== teardown_module: start ===")
+    if _test_table is not None:
+        logger.info("HBase cleanup: drop table %s", _test_table)
+        cleanup_hbase_test_table(_test_table)
+
+    if _audit_policy_id is not None:
+        logger.info("Deleting audit policy id=%s", _audit_policy_id)
+        delete_policies_by_id(_admin_session, [_audit_policy_id])
+
+    logger.info("Re-enabling all policies on %s", HBASE_SERVICE_NAME)
+    set_all_policies_enabled(_admin_session, True, HBASE_SERVICE_NAME)
+    wait_for_hbase_policy_propagation()
+    logger.info("=== teardown_module: done ===")
+
+
+def test_01_01_create_hbase_table_case1a_deny(request):
+    log_testcase_begin_for_pytest(logger, request.node.name, suite="HBASE")
+    create_cmd = (
+        "create '"
+        + _test_table
+        + "','personal','payroll','medical'"
+    )
+    logger.info(
+        "Running HBase CREATE TABLE as %s (expect deny): %s",
+        HBASE_TEST_USER,
+        create_cmd,
+    )
+    exit_code, output = run_hbase_shell(
+        HBASE_TEST_USER,
+        [create_cmd],
+        expect_substring=HBASE_AUTHZ_DENIED_SUBSTR,
+    )
+    assert HBASE_AUTHZ_DENIED_SUBSTR in output, (
+        "Expected authorization denial in HBase shell output; exit_code="
+        + str(exit_code)
+        + " output="
+        + output
+    )
diff --git a/functional-tests/hive/test_hive_01.py 
b/functional-tests/hive/test_hive_01.py
index e44ac1f31..525133963 100644
--- a/functional-tests/hive/test_hive_01.py
+++ b/functional-tests/hive/test_hive_01.py
@@ -34,7 +34,6 @@
     cleanup_hive_test_namespace,
     create_audit_only_policy,
     delete_policies_by_id,
-    ensure_hive_test_user_in_ranger,
     ensure_kerberos_user,
     preflight_hive_stack,
     prepare_hive_test_namespace,
@@ -43,8 +42,10 @@
     wait_for_policy_propagation,
 )
 from ranger_test_utils.utils import (
+    DOCKER_PLUGIN_TEST_USER_PASSWORD,
     configure_test_logging,
     create_ranger_admin_session,
+    ensure_user_exists,
     get_test_logger,
     log_testcase_begin_for_pytest,
     unique_suffix,
@@ -80,7 +81,12 @@ def setup_module():
     )
 
     logger.info("Ensuring Ranger user and Kerberos principal for %s", 
HIVE_TEST_USER)
-    ensure_hive_test_user_in_ranger(_admin_session)
+    ensure_user_exists(
+        _admin_session,
+        HIVE_TEST_USER,
+        password=DOCKER_PLUGIN_TEST_USER_PASSWORD,
+        last_name="hive_test",
+    )
     ensure_kerberos_user(HIVE_TEST_USER)
 
     logger.info(
diff --git a/functional-tests/pytest.ini b/functional-tests/pytest.ini
index 45db54be6..2777e38c3 100644
--- a/functional-tests/pytest.ini
+++ b/functional-tests/pytest.ini
@@ -28,6 +28,7 @@ markers =
     rolerest: rolerest test cases
     api: public API v2 test cases
     hive: Hive plugin enforcement (Docker HS2)
+    hbase: HBase plugin enforcement (Docker HBase shell)
 pythonpath = .
 # No console logging during pytest; logger.info -> logs/pytest.log (tail -f 
logs/pytest.log).
 log_cli = false
diff --git a/functional-tests/ranger_test_utils/hbase_utils.py 
b/functional-tests/ranger_test_utils/hbase_utils.py
new file mode 100644
index 000000000..511f188fe
--- /dev/null
+++ b/functional-tests/ranger_test_utils/hbase_utils.py
@@ -0,0 +1,357 @@
+# 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.
+
+"""HBase Docker helpers for Ranger functional-tests (HBase shell + plugin 
enforcement)."""
+
+import base64
+import socket
+import time
+
+import pytest
+
+from ranger_test_utils.utils import (
+    POLICY_URL,
+    assert_http_ok,
+    get_test_logger,
+    unique_suffix,
+)
+from ranger_test_utils.hive_utils import (
+    HIVE_TEST_USER,
+    KDC_CONTAINER,
+    POLICY_PROPAGATION_SLEEP_SEC,
+    get_docker_client,
+)
+
+logger = get_test_logger(__name__)
+
+HBASE_SHELL_LOG_OUTPUT_MAX_CHARS = 12000
+
+HBASE_SERVICE_NAME = "dev_hbase"
+HBASE_CONTAINER = "ranger-hbase"
+HADOOP_CONTAINER = "ranger-hadoop"
+ADMIN_CONTAINER = "ranger"
+
+KERBEROS_REALM = "EXAMPLE.COM"
+HBASE_SERVICE_PRINCIPAL = "hbase/ranger-hbase.rangernw@" + KERBEROS_REALM
+HBASE_SERVICE_KEYTAB = "/etc/keytabs/hbase.keytab"
+
+HBASE_TEST_USER = HIVE_TEST_USER
+
+HBASE_AUTHZ_DENIED_SUBSTR = "AccessDeniedException"
+
+HBASE_AUDIT_POLICY_SERVICE_USERS = ["hbase"]
+HBASE_AUDIT_POLICY_ACCESS_TYPES = ["create", "read", "write", "admin"]
+
+
+def _container_running(name):
+    client = get_docker_client()
+    try:
+        container = client.containers.get(name)
+    except Exception:
+        return False
+    container.reload()
+    return container.status == "running"
+
+
+def _master_ui_port_open(host="127.0.0.1", port=16010, timeout=2.0):
+    try:
+        with socket.create_connection((host, port), timeout=timeout):
+            return True
+    except OSError:
+        return False
+
+
+def preflight_hbase_stack():
+    """Skip tests when required Docker services or HBase master UI are 
unavailable."""
+    required = [
+        ADMIN_CONTAINER,
+        KDC_CONTAINER,
+        HADOOP_CONTAINER,
+        HBASE_CONTAINER,
+    ]
+    missing = [name for name in required if not _container_running(name)]
+    if missing:
+        pytest.skip(
+            "HBase functional-tests need running containers: "
+            + ", ".join(missing)
+            + ". Run ./run-tests.sh postgres hbase from functional-tests/."
+        )
+
+    if not _master_ui_port_open():
+        pytest.skip(
+            "HBase master UI is not accepting connections on localhost:16010 "
+            "(is ranger-hbase healthy?)"
+        )
+
+
+def _user_principal(username):
+    return username + "@" + KERBEROS_REALM
+
+
+def _user_keytab_in_hbase_container(username):
+    return "/etc/keytabs/" + username + ".keytab"
+
+
+def _log_multiline_block(header, text, 
max_chars=HBASE_SHELL_LOG_OUTPUT_MAX_CHARS):
+    body = text if text else "(empty)"
+    if len(body) > max_chars:
+        body = (
+            body[:max_chars]
+            + "\n... [truncated, total "
+            + str(len(text))
+            + " chars]"
+        )
+    logger.info("%s", header)
+    for line in body.splitlines():
+        logger.info("  %s", line)
+
+
+def ensure_kerberos_user(username):
+    """Create a user Kerberos principal and keytab on KDC, visible in 
ranger-hbase."""
+    kdc = get_docker_client().containers.get(KDC_CONTAINER)
+    principal = _user_principal(username)
+    keytab_in_kdc = "/etc/keytabs/ranger-hbase/" + username + ".keytab"
+    keytab_in_hbase = _user_keytab_in_hbase_container(username)
+
+    logger.info(
+        "Kerberos setup on %s: addprinc/ktadd for %s -> %s (visible in hbase 
as %s)",
+        KDC_CONTAINER,
+        principal,
+        keytab_in_kdc,
+        keytab_in_hbase,
+    )
+
+    add_cmd = 'kadmin.local -q "addprinc -randkey ' + principal + '"'
+    exit_add, out_add = kdc.exec_run(add_cmd, user="root", demux=True)
+    _log_multiline_block(
+        "kadmin addprinc exit_code=%s" % exit_add,
+        ((out_add[0] or b"") + (out_add[1] or b"")).decode(),
+        max_chars=2000,
+    )
+
+    kdc.exec_run("rm -f " + keytab_in_kdc, user="root")
+    ktadd_cmd = (
+        'kadmin.local -q "ktadd -k '
+        + keytab_in_kdc
+        + " "
+        + principal
+        + '"'
+    )
+    exit_kt, out_kt = kdc.exec_run(ktadd_cmd, user="root", demux=True)
+    kt_out = ((out_kt[0] or b"") + (out_kt[1] or b"")).decode()
+    _log_multiline_block(
+        "kadmin ktadd exit_code=%s" % exit_kt,
+        kt_out,
+        max_chars=2000,
+    )
+    if exit_kt != 0:
+        raise RuntimeError(
+            "ktadd failed for "
+            + principal
+            + " (keytab "
+            + keytab_in_hbase
+            + "): "
+            + kt_out
+        )
+    kdc.exec_run("chmod 444 " + keytab_in_kdc, user="root")
+    verify_kerberos_keytab_in_hbase(username)
+
+
+def verify_kerberos_keytab_in_hbase(username):
+    """kinit in ranger-hbase using the user's keytab (fail fast if keytab is 
bad)."""
+    hbase = get_docker_client().containers.get(HBASE_CONTAINER)
+    principal = _user_principal(username)
+    keytab = _user_keytab_in_hbase_container(username)
+    shell = (
+        "kdestroy -A 2>/dev/null || true; "
+        "kinit -kt "
+        + keytab
+        + " "
+        + principal
+        + "; klist"
+    )
+    exit_code, output = hbase.exec_run(["bash", "-c", shell], user="hbase", 
demux=True)
+    combined = ((output[0] or b"") + (output[1] or b"")).decode()
+    if exit_code != 0:
+        raise RuntimeError(
+            "Kerberos kinit failed in "
+            + HBASE_CONTAINER
+            + " for "
+            + principal
+            + ": "
+            + combined
+        )
+    logger.info(
+        "Verified Kerberos keytab for %s in %s",
+        principal,
+        HBASE_CONTAINER,
+    )
+
+
+def run_hbase_shell(username, shell_lines, service_user=False, 
expect_substring=None):
+    """
+    Run HBase shell commands inside ranger-hbase (stdin).
+
+    Returns (exit_code, combined_output).
+    """
+    hbase = get_docker_client().containers.get(HBASE_CONTAINER)
+    if service_user:
+        principal = HBASE_SERVICE_PRINCIPAL
+        keytab = HBASE_SERVICE_KEYTAB
+        ranger_user_label = "hbase (service)"
+    else:
+        principal = _user_principal(username)
+        keytab = _user_keytab_in_hbase_container(username)
+        ranger_user_label = username
+
+    script_body = "\n".join(shell_lines) + "\n"
+    logger.info("Going to run HBase shell script:\n%s", script_body)
+    logger.info(
+        "HBase shell context: container=%s docker_exec_user=hbase 
ranger_user=%s",
+        HBASE_CONTAINER,
+        ranger_user_label,
+    )
+
+    encoded = base64.b64encode(script_body.encode("utf-8")).decode("ascii")
+    hbase_cmd = "echo " + encoded + " | base64 -d | /opt/hbase/bin/hbase shell"
+    shell = (
+        "kdestroy -A 2>/dev/null || true; "
+        "kinit -kt "
+        + keytab
+        + " "
+        + principal
+        + "; "
+        + "kinit_rc=$?; "
+        + 'if [ "$kinit_rc" -ne 0 ]; then exit "$kinit_rc"; fi; '
+        + hbase_cmd
+    )
+    exit_code, output = hbase.exec_run(["bash", "-c", shell], user="hbase", 
demux=True)
+    stdout = (output[0] or b"").decode()
+    stderr = (output[1] or b"").decode()
+    combined = stdout + stderr
+
+    _log_multiline_block("HBase shell exit_code=%s stdout:" % exit_code, 
stdout)
+    _log_multiline_block("HBase shell stderr:", stderr)
+
+    if expect_substring:
+        if expect_substring in combined:
+            logger.info(
+                'Found expected string "%s" in HBase shell output',
+                expect_substring,
+            )
+        else:
+            logger.info(
+                'Expected string "%s" NOT found in HBase shell output',
+                expect_substring,
+            )
+
+    return exit_code, combined
+
+
+def prepare_hbase_test_table(table_name):
+    """Ensure test table is absent — runs as HBase service user."""
+    run_hbase_shell(
+        None,
+        [
+            "if exists '" + table_name + "'",
+            "  disable '" + table_name + "'",
+            "  drop '" + table_name + "'",
+            "end",
+        ],
+        service_user=True,
+    )
+
+
+def cleanup_hbase_test_table(table_name):
+    """Drop test table if present — runs as HBase service user."""
+    run_hbase_shell(
+        None,
+        [
+            "if exists '" + table_name + "'",
+            "  disable '" + table_name + "'",
+            "  drop '" + table_name + "'",
+            "end",
+        ],
+        service_user=True,
+    )
+
+
+def build_audit_only_policy_payload(service_name, suffix):
+    accesses = [
+        {"type": perm, "isAllowed": True}
+        for perm in HBASE_AUDIT_POLICY_ACCESS_TYPES
+    ]
+    return {
+        "isEnabled": True,
+        "service": service_name,
+        "name": "audit policy for hbase - " + suffix,
+        "policyType": 0,
+        "policyPriority": 0,
+        "description": "HBase audit policy for functional-tests",
+        "isAuditEnabled": True,
+        "resources": {
+            "table": {
+                "values": ["*"],
+                "isExcludes": False,
+                "isRecursive": False,
+            },
+            "column-family": {
+                "values": ["*"],
+                "isExcludes": False,
+                "isRecursive": False,
+            },
+            "column": {
+                "values": ["*"],
+                "isExcludes": False,
+                "isRecursive": False,
+            },
+        },
+        "policyItems": [
+            {
+                "accesses": accesses,
+                "users": list(HBASE_AUDIT_POLICY_SERVICE_USERS),
+                "groups": [],
+                "conditions": [],
+                "delegateAdmin": False,
+            }
+        ],
+        "denyPolicyItems": [],
+        "allowExceptions": [],
+        "denyExceptions": [],
+        "dataMaskPolicyItems": [],
+        "rowFilterPolicyItems": [],
+        "serviceType": "hbase",
+        "options": {},
+        "validitySchedules": [],
+        "policyLabels": [""],
+        "zoneName": "",
+    }
+
+
+def create_audit_only_policy(session, suffix=None, 
service_name=HBASE_SERVICE_NAME):
+    if suffix is None:
+        suffix = unique_suffix()
+    payload = build_audit_only_policy_payload(service_name, suffix)
+    response = session.post(POLICY_URL, json=payload)
+    assert_http_ok(response, (200, 201), "Create audit-only hbase policy", 
POLICY_URL)
+    body = response.json()
+    policy_id = body.get("id")
+    assert policy_id is not None, "Create policy response missing id: " + 
response.text
+    return policy_id, suffix
+
+
+def wait_for_hbase_policy_propagation(seconds=POLICY_PROPAGATION_SLEEP_SEC):
+    logger.info("Waiting %ss for HBase plugin policy propagation", seconds)
+    time.sleep(seconds)
diff --git a/functional-tests/ranger_test_utils/hive_utils.py 
b/functional-tests/ranger_test_utils/hive_utils.py
index a1361e080..a6e408625 100644
--- a/functional-tests/ranger_test_utils/hive_utils.py
+++ b/functional-tests/ranger_test_utils/hive_utils.py
@@ -21,9 +21,9 @@
 import pytest
 
 from ranger_test_utils.utils import (
+    DOCKER_PLUGIN_TEST_USER_PASSWORD,
     POLICY_URL,
     RANGER_ADMIN_BASE_URL,
-    XUSERS_BASE,
     assert_http_ok,
     get_test_logger,
     unique_suffix,
@@ -48,7 +48,7 @@
 )
 
 HIVE_TEST_USER = "hrt_21"
-HIVE_TEST_USER_PASSWORD = "Password@123"
+HIVE_TEST_USER_PASSWORD = DOCKER_PLUGIN_TEST_USER_PASSWORD
 
 HIVE_AUTHZ_DENIED_SUBSTR = "Permission denied"
 
@@ -299,33 +299,9 @@ def cleanup_hive_test_namespace(database, table):
     )
 
 
-def ensure_hive_test_user_in_ranger(session, username=HIVE_TEST_USER):
-    """Ensure hrt_21 exists in Ranger xusers (QE password)."""
-    lookup_url = XUSERS_BASE + "/users/userName/" + username
-    lookup = session.get(lookup_url)
-    if lookup.status_code == 200:
-        return
-    payload = {
-        "name": username,
-        "firstName": username,
-        "lastName": "hive_test",
-        "emailAddress": username + "@example.com",
-        "password": HIVE_TEST_USER_PASSWORD,
-        "status": 1,
-        "isVisible": 1,
-        "userSource": 1,
-        "userRoleList": ["ROLE_USER"],
-        "groupIdList": [],
-        "groupNameList": [],
-    }
-    create_url = XUSERS_BASE + "/secure/users"
-    create = session.post(create_url, json=payload)
-    assert_http_ok(create, 200, "Create Ranger user " + username, create_url)
-
-
 def run_beeline(username, sql, service_user=False, expect_substring=None):
     """
-    Run a beeline statement inside ranger-hive (-e, QE-style logging).
+    Run a beeline statement inside ranger-hive (-e).
 
     Returns (exit_code, combined_output).
     """
diff --git a/functional-tests/ranger_test_utils/utils.py 
b/functional-tests/ranger_test_utils/utils.py
index 4bcb1e03d..eb0931dbb 100644
--- a/functional-tests/ranger_test_utils/utils.py
+++ b/functional-tests/ranger_test_utils/utils.py
@@ -193,7 +193,16 @@ def log_testcase_begin_for_pytest(
 # --- xusers: ensure principals exist ---
 
 
-def ensure_user_exists(session, username):
+# Password for Docker plugin suites
+DOCKER_PLUGIN_TEST_USER_PASSWORD = "Password@123"
+
+
+def ensure_user_exists(
+    session,
+    username,
+    password="Test@123",
+    last_name="api_test",
+):
     """Create a Ranger user via xusers REST if it is not already present."""
     lookup_url = XUSERS_BASE + "/users/userName/" + username
     lookup = session.get(lookup_url)
@@ -202,9 +211,9 @@ def ensure_user_exists(session, username):
     payload = {
         "name": username,
         "firstName": username,
-        "lastName": "api_test",
+        "lastName": last_name,
         "emailAddress": username + "@example.com",
-        "password": "Test@123",
+        "password": password,
         "status": 1,
         "isVisible": 1,
         "userSource": 1,
diff --git a/functional-tests/readme.md b/functional-tests/readme.md
index 8bf786a95..f9f1e3d22 100644
--- a/functional-tests/readme.md
+++ b/functional-tests/readme.md
@@ -32,6 +32,7 @@ A Docker-based test execution framework that validates Apache 
Ranger service int
 | **tagrest** | Test cases for Ranger Admin Tag REST APIs |
 | **api** | Public API v2 service and policy CRUD (admin Docker only) |
 | **hive** | Hive Ranger plugin enforcement via HS2/beeline (requires 
`ranger-hadoop` + `ranger-hive`) |
+| **hbase** | HBase Ranger plugin enforcement via HBase shell (requires 
`ranger-hadoop` + `ranger-hbase`) |
 
 ### Directory Structure
 
@@ -39,6 +40,19 @@ A Docker-based test execution framework that validates 
Apache Ranger service int
 functional-tests/
 ├── multiple modules containing test cases
 ├── ...
+├── ranger_test_utils/utils.py   # Shared logging, HTTP asserts, Public API v2 
helpers
+├── hdfs/                        # Tests on HDFS encryption cycle
+├── kms/                         # Tests on KMS REST API
+├── xuserrest/                   # Tests on Ranger User/Group/Role REST APIs
+├── rolerest/                    # Tests on Ranger Role REST APIs
+├── servicerest/                 # Tests on Ranger Service REST APIs
+├── tagrest/                     # Tests on Ranger Tag REST APIs
+├── api/                         # Public API v2 (service / policy) tests
+├── hive/                        # Hive plugin enforcement tests
+├── hbase/                       # HBase plugin enforcement tests
+├── ranger_test_utils/hive_utils.py
+├── ranger_test_utils/hbase_utils.py
+├── ranger_test_utils/access_audit_utils.py  # For future access-audit asserts
 │
 ├── ranger_test_utils/utils.py   # Shared logging, HTTP asserts, Public API v2 
helpers
 ├── pytest.ini                   # Registers custom pytest markers
@@ -208,6 +222,12 @@ Brought up based on what you enter at the containers 
prompt (or `SELECTED_CONTAI
 - Tests currently assert **beeline authorization output only**. Hive access 
audits helpers live in `ranger_test_utils/access_audit_utils.py` for a 
follow-up once auditing works.
 - Example: `./run-tests.sh postgres hive`
 
+### HBase suite notes
+
+- Service repo name in Docker is `dev_hbase` (not QE `hbasedev`).
+- Tests currently assert **HBase shell authorization output only**. 
Access-audit helpers live in `ranger_test_utils/access_audit_utils.py` for a 
follow-up once auditing works.
+- Example: `./run-tests.sh postgres hbase`
+
 ## Test Reports
 
 After execution, an HTML report is automatically generated for each suite in 
the `functional-tests/` directory:
diff --git a/functional-tests/run-tests.sh b/functional-tests/run-tests.sh
index 56493c276..bd3d4940b 100755
--- a/functional-tests/run-tests.sh
+++ b/functional-tests/run-tests.sh
@@ -17,7 +17,7 @@
 
 # All available test suites (pytest folders)
 
-ALL_TEST_SUITES=(rolerest xuserrest servicerest tagrest hdfs kms api hive)
+ALL_TEST_SUITES=(rolerest xuserrest servicerest tagrest hdfs kms api hive 
hbase)
 
 # Test-only suites (no docker-compose file needed)
 TEST_ONLY_SUITES=(rolerest xuserrest servicerest tagrest api)

Reply via email to