Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 1 | from unittest import main |
| 2 | from common.utils.consulhelpers import get_endpoint_from_consul |
Richard Jankowski | 8728934 | 2018-04-19 13:59:10 -0400 | [diff] [blame] | 3 | from tests.itests.test_utils import get_pod_ip, \ |
Stephane Barbarie | cc6b2e6 | 2017-03-02 14:35:55 -0500 | [diff] [blame] | 4 | run_long_running_command_with_timeout |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 5 | from tests.itests.voltha.rest_base import RestBase |
| 6 | from google.protobuf.json_format import MessageToDict |
| 7 | from voltha.protos.device_pb2 import Device |
| 8 | import simplejson, jsonschema |
| 9 | import re |
Richard Jankowski | 8728934 | 2018-04-19 13:59:10 -0400 | [diff] [blame] | 10 | from tests.itests.orch_environment import get_orch_environment |
| 11 | from testconfig import config |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 12 | |
| 13 | # ~~~~~~~ Common variables ~~~~~~~ |
| 14 | |
| 15 | LOCAL_CONSUL = "localhost:8500" |
Richard Jankowski | 8728934 | 2018-04-19 13:59:10 -0400 | [diff] [blame] | 16 | ENV_DOCKER_COMPOSE = 'docker-compose' |
| 17 | ENV_K8S_SINGLE_NODE = 'k8s-single-node' |
| 18 | |
| 19 | orch_env = ENV_DOCKER_COMPOSE |
| 20 | if 'test_parameters' in config and 'orch_env' in config['test_parameters']: |
| 21 | orch_env = config['test_parameters']['orch_env'] |
| 22 | print 'orchestration-environment: %s' % orch_env |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 23 | |
| 24 | COMMANDS = dict( |
| 25 | kafka_client_run="kafkacat -b {} -L", |
Stephane Barbarie | e37300e | 2017-06-08 11:22:16 -0400 | [diff] [blame] | 26 | kafka_client_send_msg='echo hello | kafkacat -b {} -P -t voltha.alarms -c 1', |
| 27 | kafka_client_alarm_check="kafkacat -o end -b {} -C -t voltha.alarms -c 2", |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 28 | ) |
| 29 | |
| 30 | ALARM_SCHEMA = { |
| 31 | "type": "object", |
| 32 | "properties": { |
| 33 | "id": {"type": "string"}, |
| 34 | "type": {"type": "string"}, |
| 35 | "category": {"type": "string"}, |
| 36 | "state": {"type": "string"}, |
| 37 | "severity": {"type": "string"}, |
| 38 | "resource_id": {"type": "string"}, |
| 39 | "raised_ts": {"type": "number"}, |
| 40 | "reported_ts": {"type": "number"}, |
| 41 | "changed_ts": {"type": "number"}, |
| 42 | "description": {"type": "string"}, |
| 43 | "context": { |
| 44 | "type": "object", |
| 45 | "additionalProperties": {"type": "string"} |
| 46 | } |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | |
Stephane Barbarie | cc6b2e6 | 2017-03-02 14:35:55 -0500 | [diff] [blame] | 51 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 52 | |
| 53 | |
| 54 | class VolthaAlarmEventTests(RestBase): |
Richard Jankowski | 8728934 | 2018-04-19 13:59:10 -0400 | [diff] [blame] | 55 | # Get endpoint info |
| 56 | if orch_env == ENV_K8S_SINGLE_NODE: |
| 57 | rest_endpoint = get_pod_ip('voltha') + ':8443' |
| 58 | kafka_endpoint = get_pod_ip('kafka') |
| 59 | else: |
| 60 | rest_endpoint = get_endpoint_from_consul(LOCAL_CONSUL, 'voltha-envoy-8443') |
| 61 | kafka_endpoint = get_endpoint_from_consul(LOCAL_CONSUL, 'kafka') |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 62 | |
| 63 | # Construct the base_url |
ubuntu | c5c83d7 | 2017-07-01 17:57:19 -0700 | [diff] [blame] | 64 | base_url = 'https://' + rest_endpoint |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 65 | |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 66 | # ~~~~~~~~~~~~ Tests ~~~~~~~~~~~~ |
| 67 | |
Stephane Barbarie | e37300e | 2017-06-08 11:22:16 -0400 | [diff] [blame] | 68 | def test_1_alarm_topic_exists(self): |
| 69 | # Produce a message to ensure that the topic exists |
| 70 | cmd = COMMANDS['kafka_client_send_msg'].format(self.kafka_endpoint) |
| 71 | run_long_running_command_with_timeout(cmd, 5) |
| 72 | |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 73 | # We want to make sure that the topic is available on the system |
| 74 | expected_pattern = ['voltha.alarms'] |
| 75 | |
| 76 | # Start the kafka client to retrieve details on topics |
| 77 | cmd = COMMANDS['kafka_client_run'].format(self.kafka_endpoint) |
| 78 | kafka_client_output = run_long_running_command_with_timeout(cmd, 20) |
| 79 | |
| 80 | # Loop through the kafka client output to find the topic |
| 81 | found = False |
| 82 | for out in kafka_client_output: |
| 83 | if all(ep in out for ep in expected_pattern): |
| 84 | found = True |
| 85 | break |
| 86 | |
Stephane Barbarie | cc6b2e6 | 2017-03-02 14:35:55 -0500 | [diff] [blame] | 87 | self.assertTrue(found, |
| 88 | 'Failed to find topic {}'.format(expected_pattern)) |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 89 | |
Stephane Barbarie | e37300e | 2017-06-08 11:22:16 -0400 | [diff] [blame] | 90 | def test_2_alarm_generated_by_adapter(self): |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 91 | # Verify that REST calls can be made |
| 92 | self.verify_rest() |
| 93 | |
| 94 | # Create a new device |
| 95 | device = self.add_device() |
| 96 | |
| 97 | # Activate the new device |
| 98 | self.activate_device(device['id']) |
| 99 | |
| 100 | # The simulated olt device should start generating alarms periodically |
| 101 | alarm = self.get_alarm_event(device['id']) |
| 102 | |
| 103 | # Make sure that the schema is valid |
| 104 | self.validate_alarm_event_schema(alarm) |
| 105 | |
| 106 | # Validate the constructed alarm id |
| 107 | self.verify_alarm_event_id(device['id'], alarm['id']) |
| 108 | |
| 109 | # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 110 | |
| 111 | # Make sure the Voltha REST interface is available |
| 112 | def verify_rest(self): |
| 113 | self.get('/api/v1') |
| 114 | |
| 115 | # Create a new simulated device |
| 116 | def add_device(self): |
| 117 | device = Device( |
| 118 | type='simulated_olt', |
Richard Jankowski | 8728934 | 2018-04-19 13:59:10 -0400 | [diff] [blame] | 119 | mac_address='00:00:00:00:00:01' |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 120 | ) |
Stephane Barbarie | cd51f99 | 2017-09-07 16:37:02 -0400 | [diff] [blame] | 121 | device = self.post('/api/v1/devices', MessageToDict(device), |
| 122 | expected_http_code=200) |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 123 | return device |
| 124 | |
Stephane Barbarie | cc6b2e6 | 2017-03-02 14:35:55 -0500 | [diff] [blame] | 125 | # Active the simulated device. |
| 126 | # This will trigger the simulation of random alarms |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 127 | def activate_device(self, device_id): |
Stephane Barbarie | cd51f99 | 2017-09-07 16:37:02 -0400 | [diff] [blame] | 128 | path = '/api/v1/devices/{}'.format(device_id) |
| 129 | self.post(path + '/enable', expected_http_code=200) |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 130 | device = self.get(path) |
| 131 | self.assertEqual(device['admin_state'], 'ENABLED') |
| 132 | |
| 133 | # Retrieve a sample alarm for a specific device |
| 134 | def get_alarm_event(self, device_id): |
| 135 | cmd = COMMANDS['kafka_client_alarm_check'].format(self.kafka_endpoint) |
Stephane Barbarie | e37300e | 2017-06-08 11:22:16 -0400 | [diff] [blame] | 136 | kafka_client_output = run_long_running_command_with_timeout(cmd, 30) |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 137 | |
| 138 | # Verify the kafka client output |
| 139 | found = False |
Stephane Barbarie | e37300e | 2017-06-08 11:22:16 -0400 | [diff] [blame] | 140 | alarm_data = None |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 141 | |
| 142 | for out in kafka_client_output: |
Stephane Barbarie | e37300e | 2017-06-08 11:22:16 -0400 | [diff] [blame] | 143 | # Catch any error that might occur while reading the kafka messages |
| 144 | try: |
| 145 | alarm_data = simplejson.loads(out) |
| 146 | print alarm_data |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 147 | |
Stephane Barbarie | e37300e | 2017-06-08 11:22:16 -0400 | [diff] [blame] | 148 | if not alarm_data or 'resource_id' not in alarm_data: |
| 149 | continue |
| 150 | elif alarm_data['resource_id'] == device_id: |
| 151 | found = True |
| 152 | break |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 153 | |
Stephane Barbarie | e37300e | 2017-06-08 11:22:16 -0400 | [diff] [blame] | 154 | except Exception as e: |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 155 | continue |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 156 | |
Stephane Barbarie | cc6b2e6 | 2017-03-02 14:35:55 -0500 | [diff] [blame] | 157 | self.assertTrue( |
| 158 | found, |
| 159 | 'Failed to find kafka alarm with device id:{}'.format(device_id)) |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 160 | |
Stephane Barbarie | e37300e | 2017-06-08 11:22:16 -0400 | [diff] [blame] | 161 | return alarm_data |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 162 | |
| 163 | # Verify that the alarm follows the proper schema structure |
| 164 | def validate_alarm_event_schema(self, alarm): |
| 165 | try: |
| 166 | jsonschema.validate(alarm, ALARM_SCHEMA) |
| 167 | except Exception as e: |
Stephane Barbarie | cc6b2e6 | 2017-03-02 14:35:55 -0500 | [diff] [blame] | 168 | self.assertTrue( |
| 169 | False, 'Validation failed for alarm : {}'.format(e.message)) |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 170 | |
| 171 | # Verify that alarm identifier based on the format generated by default. |
| 172 | def verify_alarm_event_id(self, device_id, alarm_id): |
| 173 | prefix = re.findall(r"(voltha)\.(\w+)\.(\w+)", alarm_id) |
| 174 | |
Stephane Barbarie | cc6b2e6 | 2017-03-02 14:35:55 -0500 | [diff] [blame] | 175 | self.assertEqual( |
| 176 | len(prefix), 1, |
| 177 | 'Failed to parse the alarm id: {}'.format(alarm_id)) |
| 178 | self.assertEqual( |
| 179 | len(prefix[0]), 3, |
| 180 | 'Expected id format: voltha.<adapter name>.<device id>') |
| 181 | self.assertEqual( |
| 182 | prefix[0][0], 'voltha', |
| 183 | 'Expected id format: voltha.<adapter name>.<device id>') |
| 184 | self.assertEqual( |
| 185 | prefix[0][1], 'simulated_olt', |
| 186 | 'Expected id format: voltha.<adapter name>.<device id>') |
| 187 | self.assertEqual( |
| 188 | prefix[0][2], device_id, |
| 189 | 'Expected id format: voltha.<adapter name>.<device id>') |
Stephane Barbarie | 52198b9 | 2017-03-02 13:44:46 -0500 | [diff] [blame] | 190 | |
| 191 | |
| 192 | if __name__ == '__main__': |
| 193 | main() |