mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-07-28 04:07:47 +00:00
refactoring test suite controller stuff
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
from espcore import *
|
||||
|
||||
import json
|
||||
import threading
|
||||
from queue import Queue
|
||||
from logging import getLogger
|
||||
import time
|
||||
|
||||
|
||||
SENSOR_TYPE_SINGLE = 1
|
||||
SENSOR_TYPE_TEMP_HUM = 2
|
||||
SENSOR_TYPE_TEMP_BARO = 3
|
||||
SENSOR_TYPE_TEMP_HUM_BARO = 4
|
||||
SENSOR_TYPE_DUAL = 5
|
||||
SENSOR_TYPE_TRIPLE = 6
|
||||
SENSOR_TYPE_QUAD = 7
|
||||
SENSOR_TYPE_SWITCH = 10
|
||||
SENSOR_TYPE_DIMMER = 11
|
||||
SENSOR_TYPE_LONG = 20
|
||||
SENSOR_TYPE_WIND = 21
|
||||
|
||||
class ControllerEmu:
|
||||
"""class that emulates and decodes various types of controllers. run various threads in the background to recveive and queue stuff"""
|
||||
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.log=logging.getLogger("controller")
|
||||
self.start_mqtt()
|
||||
self.start_http()
|
||||
|
||||
|
||||
def start_mqtt(self):
|
||||
"""generic mqtt receiver. just queues all reqeived mqtt messages on all topics"""
|
||||
getLogger("mqtt").debug("Connecting to {mqtt_broker}".format(mqtt_broker=config.mqtt_broker))
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
mqtt_client = mqtt.Client()
|
||||
mqtt_client.connect(config.mqtt_broker, 1883, 60)
|
||||
mqtt_client.loop_start()
|
||||
mqtt_client.subscribe('#')
|
||||
|
||||
self.mqtt_messages=Queue()
|
||||
def mqtt_on_message(client, userdata, message):
|
||||
logging.getLogger("mqtt").debug("Received message '" + str(message.payload) + "' on topic '"
|
||||
+ message.topic + "' with QoS " + str(message.qos))
|
||||
self.mqtt_messages.put(message)
|
||||
|
||||
mqtt_client.on_message=mqtt_on_message
|
||||
|
||||
|
||||
def clear_mqtt(self):
|
||||
"""clear queue"""
|
||||
while not self.mqtt_messages.empty():
|
||||
self.mqtt_messages.get()
|
||||
|
||||
|
||||
def start_http(self):
|
||||
"""generic http receiver. just queues all shallow copy of all http requests objects"""
|
||||
import bottle
|
||||
|
||||
self.http_requests = Queue()
|
||||
@bottle.post('<filename:path>')
|
||||
@bottle.get('<filename:path>')
|
||||
def urlhandler(filename):
|
||||
logging.getLogger("http").debug(bottle.request.method+" "+str(dict(bottle.request.params)))
|
||||
self.http_requests.put(bottle.request.copy())
|
||||
|
||||
http_thread=threading.Thread(target=bottle.run, kwargs=dict(host='0.0.0.0', port=config.http_port, reloader=False))
|
||||
http_thread.daemon=True
|
||||
http_thread.start()
|
||||
|
||||
|
||||
def clear_http(self):
|
||||
"""clear queue"""
|
||||
while not self.http_requests.empty():
|
||||
self.http_requests.get()
|
||||
|
||||
|
||||
def decode_domoticz(self, params, sensor_type, idx):
|
||||
"""decode domoticz parameter array to espeasy uservar (same parameters are used in domoticz http and mqtt)"""
|
||||
if int(params.get('idx'))==idx:
|
||||
if params.get('param')=='udevice':
|
||||
svalues_str=params.get('svalue').split(";")
|
||||
svalues=[]
|
||||
for svalue in svalues_str:
|
||||
svalues.append(float(svalue))
|
||||
|
||||
if sensor_type==SENSOR_TYPE_SINGLE and len(svalues)==1:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_DUAL and len(svalues)==2:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_HUM and len(svalues)==3:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_BARO and len(svalues)==5:
|
||||
return [svalues[0], svalues[3]]
|
||||
elif sensor_type==SENSOR_TYPE_TRIPLE and len(svalues)==3:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_HUM_BARO and len(svalues)==5:
|
||||
return [svalues[0],svalues[2], svalues[3]]
|
||||
elif sensor_type==SENSOR_TYPE_QUAD and len(svalues)==4:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_WIND and len(svalues)==5:
|
||||
return [svalues[0], svalues[2], svalues[3]]
|
||||
|
||||
elif params.get('param')=='switchlight':
|
||||
if sensor_type==SENSOR_TYPE_DIMMER or sensor_type == SENSOR_TYPE_SWITCH:
|
||||
if params.get('switchcmd') == 'Off':
|
||||
return [0]
|
||||
elif params.get('switchcmd') == 'On':
|
||||
return [1]
|
||||
elif params.get('switchcmd') == 'Set Level':
|
||||
return [int(params.get('level'))]
|
||||
return None
|
||||
|
||||
|
||||
def recv_domoticz_http(self, sensor_type, idx, timeout=60):
|
||||
"""recv a domoticz http request from espeasy, and convert back to espeasy values"""
|
||||
|
||||
start_time=time.time()
|
||||
self.log.info("Waiting for domoticz http request idx {idx} with sensortype {sensor_type}".format(sensor_type=sensor_type,idx=idx))
|
||||
|
||||
self.clear_http()
|
||||
|
||||
# read and parse http requests
|
||||
while time.time()-start_time<timeout:
|
||||
request=self.http_requests.get(block=True, timeout=timeout)
|
||||
if request.path == "/json.htm":
|
||||
uservar=self.decode_domoticz(request.params, sensor_type, idx)
|
||||
if uservar!=None:
|
||||
return uservar
|
||||
|
||||
raise(Exception("Timeout"))
|
||||
|
||||
|
||||
def recv_domoticz_mqtt(self, sensor_type, idx, timeout=60):
|
||||
"""recv a domoticz mqtt request from espeasy, and convert back to espeasy values"""
|
||||
|
||||
|
||||
start_time=time.time()
|
||||
self.log.info("Waiting for domoticz mqtt request idx {idx} with sensortype {sensor_type}".format(sensor_type=sensor_type,idx=idx))
|
||||
|
||||
self.clear_mqtt()
|
||||
|
||||
# read and parse mqtt requests
|
||||
while time.time()-start_time<timeout:
|
||||
message=self.mqtt_messages.get(block=True, timeout=timeout)
|
||||
if message.topic == "domoticz/in":
|
||||
#decode domoticz json (should be valid json! otherwise there is a bug)
|
||||
params=json.loads(message.payload.decode())
|
||||
print(params.get('idx'))
|
||||
uservar=self.decode_domoticz(params, sensor_type, idx)
|
||||
if uservar!=None:
|
||||
return uservar
|
||||
|
||||
|
||||
|
||||
raise(Exception("Timeout while expecting mqtt json message"))
|
||||
+50
-88
@@ -5,11 +5,6 @@
|
||||
import logging
|
||||
import colorlog
|
||||
import config
|
||||
import paho.mqtt.client as mqtt
|
||||
import json
|
||||
import bottle
|
||||
import threading
|
||||
from queue import Queue, Empty
|
||||
|
||||
colorlog.basicConfig(level=logging.DEBUG)
|
||||
|
||||
@@ -17,92 +12,59 @@ colorlog.basicConfig(level=logging.DEBUG)
|
||||
logging.getLogger("requests.packages.urllib3.connectionpool").setLevel(logging.ERROR)
|
||||
|
||||
|
||||
### mqtt stuff
|
||||
logging.getLogger("MQTT").debug("Connecting to {mqtt_broker}".format(mqtt_broker=config.mqtt_broker))
|
||||
|
||||
|
||||
log=logging.getLogger("testcore")
|
||||
|
||||
mqtt_client = mqtt.Client()
|
||||
mqtt_client.connect(config.mqtt_broker, 1883, 60)
|
||||
mqtt_client.loop_start()
|
||||
mqtt_client.subscribe('#')
|
||||
|
||||
mqtt_messages=[]
|
||||
def mqtt_on_message(client, userdata, message):
|
||||
logging.getLogger("MQTT").debug("Received message '" + str(message.payload) + "' on topic '"
|
||||
+ message.topic + "' with QoS " + str(message.qos))
|
||||
mqtt_messages.append(message)
|
||||
|
||||
mqtt_client.on_message=mqtt_on_message
|
||||
|
||||
|
||||
def mqtt_expect_json(topic, matches, timeout=60):
|
||||
"""wait until a specific json message is received, and return it decoded. ignores all other messages"""
|
||||
|
||||
start_time=time.time()
|
||||
|
||||
logging.getLogger("MQTT").info("Waiting for json message on topic {topic}, with values {matches}".format(topic=topic, matches=matches))
|
||||
|
||||
# check mqtt results
|
||||
while time.time()-start_time<timeout:
|
||||
while mqtt_messages:
|
||||
message=mqtt_messages.pop()
|
||||
try:
|
||||
#ignore decoding exceptions
|
||||
payload=json.loads(message.payload.decode())
|
||||
except:
|
||||
continue
|
||||
|
||||
if message.topic == topic:
|
||||
ok=True
|
||||
for match in matches.items():
|
||||
if not match[0] in payload or payload[match[0]]!=match[1]:
|
||||
ok=False
|
||||
if ok:
|
||||
return(payload)
|
||||
time.sleep(1)
|
||||
|
||||
raise(Exception("Timeout while expecting mqtt json message"))
|
||||
# def mqtt_expect_json(topic, matches, timeout=60):
|
||||
# """wait until a specific json message is received, and return it decoded. ignores all other messages"""
|
||||
#
|
||||
# start_time=time.time()
|
||||
#
|
||||
# logging.getLogger("MQTT").info("Waiting for json message on topic {topic}, with values {matches}".format(topic=topic, matches=matches))
|
||||
#
|
||||
# # check mqtt results
|
||||
# while time.time()-start_time<timeout:
|
||||
# while mqtt_messages:
|
||||
# message=mqtt_messages.pop()
|
||||
# try:
|
||||
# #ignore decoding exceptions
|
||||
# payload=json.loads(message.payload.decode())
|
||||
# except:
|
||||
# continue
|
||||
#
|
||||
# if message.topic == topic:
|
||||
# ok=True
|
||||
# for match in matches.items():
|
||||
# if not match[0] in payload or payload[match[0]]!=match[1]:
|
||||
# ok=False
|
||||
# if ok:
|
||||
# return(payload)
|
||||
# time.sleep(1)
|
||||
#
|
||||
# raise(Exception("Timeout while expecting mqtt json message"))
|
||||
|
||||
|
||||
|
||||
### http server stuff.
|
||||
|
||||
# the http server just accepts everything and stores it in the http_requests queue
|
||||
import bottle
|
||||
|
||||
http_requests = Queue()
|
||||
@bottle.post('<filename:path>')
|
||||
@bottle.get('<filename:path>')
|
||||
def urlhandler(filename):
|
||||
logging.getLogger("HTTP").debug(bottle.request.method+" "+str(dict(bottle.request.params)))
|
||||
http_requests.put(bottle.request.copy())
|
||||
|
||||
http_thread=threading.Thread(target=bottle.run, kwargs=dict(host='0.0.0.0', port=config.http_port, reloader=False))
|
||||
http_thread.daemon=True
|
||||
http_thread.start()
|
||||
|
||||
def http_expect_request(path, matches, timeout=60):
|
||||
"""wait until a specific path and paraters are request on the http server. ignores all other requests"""
|
||||
|
||||
start_time=time.time()
|
||||
|
||||
logging.getLogger("HTTP").info("Waiting for http request on path {path}, with values {matches}".format(path=path, matches=matches))
|
||||
|
||||
# check http results
|
||||
while time.time()-start_time<timeout:
|
||||
while True:
|
||||
request=http_requests.get(block=True, timeout=timeout)
|
||||
# logging.getLogger("HTTP").debug("Body: "+str(request.body.str))
|
||||
if request.path == path:
|
||||
|
||||
ok=True
|
||||
for match in matches.items():
|
||||
if not match[0] in request.params or request.params[match[0]]!=match[1]:
|
||||
ok=False
|
||||
if ok:
|
||||
return(request)
|
||||
time.sleep(1)
|
||||
|
||||
raise(Exception("Timeout while expecting http message"))
|
||||
# def http_expect_request(path, matches, timeout=60):
|
||||
# """wait until a specific path and paraters are request on the http server. ignores all other requests"""
|
||||
#
|
||||
# start_time=time.time()
|
||||
#
|
||||
# logging.getLogger("HTTP").info("Waiting for http request on path {path}, with values {matches}".format(path=path, matches=matches))
|
||||
#
|
||||
# # check http results
|
||||
# while time.time()-start_time<timeout:
|
||||
# while True:
|
||||
# request=http_requests.get(block=True, timeout=timeout)
|
||||
# # logging.getLogger("HTTP").debug("Body: "+str(request.body.str))
|
||||
# if request.path == path:
|
||||
#
|
||||
# ok=True
|
||||
# for match in matches.items():
|
||||
# if not match[0] in request.params or request.params[match[0]]!=match[1]:
|
||||
# ok=False
|
||||
# if ok:
|
||||
# return(request)
|
||||
# time.sleep(1)
|
||||
#
|
||||
# raise(Exception("Timeout while expecting http message"))
|
||||
|
||||
@@ -4,20 +4,8 @@
|
||||
|
||||
from espcore import *
|
||||
|
||||
import time
|
||||
|
||||
|
||||
SENSOR_TYPE_SINGLE = 1
|
||||
SENSOR_TYPE_TEMP_HUM = 2
|
||||
SENSOR_TYPE_TEMP_BARO = 3
|
||||
SENSOR_TYPE_TEMP_HUM_BARO = 4
|
||||
SENSOR_TYPE_DUAL = 5
|
||||
SENSOR_TYPE_TRIPLE = 6
|
||||
SENSOR_TYPE_QUAD = 7
|
||||
SENSOR_TYPE_SWITCH = 10
|
||||
SENSOR_TYPE_DIMMER = 11
|
||||
SENSOR_TYPE_LONG = 20
|
||||
SENSOR_TYPE_WIND = 21
|
||||
|
||||
class EspEasy:
|
||||
|
||||
@@ -86,52 +74,10 @@ class EspEasy:
|
||||
""".format(**kwargs)
|
||||
)
|
||||
|
||||
def recv_domoticz_http(self, sensor_type, idx, timeout=60):
|
||||
"""recv a domoticz http request from espeasy, and convert back to espeasy values"""
|
||||
|
||||
start_time=time.time()
|
||||
logging.getLogger("domoticz http").info("Waiting for request idx {idx} with sensortype {sensor_type}".format(sensor_type=sensor_type,idx=idx))
|
||||
|
||||
# read and parse http requests
|
||||
while not http_requests.empty():
|
||||
http_requests.get()
|
||||
|
||||
while time.time()-start_time<timeout:
|
||||
request=http_requests.get(block=True, timeout=timeout)
|
||||
if request.path == "/json.htm" and int(request.params.get('idx'))==idx:
|
||||
if request.params.get('param')=='udevice':
|
||||
svalues_str=request.params.get('svalue').split(";")
|
||||
svalues=[]
|
||||
for svalue in svalues_str:
|
||||
svalues.append(float(svalue))
|
||||
|
||||
if sensor_type==SENSOR_TYPE_SINGLE and len(svalues)==1:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_DUAL and len(svalues)==2:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_HUM and len(svalues)==3:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_BARO and len(svalues)==5:
|
||||
return [svalues[0], svalues[3]]
|
||||
elif sensor_type==SENSOR_TYPE_TRIPLE and len(svalues)==3:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_HUM_BARO and len(svalues)==5:
|
||||
return [svalues[0],svalues[2], svalues[3]]
|
||||
elif sensor_type==SENSOR_TYPE_QUAD and len(svalues)==4:
|
||||
return svalues
|
||||
elif sensor_type==SENSOR_TYPE_WIND and len(svalues)==5:
|
||||
return [svalues[0], svalues[2], svalues[3]]
|
||||
|
||||
elif request.params.get('param')=='switchlight':
|
||||
if sensor_type==SENSOR_TYPE_DIMMER or sensor_type == SENSOR_TYPE_SWITCH:
|
||||
if request.params.get('switchcmd') == 'Off':
|
||||
return [0]
|
||||
elif request.params.get('switchcmd') == 'On':
|
||||
return [1]
|
||||
elif request.params.get('switchcmd') == 'Set Level':
|
||||
return [int(request.params.get('level'))]
|
||||
|
||||
raise(Exception("Timeout"))
|
||||
|
||||
|
||||
|
||||
|
||||
+9
-1
@@ -7,15 +7,17 @@
|
||||
# from espeasy import *
|
||||
from node import *
|
||||
from espeasy import *
|
||||
from controlleremu import *
|
||||
|
||||
import config
|
||||
import time
|
||||
import shelve
|
||||
import os
|
||||
from espcore import *
|
||||
|
||||
|
||||
|
||||
### create node objects and espeasy objects
|
||||
|
||||
node=[]
|
||||
espeasy=[]
|
||||
|
||||
@@ -26,6 +28,12 @@ for n in config.nodes:
|
||||
|
||||
steps=[]
|
||||
|
||||
log=logging.getLogger("esptest")
|
||||
|
||||
|
||||
## controller emulators
|
||||
controller=ControllerEmu()
|
||||
|
||||
### keep test state, so we can skip tests.
|
||||
state={
|
||||
'module': None,
|
||||
|
||||
+28
-25
@@ -15,7 +15,7 @@ from esptest import *
|
||||
|
||||
|
||||
@step
|
||||
def prepare():
|
||||
def prepare_http():
|
||||
"""configure devices and controller"""
|
||||
node[0].reboot()
|
||||
node[0].pingserial()
|
||||
@@ -25,36 +25,39 @@ def prepare():
|
||||
|
||||
|
||||
@step
|
||||
def recv():
|
||||
"""wait for result"""
|
||||
results=espeasy[0].recv_domoticz_http(SENSOR_TYPE_SINGLE,1417)
|
||||
def recv_http():
|
||||
"""wait for http result"""
|
||||
results=controller.recv_domoticz_http(SENSOR_TYPE_SINGLE,1417)
|
||||
test_in_range(results[0], -5,40)
|
||||
results=espeasy[0].recv_domoticz_http(SENSOR_TYPE_SINGLE,1418)
|
||||
results=controller.recv_domoticz_http(SENSOR_TYPE_SINGLE,1418)
|
||||
test_in_range(results[0], -5,40)
|
||||
|
||||
|
||||
|
||||
|
||||
# @step
|
||||
# def powercycle():
|
||||
# """test result on poweron"""
|
||||
# node[0].powercycle()
|
||||
# results=controller.recv_domoticz_http(SENSOR_TYPE_SINGLE,1417)
|
||||
# test_in_range(results[0], -5,40)
|
||||
# results=controller.recv_domoticz_http(SENSOR_TYPE_SINGLE,1418)
|
||||
# test_in_range(results[0], -5,40)
|
||||
|
||||
|
||||
@step
|
||||
def powercycle():
|
||||
"""test result on poweron"""
|
||||
node[0].powercycle()
|
||||
results=espeasy[0].recv_domoticz_http(SENSOR_TYPE_SINGLE,1417)
|
||||
test_in_range(results[0], -5,40)
|
||||
results=espeasy[0].recv_domoticz_http(SENSOR_TYPE_SINGLE,1418)
|
||||
test_in_range(results[0], -5,40)
|
||||
def prepare_mqtt():
|
||||
"""switch to mqtt"""
|
||||
espeasy[0].controller_domoticz_mqtt(index=1, controllerip=config.mqtt_broker)
|
||||
|
||||
|
||||
# @step
|
||||
# def prepare_mqtt():
|
||||
# """switch to mqtt"""
|
||||
# espeasy[0].controller_domoticz_mqtt(index=1, controllerip=config.mqtt_broker)
|
||||
#
|
||||
#
|
||||
# @step
|
||||
# def recv():
|
||||
# """wait for mqtt result"""
|
||||
# results=espeasy[0].recv_domoticz_mqtt(SENSOR_TYPE_SINGLE,1417)
|
||||
# test_in_range(results[0], -5,40)
|
||||
# results=espeasy[0].recv_domoticz_mqtt(SENSOR_TYPE_SINGLE,1418)
|
||||
# test_in_range(results[0], -5,40)
|
||||
@step
|
||||
def recv_mqtt():
|
||||
"""wait for mqtt result"""
|
||||
results=controller.recv_domoticz_mqtt(SENSOR_TYPE_SINGLE,1417)
|
||||
test_in_range(results[0], -5,40)
|
||||
results=controller.recv_domoticz_mqtt(SENSOR_TYPE_SINGLE,1418)
|
||||
test_in_range(results[0], -5,40)
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user