241 lines
9.0 KiB
Python
241 lines
9.0 KiB
Python
# Copyright (c) 2019 VMware, Inc. All rights reserved.
|
|
#
|
|
# Licensed 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 __future__ import print_function
|
|
from __future__ import division
|
|
from __future__ import absolute_import
|
|
|
|
from unittest import mock
|
|
import uuid
|
|
|
|
from congress.datasources import datasource_driver
|
|
from congress.datasources.json_ingester import json_ingester
|
|
from congress import exception
|
|
from congress.tests import base
|
|
|
|
|
|
class TestJsonIngester(base.TestCase):
|
|
|
|
@mock.patch('congress.datasources.datasource_utils.get_keystone_session')
|
|
@mock.patch.object(
|
|
datasource_driver.PollingDataSourceDriver, '_init_end_start_poll')
|
|
@mock.patch.object(
|
|
json_ingester.JsonIngester, '_create_schema_and_tables')
|
|
def setUp(self, _create_schema_and_tables, _init_end_start_poll,
|
|
get_keystone_session):
|
|
super(TestJsonIngester, self).setUp()
|
|
|
|
self.test_config = {
|
|
"api_endpoint": "http://127.0.0.1/compute/v2.1/",
|
|
"tables": {
|
|
"flavors": {
|
|
"poll": {
|
|
"api_method": "get",
|
|
"api_path": "flavors/detail",
|
|
"jsonpath": "$.flavors[:]"
|
|
}
|
|
},
|
|
"servers": {
|
|
"poll": {
|
|
"api_method": "get",
|
|
"api_path": "servers/detail",
|
|
"jsonpath": "$.servers[:]"
|
|
}
|
|
},
|
|
"alarms": {
|
|
"webhook": {
|
|
"record_jsonpath": "$.payload",
|
|
"id_jsonpath": "$.id"
|
|
}
|
|
}
|
|
},
|
|
"authentication": {
|
|
"type": "keystone",
|
|
"config": {
|
|
"username": "admin",
|
|
"project_name": "admin",
|
|
"password": "password",
|
|
"auth_url": "http://127.0.0.1/identity"
|
|
}
|
|
},
|
|
"poll_interval": 1,
|
|
"name": "nova"
|
|
}
|
|
|
|
from congress.datasources.json_ingester import exec_api
|
|
# exec_manager = exec_api.ExecApiManager([])
|
|
exec_manager_mock = mock.Mock(spec=exec_api.ExecApiManager)
|
|
self.test_driver = json_ingester.JsonIngester(
|
|
self.test_config['name'], self.test_config, exec_manager_mock)
|
|
|
|
def test_invalid_config_poll_plus_webhook(self):
|
|
invalid_config = self.test_config
|
|
invalid_config['tables']['servers']['webhook'] = {
|
|
"record_jsonpath": "$.payload",
|
|
"id_jsonpath": "$.id"}
|
|
self.assertRaises(
|
|
exception.BadConfig, json_ingester.JsonIngester,
|
|
invalid_config['name'], invalid_config, None)
|
|
|
|
@mock.patch.object(json_ingester.JsonIngester, '_update_table')
|
|
def test_poll(self, _update_table):
|
|
mock_api_result = {
|
|
"servers": [
|
|
{"server": 1},
|
|
{"server": 2},
|
|
{"server": 3}
|
|
],
|
|
"flavors": [],
|
|
"servers_links": [
|
|
{
|
|
"href": "blah",
|
|
"rel": "next"
|
|
}
|
|
]
|
|
}
|
|
servers_api_result_str_set = set(
|
|
['{"server": 1}', '{"server": 2}', '{"server": 3}'])
|
|
self.test_driver._session.get.return_value.json.return_value = \
|
|
mock_api_result
|
|
|
|
# test initial poll
|
|
self.test_driver.poll()
|
|
self.assertEqual(_update_table.call_count, 2)
|
|
_update_table.assert_any_call(
|
|
'servers',
|
|
new_data=servers_api_result_str_set,
|
|
old_data=set([]), use_snapshot=True)
|
|
_update_table.assert_any_call(
|
|
'flavors', new_data=set([]), old_data=set([]), use_snapshot=True)
|
|
|
|
_update_table.reset_mock()
|
|
|
|
# test subsequent poll
|
|
self.test_driver.poll()
|
|
self.assertEqual(_update_table.call_count, 2)
|
|
_update_table.assert_any_call(
|
|
'servers',
|
|
new_data=servers_api_result_str_set,
|
|
old_data=servers_api_result_str_set, use_snapshot=False)
|
|
_update_table.assert_any_call(
|
|
'flavors', new_data=set([]), old_data=set([]), use_snapshot=False)
|
|
|
|
@mock.patch.object(json_ingester.JsonIngester, '_webhook_update_table')
|
|
def test_json_ingester_webhook_handler(self, _webhook_update_table):
|
|
test_body = {"payload": {"id": 42, "other": "stuff"}}
|
|
self.test_driver.json_ingester_webhook_handler('alarms', test_body)
|
|
_webhook_update_table.assert_called_once_with(
|
|
'alarms', key=42, data=test_body['payload'])
|
|
(self.test_driver.exec_manager.
|
|
evaluate_and_execute_actions.assert_called_once())
|
|
|
|
@mock.patch.object(json_ingester.JsonIngester, '_webhook_update_table')
|
|
def test_json_ingester_webhook_handler_non_primitive_key(
|
|
self, _webhook_update_table):
|
|
test_key = {1: [2, 3], "2": "4"}
|
|
test_body = {"payload": {"id": test_key, "other": "stuff"}}
|
|
self.test_driver.json_ingester_webhook_handler('alarms', test_body)
|
|
_webhook_update_table.assert_called_once_with(
|
|
'alarms', key=test_key, data=test_body['payload'])
|
|
(self.test_driver.exec_manager.
|
|
evaluate_and_execute_actions.assert_called_once())
|
|
|
|
@mock.patch.object(json_ingester.JsonIngester, '_webhook_update_table')
|
|
def test_json_ingester_webhook_handler_missing_payload(
|
|
self, _webhook_update_table):
|
|
test_body = {"not_payload": {"id": 42, "other": "stuff"}}
|
|
self.assertRaises(
|
|
exception.BadRequest,
|
|
self.test_driver.json_ingester_webhook_handler,
|
|
'alarms', test_body)
|
|
|
|
@mock.patch.object(json_ingester.JsonIngester, '_webhook_update_table')
|
|
def test_json_ingester_webhook_handler_missing_id(
|
|
self, _webhook_update_table):
|
|
test_body = {"payload": {"not_id": 42, "other": "stuff"}}
|
|
self.assertRaises(
|
|
exception.BadRequest,
|
|
self.test_driver.json_ingester_webhook_handler,
|
|
'alarms', test_body)
|
|
|
|
def test_json_ingester_webhook_key_too_long(self):
|
|
test_body = {"payload": {"id": "X"*2713, "other": "stuff"}}
|
|
self.assertRaises(
|
|
exception.BadRequest,
|
|
self.test_driver.json_ingester_webhook_handler,
|
|
'alarms', test_body)
|
|
|
|
def test_json_ingester_webhook_nonexistent_table(self):
|
|
test_body = {"payload": {"id": 42, "other": "stuff"}}
|
|
self.assertRaises(
|
|
exception.NotFound,
|
|
self.test_driver.json_ingester_webhook_handler,
|
|
'no_such_table', test_body)
|
|
|
|
def test_json_ingester_webhook_non_webhook_table(self):
|
|
test_body = {"payload": {"id": 42, "other": "stuff"}}
|
|
self.assertRaises(
|
|
exception.NotFound,
|
|
self.test_driver.json_ingester_webhook_handler,
|
|
'servers', test_body)
|
|
|
|
|
|
class TestKeyMap(base.TestCase):
|
|
|
|
def setUp(self):
|
|
super(TestKeyMap, self).setUp()
|
|
self.key_map = json_ingester.KeyMap()
|
|
|
|
def test_init(self):
|
|
self.assertEqual(len(self.key_map), 0, 'key set not empty upon init')
|
|
|
|
def test_add_then_remove(self):
|
|
datum = str(uuid.uuid4())
|
|
key_on_add = self.key_map.add_and_get_key(datum)
|
|
self.assertEqual(len(self.key_map), 1)
|
|
key_on_remove = self.key_map.remove_and_get_key(datum)
|
|
self.assertEqual(len(self.key_map), 0)
|
|
self.assertEqual(key_on_add, key_on_remove)
|
|
|
|
def test_increment(self):
|
|
datum1 = str(uuid.uuid4())
|
|
datum2 = datum1 + 'diff'
|
|
|
|
key1 = self.key_map.add_and_get_key(datum1)
|
|
key2 = self.key_map.add_and_get_key(datum2)
|
|
self.assertEqual(len(self.key_map), 2)
|
|
self.assertEqual(key2, key1 + 1)
|
|
|
|
def test_reclaim(self):
|
|
datum1 = str(uuid.uuid4())
|
|
datum2 = datum1 + 'diff'
|
|
datum3 = datum1 + 'diffdiff'
|
|
|
|
key1 = self.key_map.add_and_get_key(datum1)
|
|
self.key_map.add_and_get_key(datum2)
|
|
self.key_map.remove_and_get_key(datum1)
|
|
key3 = self.key_map.add_and_get_key(datum3)
|
|
self.assertEqual(key1, key3)
|
|
|
|
def test_repeat_add(self):
|
|
datum = str(uuid.uuid4())
|
|
key1 = self.key_map.add_and_get_key(datum)
|
|
key2 = self.key_map.add_and_get_key(datum)
|
|
self.assertEqual(len(self.key_map), 1)
|
|
self.assertEqual(key1, key2)
|
|
|
|
def test_remove_nonexistent(self):
|
|
self.assertRaises(KeyError, self.key_map.remove_and_get_key, 'datum')
|