Skip to content

Commit

Permalink
Add pytest
Browse files Browse the repository at this point in the history
  • Loading branch information
jarovo committed Jul 31, 2023
1 parent cfe6fda commit a940445
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 33 deletions.
10 changes: 9 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,12 @@ repos:
rev: 23.1.0
hooks:
- id: black
language_version: python3.10
language_version: python3.10
- repo: local
hooks:
- id: pytest-check
name: pytest-check
entry: pytest
language: system
pass_filenames: false
always_run: true
83 changes: 51 additions & 32 deletions modbus_weather/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ def make_args_parser():
"api_key", action=EnvDefault, envvar="API_KEY", help="Openweather API key."
)
parser.add_argument(
"--api-query-period", default=5*60, type=float, help="Openweather API request period."
"--api-query-period",
default=5 * 60,
type=float,
help="Openweather API request period.",
)
parser.add_argument(
"--log-level",
Expand Down Expand Up @@ -82,14 +85,21 @@ def make_args_parser():
}


def get_current_time():
return datetime.now()


def get_lat_lon():
return 49.5938, 17.2509


def make_openweathermap_request(args):
def do_openweathermap_request(args):
lat, lon = get_lat_lon()
resp = requests.get(
OPENWEATHERMAP_API, params=dict(lat=lat, lon=lon, appid=args.api_key, exclude="minutely,hourly,daily,alerts")
OPENWEATHERMAP_API,
params=dict(
lat=lat, lon=lon, appid=args.api_key, exclude="minutely,hourly,daily,alerts"
),
).json()
_logger().debug(f"openweatherapi response: {resp}")
return resp
Expand Down Expand Up @@ -117,6 +127,7 @@ def g(obj):
return obj[item_name]
except KeyError as exc:
raise KeyError(f"{exc} when processing {obj}")

else:
try:

Expand Down Expand Up @@ -152,23 +163,23 @@ def tuplify(*items):


def extract_vals(resp):
current = resp['current']
current = resp["current"]
vals = [
current['temp'],
current['pressure'],
current['humidity'],
current['wind_speed'],
current['wind_deg'],
current['wind_gust'],
current['clouds'],
current['sunrise'],
current['sunset'],
current["temp"],
current["pressure"],
current["humidity"],
current["wind_speed"],
current["wind_deg"],
current["wind_gust"],
current["clouds"],
current["sunrise"],
current["sunset"],
]
return vals


async def get_weather_values(args):
vals = extract_vals(make_openweathermap_request(args))
vals = extract_vals(do_openweathermap_request(args))
return vals


Expand All @@ -192,7 +203,7 @@ async def updating_task(args):
and updates live values of the context. It should be noted
that there is a lrace condition for the update.
"""
while True:
while args.keep_running:
try:
_logger().debug("updating the context")
fc_as_hex = 3
Expand All @@ -202,18 +213,18 @@ async def updating_task(args):
# values = context[slave_id].getValues(fc_as_hex, address, count=3)
openweather_api_vals = await get_weather_values(args)

dt = datetime.now()
dt = get_current_time()
timestamp = dt.replace(tzinfo=timezone.utc).timestamp()
_logger().debug(f'timestamp: {timestamp}')
_logger().debug(f"timestamp: {timestamp}")

values = []
values.extend(get_version())
values.extend(convert_to_64bit_float_registers((timestamp,)))
values.extend(convert_to_32bit_float_registers(openweather_api_vals))
printout = list(f'{v:b}' for v in values)
_logger().debug(f'New values: {str(values)}')
_logger().debug(f'New values: {printout}')

printout = list(f"{v:b}" for v in values)
_logger().debug(f"New values: {str(values)}")
_logger().debug(f"New values: {printout}")

args.context[slave_id].setValues(fc_as_hex, address, values)
except Exception as exc:
Expand All @@ -222,7 +233,7 @@ async def updating_task(args):
await asyncio.sleep(args.api_query_period)


def setup_updating_server(args):
def setup_updating_server_args(args):
"""Run server setup."""
# The datastores only respond to the addresses that are initialized
# If you initialize a DataBlock to addresses of 0x00 to 0xFF, a request to
Expand All @@ -238,15 +249,26 @@ def setup_updating_server(args):
return setup_server(args)


async def run_updating_server(args):
async def start_updating_server(args):
"""Start updater task and async server."""
asyncio.create_task(updating_task(args))
await run_async_server(args)
return await run_async_server(args)


def complete_updating_tcp_async_server(cmd_args):
cmd_args.comm = "tcp"
cmd_args.framer = None
cmd_args.keep_running = True

set_logger(cmd_args)

run_args = setup_updating_server_args(cmd_args)
return run_args


def set_logger(cmd_args):
logging.basicConfig(level=get_log_level(cmd_args))


def get_log_level(cmd_args):
return cmd_args.log_level.upper()
Expand All @@ -255,10 +277,7 @@ def get_log_level(cmd_args):
def main():
parser = make_args_parser()
cmd_args = parser.parse_args()
cmd_args.comm = "tcp"
cmd_args.framer = None

set_logger(cmd_args)

run_args = setup_updating_server(cmd_args)
asyncio.run(run_updating_server(run_args), debug=('DEBUG' == get_log_level(cmd_args)))
run_args = complete_updating_tcp_async_server(cmd_args)
asyncio.run(
start_updating_server(run_args), debug=("DEBUG" == get_log_level(cmd_args))
)
122 changes: 122 additions & 0 deletions tests/test_connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import asyncio
import pytest
import socket
import logging
import json
import datetime
from copy import deepcopy

import modbus_weather
from pymodbus.client import AsyncModbusTcpClient

from argparse import Namespace

OPENWEATHERMAP_DATA = {
"lat": 49.5938,
"lon": 17.2509,
"timezone": "Europe/Prague",
"timezone_offset": 7200,
"current": {
"dt": 1690740521,
"sunrise": 1690687098,
"sunset": 1690742183,
"temp": 293.59,
"feels_like": 294.07,
"pressure": 1012,
"humidity": 91,
"dew_point": 292.07,
"uvi": 0,
"clouds": 73,
"visibility": 10000,
"wind_speed": 2.13,
"wind_deg": 160,
"wind_gust": 2.26,
"weather": [
{"id": 803, "main": "Clouds", "description": "broken clouds", "icon": "04d"}
],
},
}


async def _async_wait_for_server(event_loop, host, port):
while True:
a_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
await event_loop.sock_connect(a_socket, (host, port))
return
except ConnectionRefusedError:
await asyncio.sleep(0.01)

finally:
a_socket.close()


@pytest.fixture()
def server(event_loop, mocker):
mocker.patch("modbus_weather.app.do_openweathermap_request")
mocker.patch("modbus_weather.app.get_current_time")

modbus_weather.app.get_current_time.return_value = datetime.datetime(
1970, 1, 1, tzinfo=datetime.timezone.utc
)
modbus_weather.app.do_openweathermap_request.return_value = OPENWEATHERMAP_DATA

cmd_args = Namespace()
cmd_args.host = "localhost"
cmd_args.port = 502
cmd_args.log_level = "DEBUG"

cmd_args.api_query_period = 30
cmd_args.modbus_slave_id = 3
cmd_args.api_key = "MOCK_API_KEY"
run_args = modbus_weather.app.complete_updating_tcp_async_server(cmd_args)

cancel_handle = asyncio.ensure_future(
modbus_weather.app.start_updating_server(run_args), loop=event_loop
)
event_loop.run_until_complete(
asyncio.wait_for(
_async_wait_for_server(event_loop, cmd_args.host, cmd_args.port), 5.0
)
)

try:
yield cmd_args
finally:
cancel_handle.cancel()


@pytest.mark.asyncio
async def test_e2e_logic(mocker, server):
client = AsyncModbusTcpClient("localhost")

await client.connect()
response = await client.read_holding_registers(0x10, 24)
assert response.registers == [
0,
2,
0,
0,
0,
0,
37443,
34251,
32068,
0,
46658,
0,
2112,
60497,
8259,
0,
4160,
55203,
37442,
0,
51534,
44427,
51534,
23437,
]
server.keep_running = False
await client.close()

0 comments on commit a940445

Please sign in to comment.