def test_02_vacuum_uniqness(self): """ [administration] 02: POST /administration/vacuum : Schedule & run 2 VACUUM orders on the same table, getting a 402 error is expected on the 2nd call """ # noqa dummy_dbname = 'test_temboard02' dummy_tablename = 'test_vacuum02' self._create_dummy_db(dummy_dbname) self._create_dummy_table(dummy_dbname, dummy_tablename) status = 0 try: (status, res) = temboard_request( ENV['agent']['ssl_cert_file'], method='POST', url='https://%s:%s/administration/vacuum' % ( ENV['agent']['host'], ENV['agent']['port'] ), headers={ "Content-type": "application/json", "X-Session": XSESSION }, data={ "database": dummy_dbname, "table": dummy_tablename, "mode": "standard" } ) except HTTPError as e: status = e.code if status != 200: self._drop_dummy_db(dummy_dbname) assert False else: status = 0 try: (status, res) = temboard_request( ENV['agent']['ssl_cert_file'], method='POST', url='https://%s:%s/administration/vacuum' % ( ENV['agent']['host'], ENV['agent']['port'] ), headers={ "Content-type": "application/json", "X-Session": XSESSION }, data={ "database": dummy_dbname, "table": dummy_tablename, "mode": "standard" } ) except HTTPError as e: status = e.code self._drop_dummy_db(dummy_dbname) assert status == 402
def test_23_post_settings_hba_ok(self): """ [settings] 23: POST /settings/hba : HTTP return code is 200 and the response data structure is right """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/settings/hba' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }, data = { 'entries': [ {'connection': 'local', 'database': 'all', 'user': '******', 'auth_method': 'trust', 'auth_options': 'blahblah'}, {'connection': 'host', 'database': 'test', 'user': '******', 'address': '192.168.1.0/24', 'auth_method': 'trust'}, {'connection': 'hostssl', 'database': 'test2', 'user': '******', 'address': '192.168.1.0 255.255.255.0', 'auth_method': 'trust'} ] }) dict_data = json.loads(res) md5sum_hba = self._exec_query('postgres', "SELECT md5(pg_read_file('pg_hba.conf')) AS md5sum_hba")[0]['md5sum_hba'] # Expected hba raw content. exp_hba_raw = "local all all trust blahblah\r\nhost test test 192.168.1.0/24 trust \r\nhostssl test2 test2 192.168.1.0 255.255.255.0 trust \r\n" assert status == 200 assert type(dict_data) == dict assert 'last_version' in dict_data assert 'filepath' in dict_data assert md5sum_hba == md5(exp_hba_raw).hexdigest()
def test_01_dashboard_ok(self): """ [dashboard] 01: GET /dashboard : HTTP return code is 200 and the data structure is right """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method='GET', url='https://%s:%s/dashboard' % (cf.G_HOST, cf.G_PORT), headers={ "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 \ and 'active_backends' in dict_data \ and 'loadaverage' in dict_data \ and 'os_version' in dict_data \ and 'pg_version' in dict_data \ and 'n_cpu' in dict_data \ and 'hitratio' in dict_data \ and 'databases' in dict_data \ and 'memory' in dict_data \ and 'hostname' in dict_data \ and 'cpu' in dict_data \ and 'buffers' in dict_data
def test_27_post_settings_hba_version_ok(self): """ [settings] 27: POST /settings/hba : HTTP return code is 200 and the response data structure is right """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/settings/hba' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }, data = { 'entries': [ {'connection': 'local', 'database': 'all', 'user': '******', 'auth_method': 'trust'} ], 'new_version': True }) dict_data = json.loads(res) md5sum_hba = self._exec_query('postgres', "SELECT md5(pg_read_file('pg_hba.conf')) AS md5sum_hba")[0]['md5sum_hba'] # Expected hba raw content. exp_hba_raw = "local all all trust \r\n" assert status == 200 assert type(dict_data) == dict assert 'last_version' in dict_data try: dt_version = datetime.datetime.strptime(dict_data['last_version'], "%Y-%m-%dT%H:%M:%S") except ValueError: assert False assert 'filepath' in dict_data assert md5sum_hba == md5(exp_hba_raw).hexdigest()
def test_11_get_pgconf_configuration_categories(self): """ [pgconf] 11: GET /pgconf/configuration/categories : HTTP return code is 200 and the response data structure is right """ # noqa (status, res) = temboard_request( ENV['agent']['ssl_cert_file'], method='GET', url='https://%s:%s/pgconf/configuration/categories' % (ENV['agent']['host'], ENV['agent']['port']), headers={ "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 assert 'categories' in dict_data assert type(dict_data['categories']) == list assert len(dict_data['categories']) == \ self._exec_query( 'postgres', "SELECT COUNT(DISTINCT(category)) AS nb " "FROM pg_settings")[0]['nb'] assert dict_data['categories'][0] == \ self._exec_query( 'postgres', "SELECT category FROM pg_settings " "ORDER BY category LIMIT 1")[0]['category']
def test_07_dashboard_memory_ok(self): """ [dashboard] 07: GET /dashboard/memory : HTTP return code is 200 and the data structure is right """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method='GET', url='https://%s:%s/dashboard/memory' % (cf.G_HOST, cf.G_PORT), headers={ "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 \ and 'memory' in dict_data \ and 'total' in dict_data['memory'] \ and type(dict_data['memory']['total']) == int \ and 'active' in dict_data['memory'] \ and type(dict_data['memory']['active']) == float \ and dict_data['memory']['active'] >= 0 \ and dict_data['memory']['active'] <= 100 \ and 'cached' in dict_data['memory'] \ and type(dict_data['memory']['cached']) == float \ and dict_data['memory']['cached'] >= 0 \ and dict_data['memory']['cached'] <= 100 \ and 'free' in dict_data['memory'] \ and type(dict_data['memory']['free']) == float \ and dict_data['memory']['free'] >= 0 \ and dict_data['memory']['free'] <= 100 \ and dict_data['memory']['active'] + dict_data['memory']['cached'] + dict_data['memory']['free'] >= 99.5 \ and dict_data['memory']['active'] + dict_data['memory']['cached'] + dict_data['memory']['free'] <= 100.5
def test_01_dashboard_ok(self): """ [dashboard] 01: GET /dashboard : HTTP return code is 200 and the data structure is right """ # noqa # Wait 1 second just to be sure dashboard collector ran once time.sleep(1) (status, res) = temboard_request(ENV['agent']['ssl_cert_file'], method='GET', url='https://%s:%s/dashboard' % (ENV['agent']['host'], ENV['agent']['port']), headers={ "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 \ and 'active_backends' in dict_data \ and 'max_connections' in dict_data \ and 'loadaverage' in dict_data \ and 'os_version' in dict_data \ and 'linux_distribution' in dict_data \ and 'cpu_models' in dict_data \ and isinstance(dict_data['cpu_models'], dict) \ and 'pg_version' in dict_data \ and 'n_cpu' in dict_data \ and 'hitratio' in dict_data \ and 'databases' in dict_data \ and 'memory' in dict_data \ and 'hostname' in dict_data \ and 'cpu' in dict_data \ and 'buffers' in dict_data
def test_17_get_settings_hba_ok(self): """ [settings] 17: GET /settings/hba : HTTP return code is 200 and the response data structure is right """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'GET', url = 'https://%s:%s/settings/hba' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 assert 'version' in dict_data assert 'filepath' in dict_data assert dict_data['version'] is None assert type(dict_data['filepath']) == unicode assert 'entries' in dict_data assert len(dict_data['entries']) > 0 for row in dict_data['entries']: if 'comment' not in row: assert 'connection' in row assert 'database' in row assert 'user' in row assert 'address' in row assert 'auth_method' in row assert 'auth_options' in row else: assert 'comment' in row
def test_10_dashboard_databases_ok(self): """ [dashboard] 10: GET /dashboard/databases : HTTP return code is 200 and the data structure is right """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method='GET', url='https://%s:%s/dashboard/databases' % (cf.G_HOST, cf.G_PORT), headers={ "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 \ and 'databases' in dict_data \ and 'total_size' in dict_data['databases'] \ and type(dict_data['databases']['total_size']) == unicode \ and 'time' in dict_data['databases'] \ and type(dict_data['databases']['time']) == unicode \ and 'databases' in dict_data['databases'] \ and type(dict_data['databases']['databases']) == int \ and dict_data['databases']['databases'] >= 0 \ and 'total_commit' in dict_data['databases'] \ and type(dict_data['databases']['total_commit']) == int \ and 'total_rollback' in dict_data['databases'] \ and type(dict_data['databases']['total_rollback']) == int
def test_04_post_settings_configuration_ok(self): """ [settings] 04: POST /settings/configuration : HTTP return code is 200 and the response data structure is right """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/settings/configuration' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }, data = {'settings': [{'name': 'autovacuum', 'setting': 'off'}]}) dict_data = json.loads(res) res_query = self._exec_query('postgres', "SELECT 1 AS t FROM regexp_split_to_table(pg_read_file('postgresql.auto.conf'),E'\n') AS l WHERE l = 'autovacuum = ''off'''") # HTTP return code is 200. assert status == 200 # Check new 'autovacuum' value is in postgresql.auto.conf. assert len(res_query) > 0 assert res_query[0]['t'] == 1 # Check response's structure. assert 'settings' in dict_data assert type(dict_data['settings']) == list assert len(dict_data['settings']) == 1 assert type(dict_data['settings'][0]) == dict assert 'setting' in dict_data['settings'][0] assert 'restart' in dict_data['settings'][0] assert 'name' in dict_data['settings'][0] assert 'previous_setting' in dict_data['settings'][0] assert dict_data['settings'][0]['name'] == 'autovacuum' assert dict_data['settings'][0]['setting'] == 'off'
def test_49_post_settings_pg_ident_ok(self): """ [settings] 49: POST /settings/pg_ident : HTTP return code is 200 and the response data structure is right """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/settings/pg_ident' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }, data = { 'content': '# test\r\n# test\r\n' }) dict_data = json.loads(res) md5sum_pg_ident = self._exec_query('postgres', "SELECT md5(pg_read_file('pg_ident.conf')) AS md5sum_pg_ident")[0]['md5sum_pg_ident'] # Expected hba raw content. exp_pg_ident_raw = "# test\r\n# test\r\n" assert status == 200 assert type(dict_data) == dict assert 'update' in dict_data assert dict_data['update'] is True assert md5sum_pg_ident == md5(exp_pg_ident_raw).hexdigest()
def _temboard_login(self): (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/login' % (cf.G_HOST, cf.G_PORT), headers = {"Content-type": "application/json"}, data = {'username': cf.G_USER, 'password': cf.G_PASSWORD}) return json.loads(res)['session']
def test_01_activity_root(self): """ [activity] 01: GET /activity : Check HTTP code (200) and the whole data structure """ # noqa # Start a long query in a dedicated process. p = Process(target=pg_sleep, args=(1,)) p.start() status = 0 try: (status, res) = temboard_request( ENV['agent']['ssl_cert_file'], method='GET', url='https://%s:%s/activity' % (ENV['agent']['host'], ENV['agent']['port']), headers={ "Content-type": "application/json", "X-Session": XSESSION } ) except HTTPError as e: status = e.code dict_data = json.loads(res) # Join the process p.join() assert status == 200 assert 'rows' in dict_data assert type(dict_data['rows']) == list assert type(dict_data['rows'][0]) == dict assert 'pid' in dict_data['rows'][0] assert 'database' in dict_data['rows'][0] assert 'user' in dict_data['rows'][0] assert 'client' in dict_data['rows'][0] assert 'cpu' in dict_data['rows'][0] assert 'memory' in dict_data['rows'][0] assert 'read_s' in dict_data['rows'][0] assert 'write_s' in dict_data['rows'][0] assert 'iow' in dict_data['rows'][0] assert 'wait' in dict_data['rows'][0] assert 'duration' in dict_data['rows'][0] assert 'state' in dict_data['rows'][0] assert 'query' in dict_data['rows'][0] assert type(dict_data['rows'][0]['pid']) == int assert type(dict_data['rows'][0]['database']) == unicode assert type(dict_data['rows'][0]['user']) == unicode # can be float or 'N/A' assert type(dict_data['rows'][0]['cpu']) in (float, unicode) assert type(dict_data['rows'][0]['memory']) == float assert type(dict_data['rows'][0]['read_s']) == unicode assert type(dict_data['rows'][0]['write_s']) == unicode assert type(dict_data['rows'][0]['iow']) == unicode assert type(dict_data['rows'][0]['wait']) == unicode assert type(dict_data['rows'][0]['duration']) in (float, int) assert type(dict_data['rows'][0]['state']) in (unicode, type(None)) assert type(dict_data['rows'][0]['query']) in (unicode, type(None))
def test_31_get_settings_hba_version_ok(self): """ [settings] 31: GET /settings/hba?version=:version : HTTP return code is 200 and the response data structure is right """ # We need do get the last version id. (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'GET', url = 'https://%s:%s/settings/hba/versions' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 assert 'filepath' in dict_data assert 'versions' in dict_data assert type(dict_data['versions']) == list assert len(dict_data['versions']) == 1 assert os.path.isfile("%s.%s" % (dict_data['filepath'], dict_data['versions'][0])) last_version = dict_data['versions'][0] (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'GET', url = 'https://%s:%s/settings/hba?version=%s' % (cf.G_HOST, cf.G_PORT, last_version), headers = { "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 assert 'version' in dict_data assert 'filepath' in dict_data assert dict_data['version'] == last_version assert type(dict_data['filepath']) == unicode assert 'entries' in dict_data assert len(dict_data['entries']) > 0 assert 'connection' in dict_data['entries'][0] assert 'database' in dict_data['entries'][0] assert 'user' in dict_data['entries'][0] assert 'address' in dict_data['entries'][0] assert 'auth_method' in dict_data['entries'][0] assert 'auth_options' in dict_data['entries'][0]
def test_statements_not_enabled(xsession): try: status, res = temboard_request( ENV["agent"]["ssl_cert_file"], method="GET", url="https://{host}:{port}/statements".format(**ENV["agent"]), headers={"X-Session": xsession}, ) except urllib2.HTTPError as e: status = e.code assert status == 404
def test_01_login_ok(self): """ [api] 01: POST /login : HTTP return code is 200 on valid credentials """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/login' % (cf.G_HOST, cf.G_PORT), headers = {"Content-type": "application/json"}, data = {'username': cf.G_USER, 'password': cf.G_PASSWORD}) assert status == 200
def test_02_login_ok(self): """ [api] 02: POST /login : Session ID format matches ^[a-f0-9]{64}$ """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/login' % (cf.G_HOST, cf.G_PORT), headers = {"Content-type": "application/json"}, data = {'username': cf.G_USER, 'password': cf.G_PASSWORD}) xsession = json.loads(res)['session'] assert re.match('^[a-f0-9]{64}$', xsession)
def _temboard_login(self): (status, res) = temboard_request(ENV['agent']['ssl_cert_file'], method='POST', url='https://%s:%s/login' % (ENV['agent']['host'], ENV['agent']['port']), headers={"Content-type": "application/json"}, data={ 'username': ENV['agent']['user'], 'password': ENV['agent']['password'] }) return json.loads(res)['session']
def get_statements(): try: status, res = temboard_request( ENV["agent"]["ssl_cert_file"], method="GET", url="https://{host}:{port}/statements".format(**ENV["agent"]), headers={"X-Session": xsession}, ) except urllib2.HTTPError as e: status = e.code assert status == 200 return json.loads(res)
def test_29_get_settings_hba_versions_ko_401(self): """ [settings] 29: GET /settings/hba/versions: HTTP return code is 401 on invalid xsession. """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'GET', url = 'https://%s:%s/settings/hba/versions' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": "3b28ed94743e3ada57b217bbf9f36c6d1eb45e669a1ab693e8ca7ac3bd070b9e" }) assert status == 401
def test_16_get_settings_configuration_category_ko_406(self): """ [settings] 16: GET /settings/configuration/category/:categoryname : HTTP return code is 406 on malformed xsession """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'GET', url = 'https://%s:%s/settings/configuration/category/Autovacuum' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": "XXXXXXXXXXX" }) assert status == 406
def test_15_get_settings_configuration_category_ko_401(self): """ [settings] 15: GET /settings/configuration/category/:categoryname : HTTP return code is 401 on invalid xsession """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'GET', url = 'https://%s:%s/settings/configuration/category/Autovacuum' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": "3b28ed94743e3ada57b217bbf9f36c6d1eb45e669a1ab693e8ca7ac3bd070b9e" }) assert status == 401
def test_30_get_settings_hba_versions_ko_406(self): """ [settings] 30: GET /settings/hba/versions: HTTP return code is 406 on malformed xsession. """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'GET', url = 'https://%s:%s/settings/hba/versions' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": "XXXXXXXXXXX" }) assert status == 406
def test_37_delete_settings_hba_version_ok(self): """ [settings] 37: DELETE /settings/hba/raw?version=:version : HTTP return code is 200 and data structure is right """ # We need do get the last version id. (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'GET', url = 'https://%s:%s/settings/hba/versions' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 assert 'filepath' in dict_data assert 'versions' in dict_data assert type(dict_data['versions']) == list assert len(dict_data['versions']) == 1 assert os.path.isfile("%s.%s" % (dict_data['filepath'], dict_data['versions'][0])) last_version = dict_data['versions'][0] filepath = dict_data['filepath'] (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'DELETE', url = 'https://%s:%s/settings/hba?version=%s' % (cf.G_HOST, cf.G_PORT, last_version), headers = { "Content-type": "application/json", "X-Session": XSESSION }) dict_data = json.loads(res) assert status == 200 assert 'deleted' in dict_data assert 'version' in dict_data assert dict_data['version'] == last_version assert dict_data['deleted'] is True assert not os.path.isfile("%s.%s" % (filepath, last_version))
def test_05_post_settings_configuration_ko_401(self): """ [settings] 05: POST /settings/configuration : HTTP return code is 401 on invalid xsession """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/settings/configuration' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": "3b28ed94743e3ada57b217bbf9f36c6d1eb45e669a1ab693e8ca7ac3bd070b9e" }, data = {'settings': [{'name': 'autovacuum', 'setting': 'off'}]}) assert status == 401
def test_06_get_settings_configuration_ko_406(self): """ [settings] 06: POST /settings/configuration : HTTP return code is 406 on malformed xsession """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/settings/configuration' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": "XXXXXXXXXXX" }, data = {'settings': [{'name': 'autovacuum', 'setting': 'off'}]}) assert status == 406
def test_07_post_settings_configuration_ko_400(self): """ [settings] 07: POST /settings/configuration : HTTP return code is 400 on invalid json data """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'POST', url = 'https://%s:%s/settings/configuration' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }, data = '') assert status == 400
def test_41_delete_settings_hba_version_ko_404(self): """ [settings] 41: DELETE /settings/hba/raw?version=:version : HTTP return code is 404 on unexisting version """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'DELETE', url = 'https://%s:%s/settings/hba?version=1970-01-01T00:00:01' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }) assert status == 404
def test_40_delete_settings_hba_version_ko_406(self): """ [settings] 40: DELETE /settings/hba/raw?version=:version : HTTP return code is 406 on malformed version id """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'DELETE', url = 'https://%s:%s/settings/hba?version=1122XXGGHH' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": XSESSION }) assert status == 406
def test_38_delete_settings_hba_version_ko_401(self): """ [settings] 38: DELETE /settings/hba/raw?version=:version : HTTP return code is 401 on invalid xsession """ (status, res) = temboard_request( ENV['g_ssl_cert_file_path'], method = 'DELETE', url = 'https://%s:%s/settings/hba?version=1970-01-01T00:00:01' % (cf.G_HOST, cf.G_PORT), headers = { "Content-type": "application/json", "X-Session": "3b28ed94743e3ada57b217bbf9f36c6d1eb45e669a1ab693e8ca7ac3bd070b9e" }) assert status == 401