From 8cb45d9b23e33d04791a11bc7359869a85a17386 Mon Sep 17 00:00:00 2001 From: Marco Zeisler Date: Thu, 17 Jun 2021 19:00:26 +0200 Subject: [PATCH 1/2] make message unpacking testable; added message unpacking tests; --- .../event_store/service/event_logger.py | 18 +++-- .../event_store/service/test_event_logger.py | 68 +++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 components/event_store/service/test_event_logger.py diff --git a/components/event_store/service/event_logger.py b/components/event_store/service/event_logger.py index 36ae325..757d0c2 100644 --- a/components/event_store/service/event_logger.py +++ b/components/event_store/service/event_logger.py @@ -67,6 +67,14 @@ class EventLogger: :param bytes msg: pickled msg binary to log """ + key, to_log = self._unpack_message_to_log(msg) + + if self.log_to_redis: + self.redis.lpush(key, "{}".format(to_log)) + if self.verbose: + print(to_log) + + def _unpack_message_to_log(self, msg: bytes): try: msg = pickle.loads(msg) except Exception as e: @@ -90,9 +98,9 @@ class EventLogger: try: to_log = json.dumps(msg.to_dict()) except AttributeError: - to_log = str(msg) + try: + to_log = json.dumps(msg) + except (json.decoder.JSONDecodeError, TypeError): + to_log = str(msg) - if self.log_to_redis: - self.redis.lpush(key, "{}".format(to_log)) - if self.verbose: - print(to_log) + return key, to_log diff --git a/components/event_store/service/test_event_logger.py b/components/event_store/service/test_event_logger.py new file mode 100644 index 0000000..ac13786 --- /dev/null +++ b/components/event_store/service/test_event_logger.py @@ -0,0 +1,68 @@ +import datetime +import json +import pickle +import unittest + +import geopy +from dse_shared_libs.daf import DAF +from dse_shared_libs.target_velocity import TargetVelocity +from dse_shared_libs.traffic_light_color import TrafficLightColor +from dse_shared_libs.traffic_light_state import TrafficLightState +from redis import StrictRedis + +from event_logger import EventLogger + + +class TestEventLogger(unittest.TestCase): + def setUp(self) -> None: + self.el = EventLogger(StrictRedis(), False, False) + self.timestamp = datetime.datetime.now() + + def test_unpack_daf(self): + daf = DAF(vehicle_identification_number='my_vin', + gps_location=geopy.Point(0, 0, 0), + velocity=130.0, + near_crash_event=False, + timestamp=self.timestamp, + ) + + key, message = self.el._unpack_message_to_log(pickle.dumps(daf)) + + self.assertEqual(key, 'DAF:my_vin') + self.assertEqual(message, json.dumps(daf.to_dict())) + + def test_unpack_target_velocity(self): + tv = TargetVelocity(vin='my_other_vin', + target_velocity=120.0, + timestamp=self.timestamp) + + key, message = self.el._unpack_message_to_log(pickle.dumps(tv)) + + self.assertEqual(key, 'TV:my_other_vin') + self.assertEqual(message, json.dumps(tv.to_dict())) + + def test_unpack_traffic_light_state(self): + tls = TrafficLightState(tlid='my_traffic_light', + color=TrafficLightColor.GREEN, + last_switch=self.timestamp) + + key, message = self.el._unpack_message_to_log(pickle.dumps(tls)) + + self.assertEqual(key, 'TL:my_traffic_light') + self.assertEqual(message, json.dumps(tls.to_dict())) + + def test_unpack_unknown_dict(self): + unknown = dict(foo='foo', bar='bar') + + key, message = self.el._unpack_message_to_log(pickle.dumps(unknown)) + + self.assertEqual(key, 'UNKNOWN') + self.assertEqual(message, json.dumps(unknown)) + + def test_unpack_unknown_object(self): + obj = datetime.datetime.now() + + key, message = self.el._unpack_message_to_log(pickle.dumps(obj)) + + self.assertEqual(key, 'UNKNOWN') + self.assertEqual(message, str(obj)) From 1f2bddf2f56668e75c1cbd046a2994738da7c938 Mon Sep 17 00:00:00 2001 From: David Eder Date: Thu, 17 Jun 2021 19:05:26 +0200 Subject: [PATCH 2/2] Add API documentation for other resources on xway --- .../src/app/services/rest.service.ts | 2 +- components/x_way/x_way_server.py | 79 +++++++++++-------- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/components/control_center/src/app/services/rest.service.ts b/components/control_center/src/app/services/rest.service.ts index af42907..54033d2 100644 --- a/components/control_center/src/app/services/rest.service.ts +++ b/components/control_center/src/app/services/rest.service.ts @@ -18,7 +18,7 @@ export class RestService { } getCarEvents(vin) { - return this.http.get(this.currentLocation + 'car_events/?vin=' + vin, {observe: 'response'}); + return this.http.get(this.currentLocation + 'car_events?vin=' + vin, {observe: 'response'}); } getTrafficLights() { diff --git a/components/x_way/x_way_server.py b/components/x_way/x_way_server.py index 794754f..47e1fdb 100644 --- a/components/x_way/x_way_server.py +++ b/components/x_way/x_way_server.py @@ -9,23 +9,22 @@ import json; app = Flask(__name__) CORS(app) -api_bp = flask.Blueprint("api", __name__, url_prefix="/api/v1/resources") +api_bp = flask.Blueprint("api", __name__, url_prefix="/api/v1") API = flask_restx.Api(api_bp) app.register_blueprint(api_bp) - -NAMESPACE = API.namespace("car_events") - +NAMESPACE = API.namespace("resources") ENTITY_IDENT_URL = 'http://entityident:5002/api/v1/resources/' EVENT_STORE_URL = 'http://eventstore:5001/api/keys/' -@NAMESPACE.route('/') +@NAMESPACE.route('/car_events', doc={'description': 'Get most current car event for specific car'}) class CarsEvents(flask_restx.Resource): @NAMESPACE.doc(params={'vin': {'description': 'Vehicle Identifier Number of car', - 'type': 'String', 'default': '5GZCZ43D13S812715'}}) + 'type': 'String', 'default': '5GZCZ43D13S812715'}}) + @NAMESPACE.response(200, 'Success') def get(self): vin = request.args.get('vin') @@ -40,45 +39,57 @@ class CarsEvents(flask_restx.Resource): return jsonify(cars) -@app.route('/api/v1/resources/traffic_light_events', methods=['GET']) -def get_traffic_light_events(): - id = request.args.get('id') +@NAMESPACE.route('/traffic_light_events', doc={'description': 'Get most current traffic light event' + 'for specific traffic light'}) +class TrafficLightEvents(flask_restx.Resource): + @NAMESPACE.doc(params={'id': {'description': 'Unique ID of traffic light', + 'type': 'int', 'default': '1'}}) + @NAMESPACE.response(200, 'Success') + def get(self): + id = request.args.get('id') - try: - response = requests.get(EVENT_STORE_URL + 'TL:' + id + '/0/') - traffic_lights = json.loads(response.text) + try: + response = requests.get(EVENT_STORE_URL + 'TL:' + id + '/0/') + traffic_lights = json.loads(response.text) - except requests.exceptions.ConnectionError as e: - print("Is the EVENT_STORE_URL running and reachable?") - raise e + except requests.exceptions.ConnectionError as e: + print("Is the EVENT_STORE_URL running and reachable?") + raise e - return json_util.dumps(traffic_lights) + return jsonify(traffic_lights) -@app.route('/api/v1/resources/cars', methods=['GET']) -def get_cars(): - try: - response = requests.get(ENTITY_IDENT_URL + 'cars') - cars = response.json()['cursor'] +@NAMESPACE.route('/cars', doc={'description': 'Get entity details for all cars'}) +class Car(flask_restx.Resource): + @NAMESPACE.response(200, 'Success') + def get(self): - except requests.exceptions.ConnectionError as e: - print("Is the entity_ident_server running and reachable?") - raise e + try: + response = requests.get(ENTITY_IDENT_URL + 'cars') + cars = response.json()['cursor'] - return json_util.dumps(cars) + except requests.exceptions.ConnectionError as e: + print("Is the entity_ident_server running and reachable?") + raise e + + return jsonify(cars) -@app.route('/api/v1/resources/traffic_lights', methods=['GET']) -def get_traffic_lights(): - try: - response = requests.get(ENTITY_IDENT_URL + 'traffic_lights') - traffic_lights = response.json()['cursor'] +@NAMESPACE.route('/traffic_lights', doc={'description': 'Get entity details for all traffic lights'}) +class TrafficLights(flask_restx.Resource): - except requests.exceptions.ConnectionError as e: - print("Is the entity_ident_server running and reachable?") - raise e + @NAMESPACE.response(200, 'Success') + def get(self): - return json_util.dumps(traffic_lights) + try: + response = requests.get(ENTITY_IDENT_URL + 'traffic_lights') + traffic_lights = response.json()['cursor'] + + except requests.exceptions.ConnectionError as e: + print("Is the entity_ident_server running and reachable?") + raise e + + return jsonify(traffic_lights) if __name__ == '__main__':