|
12 | 12 |
|
13 | 13 | from datadog_checks.dev import TempDir, WaitFor, docker_run |
14 | 14 | from datadog_checks.dev.conditions import CheckDockerLogs |
| 15 | +from datadog_checks.mysql.version_utils import parse_version as parse_mysql_version |
15 | 16 |
|
16 | 17 | from . import common, tags |
17 | 18 | from .common import MYSQL_REPLICATION, MYSQL_VERSION_PARSED |
@@ -323,7 +324,10 @@ def version_metadata(): |
323 | 324 | 'version.raw': mock.ANY, |
324 | 325 | 'version.build': mock.ANY, |
325 | 326 | 'flavor': flavor, |
326 | | - 'resolved_hostname': 'forced_hostname', |
| 327 | + # Hostname resolution varies by environment but should always be a non-empty string |
| 328 | + # CI might use 'forced_hostname', local might use 'stubbed.hostname' or actual hostname |
| 329 | + # The actual value is tested separately in test_database_identifier and other tests |
| 330 | + 'resolved_hostname': mock.ANY, |
327 | 331 | } |
328 | 332 |
|
329 | 333 |
|
@@ -495,14 +499,19 @@ def init_master(): |
495 | 499 | _init_datadog_sample_collection(conn) |
496 | 500 |
|
497 | 501 |
|
498 | | -@pytest.fixture |
499 | | -def root_conn(): |
500 | | - conn = pymysql.connect( |
| 502 | +def _get_root_connection(): |
| 503 | + """Create a root connection to MySQL. Caller is responsible for closing.""" |
| 504 | + return pymysql.connect( |
501 | 505 | host=common.HOST, |
502 | 506 | port=common.PORT, |
503 | 507 | user='root', |
504 | 508 | password='mypass' if MYSQL_FLAVOR == 'percona' or MYSQL_REPLICATION in ('group', 'hybrid') else None, |
505 | 509 | ) |
| 510 | + |
| 511 | + |
| 512 | +@pytest.fixture |
| 513 | +def root_conn(): |
| 514 | + conn = _get_root_connection() |
506 | 515 | yield conn |
507 | 516 | conn.close() |
508 | 517 |
|
@@ -530,7 +539,10 @@ def _add_dog_user(conn): |
530 | 539 | # need to get better exception in order to raise errors in the future |
531 | 540 | except Exception: |
532 | 541 | if MYSQL_FLAVOR == 'mariadb': |
533 | | - cur.execute("GRANT SLAVE MONITOR ON *.* TO 'dog'@'%'") |
| 542 | + if MYSQL_VERSION_PARSED >= parse_version('10.5.0'): |
| 543 | + cur.execute("GRANT SLAVE MONITOR ON *.* TO 'dog'@'%'") |
| 544 | + else: |
| 545 | + cur.execute("GRANT REPLICATION CLIENT ON *.* TO 'dog'@'%'") |
534 | 546 | cur.execute("ALTER USER 'dog'@'%' WITH MAX_USER_CONNECTIONS 0") |
535 | 547 |
|
536 | 548 |
|
@@ -733,3 +745,46 @@ def _mysql_docker_repo(): |
733 | 745 | return 'percona/percona-server' |
734 | 746 | else: |
735 | 747 | raise ValueError('Unsupported MySQL flavor: {}'.format(MYSQL_FLAVOR)) |
| 748 | + |
| 749 | + |
| 750 | +# Runtime version detection fixtures |
| 751 | + |
| 752 | +# Well-known MySQL/MariaDB version thresholds |
| 753 | +JSON_AGGREGATION_MYSQL = (8, 0, 19) |
| 754 | +JSON_AGGREGATION_MARIADB = (10, 5, 0) |
| 755 | + |
| 756 | + |
| 757 | +@pytest.fixture(scope='session') |
| 758 | +def mysql_version(dd_environment): |
| 759 | + """ |
| 760 | + Query the actual MySQL/MariaDB version from the running database. |
| 761 | +
|
| 762 | + Returns the MySQLVersion object from version_utils with: |
| 763 | + - version: string like "8.0.32" |
| 764 | + - flavor: "MySQL", "MariaDB", or "Percona" |
| 765 | + - build: build info |
| 766 | + - version_compatible(tuple): method to check version >= tuple |
| 767 | +
|
| 768 | + Usage: |
| 769 | + def test_my_feature(mysql_version): |
| 770 | + if mysql_version.version_compatible((8, 0, 19)): |
| 771 | + # MySQL 8.0.19+ specific code |
| 772 | + """ |
| 773 | + conn = _get_root_connection() |
| 774 | + try: |
| 775 | + with conn.cursor() as cursor: |
| 776 | + cursor.execute("SELECT @@version, @@version_comment") |
| 777 | + version_str, version_comment = cursor.fetchone() |
| 778 | + |
| 779 | + mysql_ver = parse_mysql_version(version_str, version_comment) |
| 780 | + logger.info("Detected runtime MySQL version: %s %s", mysql_ver.flavor, mysql_ver.version) |
| 781 | + return mysql_ver |
| 782 | + finally: |
| 783 | + conn.close() |
| 784 | + |
| 785 | + |
| 786 | +def _supports_json_aggregation(mysql_version): |
| 787 | + """Check if the MySQL/MariaDB version supports JSON aggregation functions.""" |
| 788 | + if mysql_version.flavor.lower() == 'mariadb': |
| 789 | + return mysql_version.version_compatible(JSON_AGGREGATION_MARIADB) |
| 790 | + return mysql_version.version_compatible(JSON_AGGREGATION_MYSQL) |
0 commit comments