Skip to content
Snippets Groups Projects
Verified Commit 913e60d0 authored by David Hoese's avatar David Hoese
Browse files

Switch data api tests to pytest

parent c5789b77
Branches
No related tags found
No related merge requests found
import json import json
import unittest
from unittest import mock from unittest import mock
import metobsapi import pytest
def fake_data(interval, symbols, num_vals, single_result=False): def fake_data(interval, symbols, num_vals, single_result=False):
...@@ -53,121 +52,129 @@ def fake_data(interval, symbols, num_vals, single_result=False): ...@@ -53,121 +52,129 @@ def fake_data(interval, symbols, num_vals, single_result=False):
return series return series
class TestDataAPI(unittest.TestCase): @pytest.fixture
def setUp(self): def app():
metobsapi.app.config["TESTING"] = True from metobsapi import app as real_app
metobsapi.app.config["DEBUG"] = True
self.app = metobsapi.app.test_client()
def test_doc(self): real_app.config.update({"TESTING": True, "DEBUG": True})
res = self.app.get("/api/data") yield real_app
@pytest.fixture
def client(app):
return app.test_client()
class TestDataAPI:
def test_doc(self, client):
res = client.get("/api/data")
assert b"Data Request Application" in res.data assert b"Data Request Application" in res.data
def test_bad_format(self): def test_bad_format(self, client):
res = self.app.get("/api/data.fake") res = client.get("/api/data.fake")
self.assertIn(b"No data file format", res.data) assert b"No data file format" in res.data
def test_bad_begin_json(self): def test_bad_begin_json(self, client):
res = self.app.get("/api/data.json?symbols=air_temp&begin=blah") res = client.get("/api/data.json?symbols=air_temp&begin=blah")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertEqual(res["code"], 400) assert res["code"] == 400
self.assertEqual(res["status"], "error") assert res["status"] == "error"
self.assertIn("timestamp", res["message"]) assert "timestamp" in res["message"]
def test_bad_order(self): def test_bad_order(self, client):
res = self.app.get("/api/data.json?order=blah&symbols=air_temp") res = client.get("/api/data.json?order=blah&symbols=air_temp")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertIn("column", res["message"]) assert "column" in res["message"]
self.assertIn("row", res["message"]) assert "row" in res["message"]
def test_bad_epoch(self): def test_bad_epoch(self, client):
res = self.app.get("/api/data.json?epoch=blah&symbols=air_temp") res = client.get("/api/data.json?epoch=blah&symbols=air_temp")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertIn("'h'", res["message"]) assert "'h'" in res["message"]
self.assertIn("'m'", res["message"]) assert "'m'" in res["message"]
self.assertIn("'s'", res["message"]) assert "'s'" in res["message"]
self.assertIn("'u'", res["message"]) assert "'u'" in res["message"]
def test_bad_interval(self): def test_bad_interval(self, client):
res = self.app.get("/api/data.json?interval=blah&symbols=air_temp") res = client.get("/api/data.json?interval=blah&symbols=air_temp")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertIn("'1m'", res["message"]) assert "'1m'" in res["message"]
self.assertIn("'5m'", res["message"]) assert "'5m'" in res["message"]
self.assertIn("'1h'", res["message"]) assert "'1h'" in res["message"]
def test_missing_inst(self): def test_missing_inst(self, client):
res = self.app.get("/api/data.json?site=X&symbols=air_temp&begin=-05:00:00") res = client.get("/api/data.json?site=X&symbols=air_temp&begin=-05:00:00")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertEqual(res["code"], 400) assert res["code"] == 400
self.assertEqual(res["status"], "error") assert res["status"] == "error"
self.assertIn("'site'", res["message"]) assert "'site'" in res["message"]
self.assertIn("'inst'", res["message"]) assert "'inst'" in res["message"]
def test_missing_site(self): def test_missing_site(self, client):
res = self.app.get("/api/data.json?inst=X&symbols=air_temp&begin=-05:00:00") res = client.get("/api/data.json?inst=X&symbols=air_temp&begin=-05:00:00")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertEqual(res["code"], 400) assert res["code"] == 400
self.assertEqual(res["status"], "error") assert res["status"] == "error"
self.assertIn("'site'", res["message"]) assert "'site'" in res["message"]
self.assertIn("'inst'", res["message"]) assert "'inst'" in res["message"]
def test_missing_symbols(self): def test_missing_symbols(self, client):
res = self.app.get("/api/data.json?begin=-05:00:00") res = client.get("/api/data.json?begin=-05:00:00")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertEqual(res["code"], 400) assert res["code"] == 400
self.assertEqual(res["status"], "error") assert res["status"] == "error"
self.assertIn("'symbols'", res["message"]) assert "'symbols'" in res["message"]
def test_too_many_points(self): def test_too_many_points(self, client):
res = self.app.get("/api/data.json?symbols=aoss.tower.air_temp&begin=1970-01-01T00:00:00") res = client.get("/api/data.json?symbols=aoss.tower.air_temp&begin=1970-01-01T00:00:00")
self.assertEqual(res.status_code, 413) assert res.status_code == 413
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertIn("too many values", res["message"]) assert "too many values" in res["message"]
self.assertEqual(res["code"], 413) assert res["code"] == 413
self.assertEqual(res["status"], "fail") assert res["status"] == "fail"
@mock.patch("metobsapi.data_api.query") @mock.patch("metobsapi.data_api.query")
def test_shorthand_one_symbol_json_row(self, query_func): def test_shorthand_one_symbol_json_row(self, query_func, client):
r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp"]}, 9) r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp"]}, 9)
query_func.return_value = r query_func.return_value = r
# row should be the default # row should be the default
res = self.app.get("/api/data.json?site=aoss&inst=tower&symbols=air_temp&begin=-00:10:00") res = client.get("/api/data.json?site=aoss&inst=tower&symbols=air_temp&begin=-00:10:00")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertEqual(res["code"], 200) assert res["code"] == 200
self.assertEqual(res["num_results"], 9) assert res["num_results"] == 9
self.assertListEqual(res["results"]["symbols"], ["air_temp"]) assert res["results"]["symbols"] == ["air_temp"]
self.assertEqual(len(res["results"]["timestamps"]), 9) assert len(res["results"]["timestamps"]) == 9
self.assertEqual(len(res["results"]["data"]), 9) assert len(res["results"]["data"]) == 9
self.assertEqual(len(res["results"]["data"][0]), 1) assert len(res["results"]["data"][0]) == 1
@mock.patch("metobsapi.data_api.query") @mock.patch("metobsapi.data_api.query")
def test_shorthand_one_symbol_json_column(self, query_func): def test_shorthand_one_symbol_json_column(self, query_func, client):
r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp"]}, 9) r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp"]}, 9)
query_func.return_value = r query_func.return_value = r
res = self.app.get("/api/data.json?site=aoss&inst=tower&symbols=air_temp&begin=-00:10:00&order=column") res = client.get("/api/data.json?site=aoss&inst=tower&symbols=air_temp&begin=-00:10:00&order=column")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertEqual(res["code"], 200) assert res["code"] == 200
self.assertEqual(res["num_results"], 9) assert res["num_results"] == 9
self.assertIn("air_temp", res["results"]["data"]) assert "air_temp" in res["results"]["data"]
self.assertEqual(len(res["results"]["data"]["air_temp"]), 9) assert len(res["results"]["data"]["air_temp"]) == 9
self.assertEqual(len(res["results"]["timestamps"]), 9) assert len(res["results"]["timestamps"]) == 9
@mock.patch("metobsapi.data_api.query") @mock.patch("metobsapi.data_api.query")
def test_wind_speed_direction_json(self, query_func): def test_wind_speed_direction_json(self, query_func, client):
r = fake_data("1m", {("aoss", "tower"): ["time", "wind_speed", "wind_direction", "wind_east", "wind_north"]}, 9) r = fake_data("1m", {("aoss", "tower"): ["time", "wind_speed", "wind_direction", "wind_east", "wind_north"]}, 9)
query_func.return_value = r query_func.return_value = r
res = self.app.get( res = client.get(
"/api/data.json?symbols=aoss.tower.wind_speed:aoss.tower.wind_direction&begin=-00:10:00&order=column" "/api/data.json?symbols=aoss.tower.wind_speed:aoss.tower.wind_direction&begin=-00:10:00&order=column"
) )
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertEqual(res["code"], 200) assert res["code"] == 200
self.assertEqual(res["num_results"], 9) assert res["num_results"] == 9
self.assertIn("aoss.tower.wind_direction", res["results"]["data"]) assert "aoss.tower.wind_direction" in res["results"]["data"]
self.assertIn("aoss.tower.wind_speed", res["results"]["data"]) assert "aoss.tower.wind_speed" in res["results"]["data"]
self.assertEqual(len(list(res["results"]["data"].keys())), 2) assert len(list(res["results"]["data"].keys())) == 2
@mock.patch("metobsapi.data_api.query") @mock.patch("metobsapi.data_api.query")
def test_one_symbol_two_insts_json_row(self, query_func): def test_one_symbol_two_insts_json_row(self, query_func, client):
r = fake_data( r = fake_data(
"1m", "1m",
{ {
...@@ -178,17 +185,17 @@ class TestDataAPI(unittest.TestCase): ...@@ -178,17 +185,17 @@ class TestDataAPI(unittest.TestCase):
) )
query_func.return_value = r query_func.return_value = r
# row should be the default # row should be the default
res = self.app.get("/api/data.json?symbols=aoss.tower.air_temp:mendota.buoy.air_temp&begin=-00:10:00") res = client.get("/api/data.json?symbols=aoss.tower.air_temp:mendota.buoy.air_temp&begin=-00:10:00")
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertEqual(res["code"], 200) assert res["code"] == 200
self.assertEqual(res["num_results"], 9) assert res["num_results"] == 9
self.assertListEqual(res["results"]["symbols"], ["aoss.tower.air_temp", "mendota.buoy.air_temp"]) assert res["results"]["symbols"] == ["aoss.tower.air_temp", "mendota.buoy.air_temp"]
self.assertEqual(len(res["results"]["timestamps"]), 9) assert len(res["results"]["timestamps"]) == 9
self.assertEqual(len(res["results"]["data"]), 9) assert len(res["results"]["data"]) == 9
self.assertEqual(len(res["results"]["data"][0]), 2) assert len(res["results"]["data"][0]) == 2
@mock.patch("metobsapi.data_api.query") @mock.patch("metobsapi.data_api.query")
def test_one_symbol_three_insts_json_row(self, query_func): def test_one_symbol_three_insts_json_row(self, query_func, client):
r = fake_data( r = fake_data(
"1m", "1m",
{ {
...@@ -207,89 +214,87 @@ class TestDataAPI(unittest.TestCase): ...@@ -207,89 +214,87 @@ class TestDataAPI(unittest.TestCase):
st[("site2", "inst2")] = st[("aoss", "tower")] st[("site2", "inst2")] = st[("aoss", "tower")]
st[("site3", "inst3")] = st[("aoss", "tower")] st[("site3", "inst3")] = st[("aoss", "tower")]
with mock.patch("metobsapi.util.data_responses.SYMBOL_TRANSLATIONS", st): with mock.patch("metobsapi.util.data_responses.SYMBOL_TRANSLATIONS", st):
res = self.app.get( res = client.get(
"/api/data.json?symbols=site1.inst1.air_temp:site2.inst2.air_temp:site3.inst3.air_temp&begin=-00:10:00" "/api/data.json?symbols=site1.inst1.air_temp:site2.inst2.air_temp:site3.inst3.air_temp&begin=-00:10:00"
) )
res = json.loads(res.data.decode()) res = json.loads(res.data.decode())
self.assertEqual(res["code"], 200) assert res["code"] == 200
self.assertEqual(res["num_results"], 9) assert res["num_results"] == 9
self.assertListEqual( assert res["results"]["symbols"] == ["site1.inst1.air_temp", "site2.inst2.air_temp", "site3.inst3.air_temp"]
res["results"]["symbols"], ["site1.inst1.air_temp", "site2.inst2.air_temp", "site3.inst3.air_temp"] assert len(res["results"]["timestamps"]) == 9
) assert len(res["results"]["data"]) == 9
self.assertEqual(len(res["results"]["timestamps"]), 9) assert len(res["results"]["data"][0]) == 3
self.assertEqual(len(res["results"]["data"]), 9)
self.assertEqual(len(res["results"]["data"][0]), 3)
@mock.patch("metobsapi.data_api.query") @mock.patch("metobsapi.data_api.query")
def test_one_symbol_csv(self, query_func): def test_one_symbol_csv(self, query_func, client):
r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp"]}, 9) r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp"]}, 9)
query_func.return_value = r query_func.return_value = r
# row should be the default # row should be the default
res = self.app.get("/api/data.csv?symbols=aoss.tower.air_temp&begin=-00:10:00") res = client.get("/api/data.csv?symbols=aoss.tower.air_temp&begin=-00:10:00")
res = res.data.decode() res = res.data.decode()
# header, data, newline at end # header, data, newline at end
lines = res.split("\n") lines = res.split("\n")
self.assertEqual(len(lines), 5 + 9 + 1) assert len(lines) == 5 + 9 + 1
# time + 1 channel # time + 1 channel
self.assertEqual(len(lines[5].split(",")), 2) assert len(lines[5].split(",")) == 2
self.assertIn("# code: 200", res) assert "# code: 200" in res
@mock.patch("metobsapi.data_api.query") @mock.patch("metobsapi.data_api.query")
def test_one_symbol_xml(self, query_func): def test_one_symbol_xml(self, query_func, client):
from xml.dom.minidom import parseString from xml.dom.minidom import parseString
r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp"]}, 9) r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp"]}, 9)
query_func.return_value = r query_func.return_value = r
# row should be the default # row should be the default
res = self.app.get("/api/data.xml?symbols=aoss.tower.air_temp&begin=-00:10:00") res = client.get("/api/data.xml?symbols=aoss.tower.air_temp&begin=-00:10:00")
res = parseString(res.data.decode()) res = parseString(res.data.decode())
# symbols: time and air_temp # symbols: time and air_temp
self.assertEqual(len(res.childNodes[0].childNodes[0].childNodes), 2) assert len(res.childNodes[0].childNodes[0].childNodes) == 2
# data rows # data rows
self.assertEqual(len(res.childNodes[0].childNodes[1].childNodes), 9) assert len(res.childNodes[0].childNodes[1].childNodes) == 9
@mock.patch("metobsapi.data_api.query") @mock.patch("metobsapi.data_api.query")
def test_three_symbol_csv(self, query_func): def test_three_symbol_csv(self, query_func, client):
"""Test that multiple channels in a CSV file are structured properly.""" """Test that multiple channels in a CSV file are structured properly."""
r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp", "rel_hum", "wind_speed"]}, 9) r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp", "rel_hum", "wind_speed"]}, 9)
query_func.return_value = r query_func.return_value = r
# row should be the default # row should be the default
res = self.app.get( res = client.get(
"/api/data.csv?symbols=aoss.tower.air_temp:" "aoss.tower.rel_hum:aoss.tower.wind_speed&begin=-00:10:00" "/api/data.csv?symbols=aoss.tower.air_temp:" "aoss.tower.rel_hum:aoss.tower.wind_speed&begin=-00:10:00"
) )
res = res.data.decode() res = res.data.decode()
# header, data, newline at end # header, data, newline at end
lines = res.split("\n") lines = res.split("\n")
self.assertEqual(len(lines), 5 + 9 + 1) assert len(lines) == 5 + 9 + 1
# time + 3 channels # time + 3 channels
self.assertEqual(len(lines[5].split(",")), 4) assert len(lines[5].split(",")) == 4
self.assertIn("# code: 200", res) assert "# code: 200" in res
@mock.patch("metobsapi.data_api.query") @mock.patch("metobsapi.data_api.query")
def test_three_symbol_csv_repeat(self, query_func): def test_three_symbol_csv_repeat(self, query_func, client):
"""Test that multiple channels in a CSV file are structured properly.""" """Test that multiple channels in a CSV file are structured properly."""
r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp", "rel_hum", "wind_speed"]}, 9) r = fake_data("1m", {("aoss", "tower"): ["time", "air_temp", "rel_hum", "wind_speed"]}, 9)
query_func.return_value = r query_func.return_value = r
# row should be the default # row should be the default
res = self.app.get( res = client.get(
"/api/data.csv?symbols=aoss.tower.air_temp:" "aoss.tower.air_temp:aoss.tower.air_temp&begin=-00:10:00" "/api/data.csv?symbols=aoss.tower.air_temp:" "aoss.tower.air_temp:aoss.tower.air_temp&begin=-00:10:00"
) )
res = res.data.decode() res = res.data.decode()
# header, data, newline at end # header, data, newline at end
lines = res.split("\n") lines = res.split("\n")
# header, data (one empty line), newline at end # header, data (one empty line), newline at end
self.assertEqual(len(lines), 5 + 1 + 1) assert len(lines) == 5 + 1 + 1
# time + 1 channel # time + 1 channel
self.assertEqual(len(lines[5].split(",")), 1) assert len(lines[5].split(",")) == 1
self.assertIn("# code: 400", res) assert "# code: 400" in res
# @mock.patch('metobsapi.data_api.query') # @mock.patch('metobsapi.data_api.query')
# def test_jsonp_bad_symbol_400(self, query_func): # def test_jsonp_bad_symbol_400(self, query_func, client):
# XXX: Not currently possible with flask-json # XXX: Not currently possible with flask-json
# r = fake_data('1m', {('aoss', 'tower'): ['time', 'air_temp']}, 9) # r = fake_data('1m', {('aoss', 'tower'): ['time', 'air_temp']}, 9)
# query_func.return_value = r # query_func.return_value = r
# # row should be the default # # row should be the default
# res = self.app.get('/api/data.json?site=aoss&inst=tower&symbols=bad&begin=-00:10:00&callback=test') # res = client.get('/api/data.json?site=aoss&inst=tower&symbols=bad&begin=-00:10:00&callback=test')
# self.assertEqual(res.status_code, 400) # assert res.status_code == 400
# res = res.data.decode() # res = res.data.decode()
# self.assertEqual(res['code'], 400) # assert res['code'] == 400
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment