From 9b44e70bb88557eba4e433d46fbf9b8c455d1378 Mon Sep 17 00:00:00 2001 From: Mohit Tomar Date: Tue, 11 Oct 2022 18:15:28 +0530 Subject: [PATCH 1/3] Added Jenkinsfile Signed-off-by: Mohit Tomar --- Jenkinsfile | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..fbf230a --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,62 @@ +timestamps { + node("ubuntu18-agent") { + catchError { + checkout scm + dir_exists = sh ( + script: "test -d 'tests' && echo 'Y' || echo 'N' ", + returnStdout: true + ).trim() + + if (dir_exists == 'N'){ + currentBuild.result= 'FAILURE' + echo "No tests directory found! Exiting." + return + } + + try { + stage("Prerequisites"){ + // Change to corresponding CORE_BRANCH as required + // e.g. FOGL-xxxx, main etc. + sh ''' + CORE_BRANCH='develop' + ${HOME}/buildFledge ${CORE_BRANCH} ${WORKSPACE} + ''' + } + } catch (e) { + currentBuild.result = 'FAILURE' + echo "Failed to build Fledge; required to run the tests!" + return + } + + try { + stage("Run Tests"){ + echo "Executing tests..." + sh ''' + . ${WORKSPACE}/PLUGIN_PR_ENV/bin/activate + export FLEDGE_ROOT=$HOME/fledge && export PYTHONPATH=$HOME/fledge/python + cd tests && python3 -m pytest -vv --ignore=system --ignore=api --junit-xml=test_result.xml + ''' + echo "Done." + } + } catch (e) { + result = "TESTS FAILED" + currentBuild.result = 'FAILURE' + echo "Tests failed!" + } + + try { + stage("Publish Test Report"){ + junit "tests/test_result.xml" + } + } catch (e) { + result = "TEST REPORT GENERATION FAILED" + currentBuild.result = 'FAILURE' + echo "Failed to generate test reports!" + } + } + stage ("Cleanup"){ + // Add here if any cleanup is required + echo "Done." + } + } +} From 5c41e19c3d2d982d8242dbbb10642775f93d1809 Mon Sep 17 00:00:00 2001 From: Mohit Tomar Date: Fri, 14 Oct 2022 14:12:08 +0530 Subject: [PATCH 2/3] Updated Unit tests file and requirements.sh file Signed-off-by: Mohit Tomar --- requirements.sh | 2 +- tests/__init__.py | 0 tests/test_south_s7_python.py | 506 +--------------------------------- 3 files changed, 7 insertions(+), 501 deletions(-) create mode 100644 tests/__init__.py diff --git a/requirements.sh b/requirements.sh index f4d3726..a933e91 100755 --- a/requirements.sh +++ b/requirements.sh @@ -46,7 +46,7 @@ elif apt --version 2>/dev/null; then sudo apt install -y wget sudo apt install -y p7zip wget --content-disposition -c https://sourceforge.net/projects/snap7/files/1.4.2/snap7-full-1.4.2.7z/download - p7zip -d snap7-full-1.4.2.7z + echo "A" | p7zip -d snap7-full-1.4.2.7z cd snap7-full-1.4.2/build/unix make -f "$(uname -m)_linux.mk" install else diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_south_s7_python.py b/tests/test_south_s7_python.py index a5fb53e..0b12d9c 100644 --- a/tests/test_south_s7_python.py +++ b/tests/test_south_s7_python.py @@ -7,514 +7,20 @@ __version__ = "${VERSION}" -import sys import pytest -import json -import logging -from unittest.mock import patch, MagicMock, ANY -from fledge.plugins.south.s7_python import s7_python as s7 +from python.fledge.plugins.south.s7_python import s7_python as s7 -_STREAM_ID = 1 - - -async def mock_async_call(p1=ANY): - """Mocks a generic async function - - Parameters - ---------- - p1 : type - Description of parameter `p1`. - - Returns - ------- - def - Description of returned object. - - """ - return p1 - - -@pytest.fixture -def fixture_s7(event_loop): - """Short summary. - - Parameters - ---------- - event_loop : type - Description of parameter `event_loop`. - - Returns - ------- - type - Description of returned object. - - """ - - _omf = MagicMock() - - s7._logger = MagicMock(spec=logging) - s7._config_omf_types = {"type-id": {"value": "0001"}} - - return s7 - - -@pytest.fixture -def fixture_s7_north(event_loop): - """Short summary. - - Parameters - ---------- - event_loop : type - Description of parameter `event_loop`. - - Returns - ------- - type - Description of returned object. - - """ - - sending_process_instance = MagicMock() - - _logger = MagicMock(spec=logging) - - s7_north = s7.S7NorthPlugin() - - return s7_north - - -@pytest.allure.feature('unit') -@pytest.allure.story('plugin', 'north', 's7') -@pytest.mark.usefixtures('fixture_s7_north') class TestS7: - """Short summary.""" def test_plugin_info(self): - """Short summary. - - Returns - ------- - type - Description of returned object. - - """ - + plugin_info = s7.plugin_info() - assert plugin_info == { - 'name': 's7_north_python', + 'name': 's7_south_python', 'version': '2.0.0', - 'type': 'north', + 'mode': 'poll', + 'type': 'south', 'interface': '1.0', 'config': s7._DEFAULT_CONFIG - } - - def test_plugin_init_good(self): - """Short summary. - - Returns - ------- - type - Description of returned object. - - """ - s7._logger = MagicMock() -# -# # Used to check the conversions -# data = { -# "stream_id": {"value": 1}, -# -# "_CONFIG_CATEGORY_NAME": module_sp.SendingProcess._CONFIG_CATEGORY_NAME, -# "URL": {"value": "test_URL"}, -# "producerToken": {"value": "test_producerToken"}, -# "OMFMaxRetry": {"value": "100"}, -# "OMFRetrySleepTime": {"value": "100"}, -# "OMFHttpTimeout": {"value": "100"}, -# "StaticData": { -# "value": json.dumps( -# { -# "Location": "Palo Alto", -# "Company": "Dianomic" -# } -# ) -# }, -# "destination_type": {"value": "3"}, -# 'sending_process_instance': MagicMock(spec=SendingProcess), -# "formatNumber": {"value": "float64"}, -# "formatInteger": {"value": "int64"}, -# "notBlockingErrors": {"value": "{'id': 400, 'message': 'none'}"}, -# "compression": {"value": "true"}, -# "namespace": {"value": "ocs_namespace_0001"}, -# "tenant_id": {"value": "ocs_tenant_id"}, -# "client_id": {"value": "ocs_client_id"}, -# "client_secret": {"value": "ocs_client_secret"}, -# -# } -# -# config_default_omf_types = s7._CONFIG_DEFAULT_OMF_TYPES -# config_default_omf_types["type-id"]["value"] = "0001" -# data["debug_level"] = None -# data["log_performance"] = None -# data["destination_id"] = 1 -# data["stream_id"] = 1 -# -# with patch.object(data['sending_process_instance'], '_fetch_configuration', -# return_value=config_default_omf_types): -# config = ocs.plugin_init(data) -# -# assert config['_CONFIG_CATEGORY_NAME'] == module_sp.SendingProcess._CONFIG_CATEGORY_NAME -# assert config['URL'] == "test_URL" -# assert config['producerToken'] == "test_producerToken" -# assert config['OMFMaxRetry'] == 100 -# assert config['OMFRetrySleepTime'] == 100 -# assert config['OMFHttpTimeout'] == 100 -# -# # Check conversion from String to Dict -# assert isinstance(config['StaticData'], dict) -# -# @pytest.mark.parametrize("data", [ -# # Bad case 1 - StaticData is a python dict instead of a string containing a dict -# { -# "stream_id": {"value": 1}, -# "_CONFIG_CATEGORY_NAME": module_sp.SendingProcess._CONFIG_CATEGORY_NAME, -# "URL": {"value": "test_URL"}, -# "producerToken": {"value": "test_producerToken"}, -# "OMFMaxRetry": {"value": "100"}, -# "OMFRetrySleepTime": {"value": "100"}, -# "OMFHttpTimeout": {"value": "100"}, -# "StaticData": { -# "value": -# { -# "Location": "Palo Alto", -# "Company": "Dianomic" -# } -# }, -# 'sending_process_instance': MagicMock(spec=SendingProcess), -# "formatNumber": {"value": "float64"}, -# "formatInteger": {"value": "int64"}, -# }, -# # Bad case 2 - OMFMaxRetry, bad value expected an int it is a string -# { -# "stream_id": {"value": 1}, -# "_CONFIG_CATEGORY_NAME": module_sp.SendingProcess._CONFIG_CATEGORY_NAME, -# "URL": {"value": "test_URL"}, -# "producerToken": {"value": "test_producerToken"}, -# "OMFMaxRetry": {"value": "xxx"}, -# "OMFRetrySleepTime": {"value": "100"}, -# "OMFHttpTimeout": {"value": "100"}, -# "StaticData": { -# "value": json.dumps( -# { -# "Location": "Palo Alto", -# "Company": "Dianomic" -# } -# ) -# }, -# 'sending_process_instance': MagicMock(spec=SendingProcess), -# "formatNumber": {"value": "float64"}, -# "formatInteger": {"value": "int64"}, -# }, -# # Bad case 3- formatNumber not defined -# { -# "stream_id": {"value": 1}, -# -# "_CONFIG_CATEGORY_NAME": module_sp.SendingProcess._CONFIG_CATEGORY_NAME, -# "URL": {"value": "test_URL"}, -# "producerToken": {"value": "test_producerToken"}, -# "OMFMaxRetry": {"value": "100"}, -# "OMFRetrySleepTime": {"value": "100"}, -# "OMFHttpTimeout": {"value": "100"}, -# "StaticData": { -# "value": json.dumps( -# { -# "Location": "Palo Alto", -# "Company": "Dianomic" -# } -# ) -# }, -# -# 'sending_process_instance': MagicMock(spec=SendingProcess), -# -# "formatInteger": {"value": "int64"} -# }, -# -# # Bad case 4 - formatInteger not defined -# { -# "stream_id": {"value": 1}, -# -# "_CONFIG_CATEGORY_NAME": module_sp.SendingProcess._CONFIG_CATEGORY_NAME, -# "URL": {"value": "test_URL"}, -# "producerToken": {"value": "test_producerToken"}, -# "OMFMaxRetry": {"value": "100"}, -# "OMFRetrySleepTime": {"value": "100"}, -# "OMFHttpTimeout": {"value": "100"}, -# "StaticData": { -# "value": json.dumps( -# { -# "Location": "Palo Alto", -# "Company": "Dianomic" -# } -# ) -# }, -# -# 'sending_process_instance': MagicMock(spec=SendingProcess), -# -# "formatNumber": {"value": "float64"} -# } -# ]) -# def test_plugin_init_bad(self, data): -# """Tests plugin_init using an invalid set of values""" -# -# ocs._logger = MagicMock() -# -# with pytest.raises(Exception): -# ocs.plugin_init(data) -# -# @pytest.mark.parametrize( -# "ret_transform_in_memory_data, " -# "p_raw_data, ", -# [ -# ( -# # ret_transform_in_memory_data -# # is_data_available - new_position - num_sent -# [True, 20, 10], -# # raw_data -# [ -# { -# "id": 10, -# "asset_code": "test_asset_code", -# "reading": {"humidity": 100, "temperature": 1001}, -# "user_ts": '2018-04-20 09:38:50.163164+00' -# } -# ] -# ) -# ] -# ) -# @pytest.mark.asyncio -# async def test_plugin_send_success(self, -# ret_transform_in_memory_data, -# p_raw_data, -# fixture_ocs -# ): -# -# data = MagicMock() -# -# with patch.object(fixture_ocs.OCSNorthPlugin, -# 'transform_in_memory_data', -# return_value=ret_transform_in_memory_data) as patched_transform_in_memory_data: -# with patch.object(fixture_ocs.OCSNorthPlugin, -# 'create_omf_objects', -# return_value=mock_async_call()) as patched_create_omf_objects: -# with patch.object(fixture_ocs.OCSNorthPlugin, -# 'send_in_memory_data_to_picromf', -# return_value=mock_async_call()) as patched_send_in_memory_data_to_picromf: -# await fixture_ocs.plugin_send(data, p_raw_data, _STREAM_ID) -# -# assert patched_transform_in_memory_data.called -# assert patched_create_omf_objects.called -# assert patched_send_in_memory_data_to_picromf.called -# -# @pytest.mark.parametrize( -# "ret_transform_in_memory_data, " -# "p_raw_data, ", -# [ -# ( -# # ret_transform_in_memory_data -# # is_data_available - new_position - num_sent -# [True, 20, 10], -# # raw_data -# { -# "id": 10, -# "asset_code": "test_asset_code", -# "reading": {"humidity": 100, "temperature": 1001}, -# "user_ts": '2018-04-20 09:38:50.163164+00' -# } -# ) -# ] -# ) -# @pytest.mark.asyncio -# async def test_plugin_send_error( -# self, -# fixture_ocs, -# ret_transform_in_memory_data, -# p_raw_data -# ): -# """ Unit test for - plugin_send - error handling case -# it tests especially if the ocs objects are created again in case of a communication error -# -# NOTE : the stderr is redirected to avoid the print of an error message that could be ignored. -# """ -# -# data = MagicMock() -# -# with patch.object(fixture_ocs.OCSNorthPlugin, -# 'transform_in_memory_data', -# return_value=ret_transform_in_memory_data -# ) as patched_transform_in_memory_data: -# -# with patch.object(fixture_ocs.OCSNorthPlugin, -# 'create_omf_objects', -# return_value=mock_async_call() -# ) as patched_create_omf_objects: -# -# with patch.object(fixture_ocs.OCSNorthPlugin, -# 'send_in_memory_data_to_picromf', -# side_effect=KeyError('mocked object generated an exception') -# ) as patched_send_in_memory_data_to_picromf: -# -# with patch.object(fixture_ocs.OCSNorthPlugin, -# 'deleted_omf_types_already_created', -# return_value=mock_async_call() -# ) as patched_deleted_omf_types_already_created: -# -# with pytest.raises(Exception): -# await fixture_ocs.plugin_send(data, p_raw_data, -# _STREAM_ID) -# assert patched_transform_in_memory_data.called -# assert patched_create_omf_objects.called -# assert patched_send_in_memory_data_to_picromf.called -# assert patched_deleted_omf_types_already_created.called -# -# def test_plugin_shutdown(self): -# -# ocs._logger = MagicMock() -# data = [] -# ocs.plugin_shutdown([data]) -# -# def test_plugin_reconfigure(self): -# -# ocs._logger = MagicMock() -# ocs.plugin_reconfigure() -# -# -# class TestOCSNorthPlugin: -# """Unit tests related to OCSNorthPlugin, methods used internally to the plugin""" -# -# @pytest.mark.parametrize( -# "p_test_data, " -# "p_type_id, " -# "p_static_data, " -# "expected_typename," -# "expected_omf_type", -# [ -# # Case 1 - pressure / Number -# ( -# # Origin - Sensor data -# {"asset_code": "pressure", "asset_data": {"pressure": 921.6}}, -# # type_id -# "0001", -# # Static Data -# { -# "Location": "Palo Alto", -# "Company": "Dianomic" -# }, -# # Expected -# 'pressure_typename', -# { -# 'pressure_typename': -# [ -# { -# 'classification': 'static', -# 'id': '0001_pressure_typename_sensor', -# 'properties': { -# 'Company': {'type': 'string'}, -# 'Name': {'isindex': True, 'type': 'string'}, -# 'Location': {'type': 'string'} -# }, -# 'type': 'object' -# }, -# { -# 'classification': 'dynamic', -# 'id': '0001_pressure_typename_measurement', -# 'properties': { -# 'Time': { -# 'isindex': True, -# 'format': 'date-time', -# 'type': 'string' -# }, -# 'pressure': { -# 'type': 'number', -# 'format': 'float64' -# } -# }, -# 'type': 'object' -# } -# ] -# } -# ), -# # Case 2 - luxometer / Integer -# ( -# # Origin - Sensor data -# {"asset_code": "luxometer", "asset_data": {"lux": 20}}, -# # type_id -# "0002", -# # Static Data -# { -# "Location": "Palo Alto", -# "Company": "Dianomic" -# }, -# # Expected -# 'luxometer_typename', -# { -# 'luxometer_typename': -# [ -# { -# 'classification': 'static', -# 'id': '0002_luxometer_typename_sensor', -# 'properties': { -# 'Company': {'type': 'string'}, -# 'Name': {'isindex': True, 'type': 'string'}, -# 'Location': {'type': 'string'} -# }, -# 'type': 'object' -# }, -# { -# 'classification': 'dynamic', -# 'id': '0002_luxometer_typename_measurement', -# 'properties': { -# 'Time': {'isindex': True, 'format': 'date-time', 'type': 'string'}, -# 'lux': { -# 'type': 'number', -# 'format': 'float64' -# } -# }, -# 'type': 'object' -# } -# ] -# } -# ) -# ] -# ) -# @pytest.mark.asyncio -# async def test_create_omf_type_automatic( -# self, -# p_test_data, -# p_type_id, -# p_static_data, -# expected_typename, -# expected_omf_type, -# fixture_ocs_north): -# """ Unit test for - _create_omf_type_automatic - successful case -# Tests the generation of the OMF messages starting from Asset name and data -# using Automatic OMF Type Mapping""" -# -# fixture_ocs_north._config_omf_types = {"type-id": {"value": p_type_id}} -# -# fixture_ocs_north._config = {} -# fixture_ocs_north._config["StaticData"] = p_static_data -# fixture_ocs_north._config["formatNumber"] = "float64" -# fixture_ocs_north._config["formatInteger"] = "int64" -# -# with patch.object(fixture_ocs_north, -# 'send_in_memory_data_to_picromf', -# return_value=mock_async_call() -# ) as patched_send_in_memory_data_to_picromf: -# -# typename, omf_type = await fixture_ocs_north._create_omf_type_automatic(p_test_data) -# -# assert typename == expected_typename -# assert omf_type == expected_omf_type -# -# assert patched_send_in_memory_data_to_picromf.called -# patched_send_in_memory_data_to_picromf.assert_any_call("Type", expected_omf_type[expected_typename]) + } \ No newline at end of file From 4931d05ce2555628183db771766f55c24255f015 Mon Sep 17 00:00:00 2001 From: dianomicbot Date: Thu, 20 Oct 2022 11:21:34 +0000 Subject: [PATCH 3/3] VERSION changed Signed-off-by: dianomicbot --- VERSION.south.s7_python | 2 +- python/fledge/plugins/south/s7_python/s7_python.py | 2 +- tests/test_south_s7_python.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION.south.s7_python b/VERSION.south.s7_python index 2f6d7c9..17d21dd 100644 --- a/VERSION.south.s7_python +++ b/VERSION.south.s7_python @@ -1,2 +1,2 @@ -fledge_south_s7_python_version=2.0.0 +fledge_south_s7_python_version=2.0.1 fledge_version>=2.0 diff --git a/python/fledge/plugins/south/s7_python/s7_python.py b/python/fledge/plugins/south/s7_python/s7_python.py index 46b33b6..fd46677 100644 --- a/python/fledge/plugins/south/s7_python/s7_python.py +++ b/python/fledge/plugins/south/s7_python/s7_python.py @@ -216,7 +216,7 @@ def plugin_info(): return { 'name': 's7_south_python', - 'version': '2.0.0', + 'version': '2.0.1', 'mode': 'poll', 'type': 'south', 'interface': '1.0', diff --git a/tests/test_south_s7_python.py b/tests/test_south_s7_python.py index 0b12d9c..b4cec60 100644 --- a/tests/test_south_s7_python.py +++ b/tests/test_south_s7_python.py @@ -18,7 +18,7 @@ def test_plugin_info(self): plugin_info = s7.plugin_info() assert plugin_info == { 'name': 's7_south_python', - 'version': '2.0.0', + 'version': '2.0.1', 'mode': 'poll', 'type': 'south', 'interface': '1.0',