Skip to content

Commit

Permalink
Merge pull request #23 from GRIDAPPSD/releases/2020.12.0
Browse files Browse the repository at this point in the history
Release of version 2020.12.0
  • Loading branch information
poorva1209 authored Feb 22, 2021
2 parents 850ec18 + 15e3c05 commit 77c351e
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 98 deletions.
18 changes: 18 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from copy import deepcopy
from pathlib import Path
from py.xml import html

import pytest
from gridappsd import GOSS, GridAPPSD
Expand Down Expand Up @@ -104,3 +105,20 @@ def gridappsd_client(docker_dependencies):
# yield gappsd
#
# gappsd.disconnect()


# Add description column to the html report and fill with the __doc__ text

def pytest_html_results_table_header(cells):
cells.insert(2, html.th("Description"))


def pytest_html_results_table_row(report, cells):
cells.insert(2, html.td(report.description))


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
report.description = str(item.function.__doc__)
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
git+https://github.com/GRIDAPPSD/gridappsd-python.git@develop#egg=gridappsd
pytest
docker
pandas
mock
pytest-html
4 changes: 2 additions & 2 deletions simulation_config_files/9500-timeseries-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@
"id": "gridappsd-sensor-simulator",
"user_options": {
"default-perunit-confidence-band": 0.02,
"simulate-all": false,
"simulate-all": true,
"sensors-config": {},
"default-normal-value": 100,
"random-seed": 0,
"default-aggregation-interval": 30,
"passthrough-if-not-specified": false,
"passthrough-if-not-specified": true,
"default-perunit-drop-rate": 0.05
}
}]
Expand Down
109 changes: 109 additions & 0 deletions test_logging_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import os
import time
import mock
import pytest
from gridappsd import GridAPPSD, topics as t
from gridappsd.loghandler import Logger


@pytest.fixture
def logger_and_gridapspd(gridappsd_client) -> (Logger, GridAPPSD):

logger = Logger(gridappsd_client)

yield logger, gridappsd_client

logger = None


@mock.patch.dict(os.environ,
dict(GRIDAPPSD_APPLICATION_ID='sample_app',
GRIDAPPSD_APPLICATION_STATUS='RUNNING'))
def test_log_stored(record_property, logger_and_gridapspd):
"""This function queries the database through the gridappsd api. Specifically checking that the
specific logs are available. The results are interrogated for multiple logs pushed to the topic and stored in the
database. The return values of the query are interrogated and the values associated are tested """
logger, gapps = logger_and_gridapspd
doc_str = """This function queries the database through the gridappsd api. Specifically checking that the
specific logs are available. The results are interrogated for multiple logs pushed to the topic and stored in the
database. The return values of the query are interrogated and the values associated are tested """

record_property("gridappsd_doc", doc_str)
log_data_map = [
(logger.debug, "A debug message", "DEBUG"),
(logger.info, "An info message", "INFO"),
(logger.error, "An error message", "ERROR"),
(logger.error, "Another error message", "ERROR"),
(logger.info, "Another info message", "INFO"),
(logger.debug, "A debug message", "DEBUG")
]

assert gapps.connected

# Make the calls to debug
for d in log_data_map:
d[0](d[1])

payload = {
"query": "select * from log order by timestamp"
}
time.sleep(5)
response = gapps.get_response(t.LOGS, payload, timeout=60)
assert response['data'], "There were not any records returned."

for x in response['data']:
if x['source'] != 'sample_app':
continue
expected = log_data_map.pop(0)
assert expected[1] == x['log_message']
assert expected[2] == x['log_level']


SIMULATION_ID='54321'

#TODO Ask about loging api for simulations.
@mock.patch.dict(os.environ,
dict(GRIDAPPSD_APPLICATION_ID='new_sample_app',
GRIDAPPSD_APPLICATION_STATUS='RUNNING',
GRIDAPPSD_SIMULATION_ID=SIMULATION_ID))
def test_simulation_log_stored(record_property, logger_and_gridapspd):
"""This function queries the database through the gridappsd api. Specifically checking that the
specific logs are available in simulation log. The results are interrogated for the logs pushed to the topic and
stored in the database. The return values of the query are interrogated and the values associated are tested """
logger, gapps = logger_and_gridapspd
doc_str = """This function queries the database through the gridappsd api. Specifically checking that the
specific logs are available in simulation log. The results are interrogated for the logs pushed to the topic and
stored in the database. The return values of the query are interrogated and the values associated are tested """

record_property("gridappsd_doc", doc_str)
assert gapps.get_simulation_id() == SIMULATION_ID

log_data_map = [
(logger.debug, "A debug message", "DEBUG"),
(logger.info, "An info message", "INFO"),
(logger.error, "An error message", "ERROR"),
(logger.error, "Another error message", "ERROR"),
(logger.info, "Another info message", "INFO"),
(logger.debug, "A debug message", "DEBUG")
]

assert gapps.connected

# Make the calls to debug
for d in log_data_map:
d[0](d[1])

time.sleep(5)
payload = {
"query": "select * from log"
}

response = gapps.get_response(t.LOGS, payload, timeout=60)
assert response['data'], "There were not any records returned."

for x in response['data']:
if x['source'] != 'new_sample_app':
continue
expected = log_data_map.pop(0)
assert expected[1] == x['log_message']
assert expected[2] == x['log_level']
175 changes: 80 additions & 95 deletions test_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,115 +6,100 @@
from time import sleep, time
import sys
import pytest
from gridappsd import GridAPPSD, topics as t
# tm: added for run_simulation workaround

from gridappsd import GridAPPSD
from gridappsd.simulation import Simulation
from gridappsd_docker import docker_up, docker_down

logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
from gridappsd import GridAPPSD, topics as t

LOGGER = logging.getLogger(__name__)


@contextmanager
def startup_containers(spec=None):
LOGGER.info('Starting gridappsd containers')
docker_up(spec)
LOGGER.info('Containers started')

yield

LOGGER.info('Stopping gridappsd containers')
# docker_down()
# LOGGER.info('Containers stopped')


@contextmanager
def gappsd() -> GridAPPSD:
gridappsd = GridAPPSD()
LOGGER.info('Gridappsd connected')

yield gridappsd

gridappsd.disconnect()
LOGGER.info('Gridappsd disconnected')

result_weather_data = []
result_timeseries_query = []
result_sensor_query = []

@pytest.mark.parametrize("sim_config_file, sim_result_file", [
("9500-timeseries-config.json", "9500-simulation.json")
# ("123-config.json", "123-simulation.json"),
# ("13-node-config.json", "13-node-sim.json"),
# , ("t3-p1-config.json", "t3-p1.json"),
])
def test_timeseries_output(sim_config_file, sim_result_file):
def test_timeseries_output(gridappsd_client, sim_config_file, sim_result_file):
global result_weather_data
global result_timeseries_query
global result_sensor_query
simulation_id = None
sim_config_file = os.path.join(os.path.dirname(__file__), f"simulation_config_files/{sim_config_file}")
sim_result_file = os.path.join(os.path.dirname(__file__), f"simulation_baseline_files/{sim_result_file}")
# sim_test_config = os.path.join(os.path.dirname(__file__), f"simulation_baseline_files/{sim_test_file}")

assert os.path.exists(sim_config_file), f"File {sim_config_file} must exist to run simulation test"
# assert os.path.exists(sim_result_file), f"File {sim_result_file} must exist to run simulation test"

with startup_containers():
with gappsd() as gapps:
os.makedirs("/tmp/output", exist_ok=True)
with open("/tmp/output/simulation.json", 'w') as outfile:
sim_complete = False
rcvd_measurement = False

def onmeasurement(sim, timestep, measurements):
nonlocal rcvd_measurement
# print(rcvd_measurement)
if not rcvd_measurement:
# print(f"A measurement happened at {timestep}")
LOGGER.info('Measurement received at %s', timestep)
outfile.write(f"{timestep}|{json.dumps(measurements)}\n")

with open(sim_config_file) as fp:
run_config = json.load(fp)
starttime = run_config["simulation_config"]["start_time"]
# run_config["simulation_config"]["start_time"] = str(starttime)
print(run_config["simulation_config"]["start_time"])

def onfinishsimulation(sim):
nonlocal sim_complete
sim_complete = True
LOGGER.info('Simulation Complete')

sim = Simulation(gapps, run_config)
sim.add_oncomplete_callback(onfinishsimulation)
sim.add_onmesurement_callback(onmeasurement)
sim.start_simulation()
LOGGER.info("Starting simulation")
print(sim.simulation_id)

with open("./simulation_config_files/weather_data.json", 'r') as g:
LOGGER.info('Querying weather data from timeseries')
query1 = json.load(g)

a = gapps.get_response(t.TIMESERIES, query1, timeout=60)
LOGGER.info('Weather data received ')
assert "Diffuse" in a["data"][0], "Weather data query does not have expected output"
LOGGER.info('Weather data query has expected output')

while not sim_complete:
sleep(5)

with open("./simulation_config_files/timeseries_query.json", 'r') as f:
query2 = json.load(f)
query2["queryFilter"]["simulation_id"] = sim.simulation_id
LOGGER.info('Querying simulation data from timeseries')
q = gapps.get_response(t.TIMESERIES, query2, timeout=300)
LOGGER.info('Simulation data received for Timeseries API')
file2 = open("./out-input.txt", 'w')
file2.write(json.dumps(q))
assert "hasSimulationMessageType" in q["data"][0], "Simulation data query does not have expected output"
LOGGER.info('Simulation data query has expected output')

with open("./simulation_config_files/sensor_query.json", 'r') as file:
sensor_query = json.load(file)
sensor_query["queryFilter"]["simulation_id"] = sim.simulation_id
LOGGER.info('Querying GridAPPS-D sensor simulator data from timeseries')
result = gapps.get_response(t.TIMESERIES, sensor_query, timeout=300)
assert "hasSimulationMessageType" in result["data"][0], "Sensor simulator data does not have expected output"
LOGGER.info('Query response received for GridAPPS-D sensor simulator data from timeseries')

gapps = gridappsd_client
sim_complete = False
rcvd_measurement = False

def onmeasurement(sim, timestep, measurements):
LOGGER.info('Measurement received at %s', timestep)

def onfinishsimulation(sim):
nonlocal sim_complete
sim_complete = True
LOGGER.info('Simulation Complete')

with open(sim_config_file) as fp:
LOGGER.info('Loading config')
run_config = json.load(fp)
LOGGER.info(f'Simulation start time {run_config["simulation_config"]["start_time"]}')

LOGGER.info('Starting the simulation')
sim = Simulation(gapps, run_config)
sim.start_simulation()
LOGGER.info(f'Simulation id {sim.simulation_id}')

LOGGER.info('sim.add_oncomplete_callback')
sim.add_oncomplete_callback(onfinishsimulation)

LOGGER.info('sim.add_onmeasurement_callback')
sim.add_onmesurement_callback(onmeasurement)

with open("./simulation_config_files/weather_data.json", 'r') as g:
LOGGER.info('Querying weather data from timeseries')
query1 = json.load(g)
result_weather_data = gapps.get_response(t.TIMESERIES, query1, timeout=60)
LOGGER.info('Weather data received ')

while not sim_complete:
LOGGER.info('Sleeping')
sleep(5)
else:
with open("./simulation_config_files/timeseries_query.json", 'r') as f:
query2 = json.load(f)
query2["queryFilter"]["simulation_id"] = sim.simulation_id
LOGGER.info('Querying simulation data from timeseries')
result_timeseries_query = gapps.get_response(t.TIMESERIES, query2, timeout=300)
LOGGER.info('Simulation data received for Timeseries API')

with open("./simulation_config_files/sensor_query.json", 'r') as file:
sensor_query = json.load(file)
sensor_query["queryFilter"]["simulation_id"] = sim.simulation_id
LOGGER.info('Querying GridAPPS-D sensor simulator data from timeseries')
result_sensor_query = gapps.get_response(t.TIMESERIES, sensor_query, timeout=300)
LOGGER.info('Simulation data received for sensor simulator')

def test_weather_api():
global result_weather_data
assert "Diffuse" in result_weather_data["data"][0], \
"Weather data query does not have expected output"
LOGGER.info('Weather data query has expected output')

def test_timeseries_simulation_api():
global result_timeseries_query
assert "hasSimulationMessageType" in result_timeseries_query["data"][0], \
"Simulation data query does not have expected output"
LOGGER.info('Simulation data query has expected output')

def test_sensor_simulator_api():
global result_sensor_query
assert "hasSimulationMessageType" in result_sensor_query["data"][0], \
"Sensor simulator data does not have expected output"
LOGGER.info('Query response received for GridAPPS-D sensor simulator data from timeseries')

0 comments on commit 77c351e

Please sign in to comment.