2025-01-03 07:16:40 +00:00
|
|
|
import unittest
|
|
|
|
|
|
2025-01-08 07:39:20 +00:00
|
|
|
from datetime import datetime, timedelta
|
2025-01-08 22:01:11 +00:00
|
|
|
import tempfile
|
|
|
|
|
|
|
|
|
|
import logging
|
2025-01-08 07:39:20 +00:00
|
|
|
|
2025-01-03 07:16:40 +00:00
|
|
|
import pgmon
|
|
|
|
|
|
2025-01-08 22:01:11 +00:00
|
|
|
# Silence most logging output
|
|
|
|
|
logging.disable(logging.CRITICAL)
|
|
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
|
2025-01-03 07:16:40 +00:00
|
|
|
class TestPgmonMethods(unittest.TestCase):
|
2025-05-13 05:44:47 +00:00
|
|
|
##
|
|
|
|
|
# update_deep
|
|
|
|
|
##
|
|
|
|
|
def test_update_deep__empty_cases(self):
|
|
|
|
|
# Test empty dict cases
|
|
|
|
|
d1 = {}
|
|
|
|
|
d2 = {}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {})
|
|
|
|
|
self.assertEqual(d2, {})
|
|
|
|
|
|
|
|
|
|
d1 = {"a": 1}
|
|
|
|
|
d2 = {}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"a": 1})
|
|
|
|
|
self.assertEqual(d2, {})
|
|
|
|
|
|
|
|
|
|
d1 = {}
|
|
|
|
|
d2 = {"a": 1}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"a": 1})
|
|
|
|
|
self.assertEqual(d2, d1)
|
|
|
|
|
|
|
|
|
|
def test_update_deep__scalars(self):
|
|
|
|
|
# Test adding/updating scalar values
|
|
|
|
|
d1 = {"foo": 1, "bar": "text", "hello": "world"}
|
|
|
|
|
d2 = {"foo": 2, "baz": "blah"}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"foo": 2, "bar": "text", "baz": "blah", "hello": "world"})
|
|
|
|
|
self.assertEqual(d2, {"foo": 2, "baz": "blah"})
|
|
|
|
|
|
|
|
|
|
def test_update_deep__lists(self):
|
|
|
|
|
# Test adding to lists
|
|
|
|
|
d1 = {"lst1": []}
|
|
|
|
|
d2 = {"lst1": [1, 2]}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"lst1": [1, 2]})
|
|
|
|
|
self.assertEqual(d2, d1)
|
|
|
|
|
|
|
|
|
|
d1 = {"lst1": [1, 2]}
|
|
|
|
|
d2 = {"lst1": []}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"lst1": [1, 2]})
|
|
|
|
|
self.assertEqual(d2, {"lst1": []})
|
|
|
|
|
|
|
|
|
|
d1 = {"lst1": [1, 2, 3]}
|
|
|
|
|
d2 = {"lst1": [3, 4]}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"lst1": [1, 2, 3, 3, 4]})
|
|
|
|
|
self.assertEqual(d2, {"lst1": [3, 4]})
|
|
|
|
|
|
|
|
|
|
# Lists of objects
|
|
|
|
|
d1 = {"lst1": [{"id": 1}, {"id": 2}, {"id": 3}]}
|
|
|
|
|
d2 = {"lst1": [{"id": 3}, {"id": 4}]}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
d1, {"lst1": [{"id": 1}, {"id": 2}, {"id": 3}, {"id": 3}, {"id": 4}]}
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(d2, {"lst1": [{"id": 3}, {"id": 4}]})
|
|
|
|
|
|
|
|
|
|
# Nested lists
|
|
|
|
|
d1 = {"obj1": {"l1": [1, 2]}}
|
|
|
|
|
d2 = {"obj1": {"l1": [3, 4]}}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"obj1": {"l1": [1, 2, 3, 4]}})
|
|
|
|
|
self.assertEqual(d2, {"obj1": {"l1": [3, 4]}})
|
|
|
|
|
|
|
|
|
|
def test_update_deep__dicts(self):
|
|
|
|
|
# Test adding to lists
|
|
|
|
|
d1 = {"obj1": {}}
|
|
|
|
|
d2 = {"obj1": {"a": 1, "b": 2}}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"obj1": {"a": 1, "b": 2}})
|
|
|
|
|
self.assertEqual(d2, d1)
|
|
|
|
|
|
|
|
|
|
d1 = {"obj1": {"a": 1, "b": 2}}
|
|
|
|
|
d2 = {"obj1": {}}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"obj1": {"a": 1, "b": 2}})
|
|
|
|
|
self.assertEqual(d2, {"obj1": {}})
|
|
|
|
|
|
|
|
|
|
d1 = {"obj1": {"a": 1, "b": 2}}
|
|
|
|
|
d2 = {"obj1": {"a": 5, "c": 12}}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"obj1": {"a": 5, "b": 2, "c": 12}})
|
|
|
|
|
self.assertEqual(d2, {"obj1": {"a": 5, "c": 12}})
|
|
|
|
|
|
|
|
|
|
# Nested dicts
|
|
|
|
|
d1 = {"obj1": {"d1": {"a": 1, "b": 2}}}
|
|
|
|
|
d2 = {"obj1": {"d1": {"a": 5, "c": 12}}}
|
|
|
|
|
pgmon.update_deep(d1, d2)
|
|
|
|
|
self.assertEqual(d1, {"obj1": {"d1": {"a": 5, "b": 2, "c": 12}}})
|
|
|
|
|
self.assertEqual(d2, {"obj1": {"d1": {"a": 5, "c": 12}}})
|
|
|
|
|
|
|
|
|
|
def test_update_deep__types(self):
|
|
|
|
|
# Test mismatched types
|
|
|
|
|
d1 = {"foo": 5}
|
|
|
|
|
d2 = None
|
|
|
|
|
self.assertRaises(TypeError, pgmon.update_deep, d1, d2)
|
|
|
|
|
|
|
|
|
|
d1 = None
|
|
|
|
|
d2 = {"foo": 5}
|
|
|
|
|
self.assertRaises(TypeError, pgmon.update_deep, d1, d2)
|
|
|
|
|
|
|
|
|
|
# Nested mismatched types
|
|
|
|
|
d1 = {"foo": [1, 2]}
|
|
|
|
|
d2 = {"foo": {"a": 7}}
|
|
|
|
|
self.assertRaises(TypeError, pgmon.update_deep, d1, d2)
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
|
# get_pool
|
|
|
|
|
##
|
|
|
|
|
|
|
|
|
|
def test_get_pool__simple(self):
|
|
|
|
|
# Just get a pool in a normal case
|
|
|
|
|
pgmon.config.update(pgmon.default_config)
|
|
|
|
|
pool = pgmon.get_pool("postgres")
|
|
|
|
|
self.assertIsNotNone(pool)
|
|
|
|
|
|
|
|
|
|
def test_get_pool__unhappy(self):
|
|
|
|
|
# Test getting an unhappy database pool
|
|
|
|
|
pgmon.config.update(pgmon.default_config)
|
|
|
|
|
pgmon.unhappy_cooldown["postgres"] = datetime.now() + timedelta(60)
|
|
|
|
|
self.assertRaises(pgmon.UnhappyDBError, pgmon.get_pool, "postgres")
|
|
|
|
|
|
|
|
|
|
# Test getting a different database when there's an unhappy one
|
|
|
|
|
pool = pgmon.get_pool("template0")
|
|
|
|
|
self.assertIsNotNone(pool)
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
|
# handle_connect_failure
|
|
|
|
|
##
|
|
|
|
|
|
|
|
|
|
def test_handle_connect_failure__simple(self):
|
|
|
|
|
# Test adding to an empty unhappy list
|
|
|
|
|
pgmon.config.update(pgmon.default_config)
|
|
|
|
|
pgmon.unhappy_cooldown = {}
|
|
|
|
|
pool = pgmon.get_pool("postgres")
|
|
|
|
|
pgmon.handle_connect_failure(pool)
|
|
|
|
|
self.assertGreater(pgmon.unhappy_cooldown["postgres"], datetime.now())
|
|
|
|
|
|
|
|
|
|
# Test adding another database
|
|
|
|
|
pool = pgmon.get_pool("template0")
|
|
|
|
|
pgmon.handle_connect_failure(pool)
|
|
|
|
|
self.assertGreater(pgmon.unhappy_cooldown["postgres"], datetime.now())
|
|
|
|
|
self.assertGreater(pgmon.unhappy_cooldown["template0"], datetime.now())
|
|
|
|
|
self.assertEqual(len(pgmon.unhappy_cooldown), 2)
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
|
# get_query
|
|
|
|
|
##
|
|
|
|
|
|
|
|
|
|
def test_get_query__basic(self):
|
|
|
|
|
# Test getting a query with one version
|
|
|
|
|
metric = {"type": "value", "query": {0: "DEFAULT"}}
|
|
|
|
|
self.assertEqual(pgmon.get_query(metric, 100000), "DEFAULT")
|
|
|
|
|
|
|
|
|
|
def test_get_query__versions(self):
|
|
|
|
|
metric = {"type": "value", "query": {0: "DEFAULT", 110000: "NEW"}}
|
|
|
|
|
|
|
|
|
|
# Test getting the default version of a query with no lower bound and a newer version
|
|
|
|
|
self.assertEqual(pgmon.get_query(metric, 100000), "DEFAULT")
|
|
|
|
|
|
|
|
|
|
# Test getting the newer version of a query with no lower bound and a newer version for the newer version
|
|
|
|
|
self.assertEqual(pgmon.get_query(metric, 110000), "NEW")
|
|
|
|
|
|
|
|
|
|
# Test getting the newer version of a query with no lower bound and a newer version for an even newer version
|
|
|
|
|
self.assertEqual(pgmon.get_query(metric, 160000), "NEW")
|
|
|
|
|
|
|
|
|
|
# Test getting a version in bwtween two other versions
|
|
|
|
|
metric = {"type": "value", "query": {0: "DEFAULT", 96000: "OLD", 110000: "NEW"}}
|
|
|
|
|
self.assertEqual(pgmon.get_query(metric, 100000), "OLD")
|
|
|
|
|
|
|
|
|
|
def test_get_query__missing_version(self):
|
|
|
|
|
metric = {"type": "value", "query": {96000: "OLD", 110000: "NEW", 150000: ""}}
|
|
|
|
|
|
|
|
|
|
# Test getting a metric that only exists for newer versions
|
|
|
|
|
self.assertRaises(pgmon.MetricVersionError, pgmon.get_query, metric, 80000)
|
|
|
|
|
|
|
|
|
|
# Test getting a metric that only exists for older versions
|
|
|
|
|
self.assertRaises(pgmon.MetricVersionError, pgmon.get_query, metric, 160000)
|
|
|
|
|
|
|
|
|
|
##
|
|
|
|
|
# read_config
|
|
|
|
|
##
|
|
|
|
|
|
|
|
|
|
def test_read_config__simple(self):
|
|
|
|
|
pgmon.config = {}
|
|
|
|
|
|
|
|
|
|
# Test reading just a metric and using the defaults for everything else
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
# This is a comment!
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: TEST1
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
pgmon.read_config(f"{tmpdirname}/config.yml")
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
self.assertEqual(
|
|
|
|
|
pgmon.config["max_pool_size"], pgmon.default_config["max_pool_size"]
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], pgmon.default_config["dbuser"])
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
pgmon.config = {}
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
# Test reading a basic config
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
# This is a comment!
|
|
|
|
|
min_pool_size: 1
|
|
|
|
|
max_pool_size: 2
|
|
|
|
|
max_idle_time: 10
|
|
|
|
|
log_level: debug
|
|
|
|
|
dbuser: someone
|
|
|
|
|
dbhost: localhost
|
|
|
|
|
dbport: 5555
|
|
|
|
|
dbname: template0
|
|
|
|
|
pool_slot_timeout: 1
|
|
|
|
|
connect_timeout: 1
|
|
|
|
|
reconnect_cooldown: 15
|
|
|
|
|
version_check_period: 3600
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: TEST1
|
|
|
|
|
test2:
|
|
|
|
|
type: set
|
|
|
|
|
query:
|
|
|
|
|
0: TEST2
|
|
|
|
|
test3:
|
|
|
|
|
type: row
|
|
|
|
|
query:
|
|
|
|
|
0: TEST3
|
|
|
|
|
test4:
|
|
|
|
|
type: column
|
|
|
|
|
query:
|
|
|
|
|
0: TEST4
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
pgmon.read_config(f"{tmpdirname}/config.yml")
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
self.assertEqual(pgmon.config["dbuser"], "someone")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["type"], "value")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test2"]["query"][0], "TEST2")
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
def test_read_config__include(self):
|
|
|
|
|
pgmon.config = {}
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
# Test reading a config that includes other files (absolute and relative paths, multiple levels)
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
f"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
# This is a comment!
|
|
|
|
|
min_pool_size: 1
|
|
|
|
|
max_pool_size: 2
|
|
|
|
|
max_idle_time: 10
|
|
|
|
|
log_level: debug
|
|
|
|
|
pool_slot_timeout: 1
|
|
|
|
|
connect_timeout: 1
|
|
|
|
|
reconnect_cooldown: 15
|
|
|
|
|
version_check_period: 3600
|
|
|
|
|
include:
|
|
|
|
|
- dbsettings.yml
|
|
|
|
|
- {tmpdirname}/metrics.yml
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
with open(f"{tmpdirname}/dbsettings.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
f"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: someone
|
|
|
|
|
dbhost: localhost
|
|
|
|
|
dbport: 5555
|
|
|
|
|
dbname: template0
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
with open(f"{tmpdirname}/metrics.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
f"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: TEST1
|
|
|
|
|
test2:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: TEST2
|
|
|
|
|
include:
|
|
|
|
|
- more_metrics.yml
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
with open(f"{tmpdirname}/more_metrics.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
f"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
metrics:
|
|
|
|
|
test3:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: TEST3
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
pgmon.read_config(f"{tmpdirname}/config.yml")
|
|
|
|
|
|
|
|
|
|
self.assertEqual(pgmon.config["max_idle_time"], 10)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "someone")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test2"]["query"][0], "TEST2")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test3"]["query"][0], "TEST3")
|
|
|
|
|
|
|
|
|
|
def test_read_config__reload(self):
|
|
|
|
|
pgmon.config = {}
|
|
|
|
|
|
|
|
|
|
# Test rereading a config to update an existing config
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
# This is a comment!
|
|
|
|
|
min_pool_size: 1
|
|
|
|
|
max_pool_size: 2
|
|
|
|
|
max_idle_time: 10
|
|
|
|
|
log_level: debug
|
|
|
|
|
dbuser: someone
|
|
|
|
|
dbhost: localhost
|
|
|
|
|
dbport: 5555
|
|
|
|
|
dbname: template0
|
|
|
|
|
pool_slot_timeout: 1
|
|
|
|
|
connect_timeout: 1
|
|
|
|
|
reconnect_cooldown: 15
|
|
|
|
|
version_check_period: 3600
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: TEST1
|
|
|
|
|
test2:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: TEST2
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
pgmon.read_config(f"{tmpdirname}/config.yml")
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
# Just make sure the first config was read
|
|
|
|
|
self.assertEqual(len(pgmon.config["metrics"]), 2)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
# This is a comment!
|
|
|
|
|
min_pool_size: 7
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: NEW1
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
pgmon.read_config(f"{tmpdirname}/config.yml")
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
self.assertEqual(pgmon.config["min_pool_size"], 7)
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "NEW1")
|
|
|
|
|
self.assertEqual(len(pgmon.config["metrics"]), 1)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
def test_read_config__query_file(self):
|
|
|
|
|
pgmon.config = {}
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
# Read a config file that reads a query from a file
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: file:some_query.sql
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
with open(f"{tmpdirname}/some_query.sql", "w") as f:
|
|
|
|
|
f.write("This is a query")
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
pgmon.read_config(f"{tmpdirname}/config.yml")
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
self.assertEqual(
|
|
|
|
|
pgmon.config["metrics"]["test1"]["query"][0], "This is a query"
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
def test_read_config__invalid(self):
|
|
|
|
|
pgmon.config = {}
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
# For all of these tests, we start with a valid config and also ensure that
|
|
|
|
|
# it is not modified when a new config read fails
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: TEST1
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
pgmon.read_config(f"{tmpdirname}/config.yml")
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
# Just make sure the config was read
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
# Test reading a nonexistant config file
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
FileNotFoundError, pgmon.read_config, f"{tmpdirname}/missing.yml"
|
|
|
|
|
)
|
2025-01-08 22:01:11 +00:00
|
|
|
|
2025-05-13 05:44:47 +00:00
|
|
|
# Test reading an invalid config file
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""[default]
|
2025-01-08 22:01:11 +00:00
|
|
|
This looks a lot like an ini file to me
|
|
|
|
|
|
|
|
|
|
Or maybe a TOML?
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Test reading a config that includes an invalid file
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: EVIL1
|
|
|
|
|
include:
|
|
|
|
|
- missing_file.yml
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
FileNotFoundError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test invalid log level
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
log_level: noisy
|
|
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: EVIL1
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test invalid query return type
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: lots_of_data
|
|
|
|
|
query:
|
|
|
|
|
0: EVIL1
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test invalid query dict type
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: lots_of_data
|
|
|
|
|
query: EVIL1
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test incomplete metric: missing type
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
query:
|
|
|
|
|
0: EVIL1
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test incomplete metric: missing queries
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test incomplete metric: empty queries
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query: {}
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test incomplete metric: query dict is None
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test reading a config with no metrics
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test reading a query defined in a file but the file is missing
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
0: file:missing.sql
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
FileNotFoundError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|
|
|
|
|
|
|
|
|
|
# Test invalid query versions
|
|
|
|
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
|
|
|
with open(f"{tmpdirname}/config.yml", "w") as f:
|
|
|
|
|
f.write(
|
|
|
|
|
"""---
|
2025-01-08 22:01:11 +00:00
|
|
|
dbuser: evil
|
|
|
|
|
metrics:
|
|
|
|
|
test1:
|
|
|
|
|
type: value
|
|
|
|
|
query:
|
|
|
|
|
default: EVIL1
|
2025-05-13 05:44:47 +00:00
|
|
|
"""
|
|
|
|
|
)
|
|
|
|
|
self.assertRaises(
|
|
|
|
|
pgmon.ConfigError, pgmon.read_config, f"{tmpdirname}/config.yml"
|
|
|
|
|
)
|
|
|
|
|
self.assertEqual(pgmon.config["dbuser"], "postgres")
|
|
|
|
|
self.assertEqual(pgmon.config["metrics"]["test1"]["query"][0], "TEST1")
|