Add table "channels" + move some of the db functionas to module db.py
This commit is contained in:
parent
f4d704efa0
commit
0c0d8992b1
3 changed files with 631 additions and 207 deletions
93
srv/db.py
Normal file
93
srv/db.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import os
|
||||
from typing import List
|
||||
|
||||
from databases import Database
|
||||
from sqlalchemy import (Column, DateTime, Integer, Float, String,
|
||||
MetaData, Table, UniqueConstraint, create_engine)
|
||||
|
||||
import sqlalchemy
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
class EnergyDB():
|
||||
def __init__(self, db_url : str):
|
||||
self._engine = create_engine(db_url, connect_args={"check_same_thread": False})
|
||||
|
||||
# self.database = Database(db_url)
|
||||
self._conn = self._engine.connect()
|
||||
|
||||
self._metadata = MetaData(self._engine)
|
||||
self._tables = {
|
||||
"energy": Table(
|
||||
"energy", self._metadata,
|
||||
Column("timestamp", DateTime, primary_key=True),
|
||||
Column("channel_id", Integer(), nullable=False),
|
||||
Column("value", Float),
|
||||
UniqueConstraint("timestamp"),
|
||||
),
|
||||
"channels": Table(
|
||||
"channels", self._metadata,
|
||||
# Column("id", Integer(), autoincrement = True),
|
||||
Column("id", Integer()), #, primary_key = True),
|
||||
Column("name", String(), primary_key = True),
|
||||
),
|
||||
}
|
||||
self._metadata.create_all(self._engine)
|
||||
|
||||
def metadata(self):
|
||||
return self._metadata
|
||||
|
||||
def url(self):
|
||||
return self._engine.url
|
||||
|
||||
def engine(self):
|
||||
return self._engine
|
||||
|
||||
def table(self, name : str) -> sqlalchemy.Table:
|
||||
return self._tables[name]
|
||||
|
||||
def execute(self, cmd, values = None, **args):
|
||||
if values is None:
|
||||
return self._conn.execute(cmd, args)
|
||||
else:
|
||||
return self._conn.execute(cmd, values, args)
|
||||
return self._conn.execute(cmd, args)
|
||||
|
||||
def addChannels(self, channelNames: List[str]):
|
||||
result = []
|
||||
try:
|
||||
# query = self.table("channels").insert()
|
||||
query = sqlalchemy.sql.text("INSERT INTO channels (name) VALUES(:name)")
|
||||
# nameDicts = [ {"name": name } for name in channelNames]
|
||||
# result = self.execute(query, name=channelNames)
|
||||
for n in channelNames:
|
||||
result.append({"n": n})
|
||||
self.execute(query, name=n)
|
||||
except Exception as e:
|
||||
raise Exception(f"Database error in addChannels(): {type(e)} - {str(e)}")
|
||||
return {
|
||||
"query": str(query),
|
||||
"result": result,
|
||||
# "result": [str(r) for r in result.fetchall()]
|
||||
}
|
||||
|
||||
def getChannels(self) -> dict:
|
||||
try:
|
||||
table_channels = self.table("channels")
|
||||
query = sqlalchemy.select([table_channels.c.name, table_channels.c.id]).select_from(table_channels)
|
||||
channels = [dict(r.items()) for r in self.execute(query).fetchall()]
|
||||
except Exception as e:
|
||||
raise Exception(f"Database error in getChannels(): {type(e)} - {str(e)}")
|
||||
return {
|
||||
"channels": channels,
|
||||
"query": str(query),
|
||||
}
|
||||
|
||||
def getChannelId(self, channelName : str) -> int:
|
||||
try:
|
||||
query = sqlalchemy.sql.text(f"SELECT _ROWID_, name FROM channels WHERE name == :name")
|
||||
chId = self.execute(query, name=channelName).scalar()
|
||||
except Exception as e:
|
||||
raise Exception(f"Database error in getChannelId(): {type(e)} - {str(e)}")
|
||||
if chId is None:
|
||||
raise Exception(f"Database error in getChannelId(): channel '{channelName}' not found")
|
||||
return chId
|
||||
334
srv/energyDB.py
334
srv/energyDB.py
|
|
@ -1,42 +1,36 @@
|
|||
from typing import Optional, List
|
||||
from typing import Optional, List, Dict
|
||||
from fastapi import FastAPI, Header, HTTPException
|
||||
from pydantic import BaseModel
|
||||
import datetime
|
||||
import databases
|
||||
import os
|
||||
import sqlalchemy
|
||||
from sqlite3 import OperationalError
|
||||
|
||||
# import sqlalchemy
|
||||
|
||||
from .db import EnergyDB
|
||||
|
||||
import logging
|
||||
|
||||
API_VERSION_MAJOR = 1
|
||||
API_VERSION_MINOR = 0
|
||||
|
||||
REST_API_ROOT = f"/energy/v{API_VERSION_MAJOR}/"
|
||||
DB_URL = os.getenv("DATABASE_URL") #, default="sqlite://")
|
||||
if len(DB_URL) == 0:
|
||||
raise Exception("Environment variable DATABASE_URL missed!")
|
||||
print(f"DB URL: {DB_URL}")
|
||||
db = EnergyDB(DB_URL)
|
||||
|
||||
metadata = sqlalchemy.MetaData()
|
||||
energy = sqlalchemy.Table(
|
||||
"energy",
|
||||
metadata,
|
||||
sqlalchemy.Column("timestamp", sqlalchemy.DateTime, primary_key=True),
|
||||
sqlalchemy.Column("channel_id", sqlalchemy.Integer(), nullable=False),
|
||||
sqlalchemy.Column("value", sqlalchemy.Float),
|
||||
sqlalchemy.UniqueConstraint("timestamp"),
|
||||
)
|
||||
app = FastAPI(debug=True)
|
||||
|
||||
# DATABASE_URL = "sqlite:///./energyDB.sqlite"
|
||||
DATABASE_URL = os.getenv("DATABASE_URL", default="sqlite://")
|
||||
print(f"DB URL: {DATABASE_URL}")
|
||||
db = databases.Database(DATABASE_URL)
|
||||
engine = sqlalchemy.create_engine(
|
||||
DATABASE_URL,
|
||||
connect_args={"check_same_thread": False})
|
||||
metadata.create_all(engine)
|
||||
class InfoData(BaseModel):
|
||||
info: Dict
|
||||
|
||||
class EnergyValue(BaseModel):
|
||||
timestamp: datetime.datetime
|
||||
value: float
|
||||
|
||||
class ChannelData(BaseModel):
|
||||
channel_id: int
|
||||
channel_id: Optional[int]
|
||||
channel: Optional[str]
|
||||
data: List[EnergyValue]
|
||||
msg: Optional[str]
|
||||
|
||||
|
|
@ -49,80 +43,246 @@ class BulkDataRequest(BaseModel):
|
|||
fromTime: datetime.datetime
|
||||
tillTime: datetime.datetime = datetime.datetime.now()
|
||||
|
||||
app = FastAPI(debug=True)
|
||||
class ChannelInfo(BaseModel):
|
||||
name: str
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup():
|
||||
"""On startup connect to the database"""
|
||||
await db.connect()
|
||||
class Channels(BaseModel):
|
||||
channels: List[ChannelInfo]
|
||||
|
||||
@app.on_event("shutdown")
|
||||
async def shutdown():
|
||||
"""On shutdow diconnect from the database"""
|
||||
await db.disconnect()
|
||||
def _restApiPath(subPath : str) -> str:
|
||||
"""Return the full REST API path
|
||||
|
||||
# def _raiseHttpExceptionOnWrongToken(token : str):
|
||||
# if token != fake_secret_token:
|
||||
# raise HTTPException(status_code=400, detail="Invalid X-Token header")
|
||||
Arguments:
|
||||
subPath {str} -- The sub-URL
|
||||
|
||||
@app.put(REST_API_ROOT + "bulkData")
|
||||
async def putBulkEnergyData(bulkData: BulkData):
|
||||
valuesToInsert = []
|
||||
for channelData in bulkData.bulk:
|
||||
for measurement in channelData.data:
|
||||
valuesToInsert.append({
|
||||
"channel_id": channelData.channel_id,
|
||||
"timestamp": measurement.timestamp,
|
||||
"value": measurement.value})
|
||||
query = energy.insert().values(valuesToInsert)
|
||||
result = await db.execute(query)
|
||||
Returns:
|
||||
str -- The full REST API URL
|
||||
"""
|
||||
REST_API_ROOT = f"/energy/v{API_VERSION_MAJOR}"
|
||||
if (subPath.startswith("/")):
|
||||
return REST_API_ROOT + subPath
|
||||
else:
|
||||
return REST_API_ROOT + "/" + subPath
|
||||
|
||||
@app.get(_restApiPath("/version"))
|
||||
async def restApiGetVersion() -> dict:
|
||||
"""Return the version information
|
||||
|
||||
Returns:
|
||||
dict -- The version information of energyDB and SQLAlchemy
|
||||
"""
|
||||
return {
|
||||
"valuesToInsert": valuesToInsert
|
||||
"version": f"{API_VERSION_MAJOR}.{API_VERSION_MINOR}",
|
||||
}
|
||||
|
||||
@app.get(REST_API_ROOT + "bulkData", response_model = BulkData)
|
||||
@app.get(_restApiPath("/info"), response_model = InfoData)
|
||||
async def apiGetInfo():
|
||||
info = {}
|
||||
info["db_url"] = db.url()
|
||||
|
||||
e = sqlalchemy.Table("energy", db.metadata(), autoload=True, autoload_with=db.engine())
|
||||
info["db_fields"] = [c.name for c in e.columns]
|
||||
|
||||
result = db.execute("select * from energy")
|
||||
info["db_dir"] = str(dir(db))
|
||||
info["result_type"] = str(type(result))
|
||||
info["result_dir"] = str(dir(result))
|
||||
info["result_count"] = str(result.rowcount)
|
||||
info["db_contents"] = [str(row) for row in result.fetchall()]
|
||||
result = db.execute("SELECT name FROM sqlite_master WHERE type='table'")
|
||||
info["tables"] = [str(row) for row in result.fetchall()]
|
||||
result = db.execute("SELECT sql FROM sqlite_master WHERE type='table'")
|
||||
info["energy.sql"] = str(result.fetchone()[0]).replace("\n", "").replace("\t","")
|
||||
result = db.execute("SELECT COUNT(*) FROM energy")
|
||||
info["rows"] = str(result.fetchone())
|
||||
# info["rows"] = [str(row) for row in result.fetchall()]
|
||||
|
||||
info["tables"] = [t.name for t in db.metadata().sorted_tables]
|
||||
for t in db.metadata().sorted_tables:
|
||||
# info[f"columns_{t}"] = str(dir(t))
|
||||
info[f"columns_{t}"] = t.schema
|
||||
|
||||
return {
|
||||
"info": info
|
||||
}
|
||||
|
||||
@app.get(_restApiPath("/bulkData"), response_model = BulkData)
|
||||
async def getBulkEnergyData(bulkDataRequest: BulkDataRequest):
|
||||
bulkData = []
|
||||
for ch in bulkDataRequest.channel_ids:
|
||||
query = sqlalchemy.select([energy.c.timestamp, energy.c.value]) \
|
||||
.where(energy.c.channel_id == ch) \
|
||||
.where(energy.c.timestamp >= bulkDataRequest.fromTime) \
|
||||
.where(energy.c.timestamp <= bulkDataRequest.tillTime)
|
||||
try:
|
||||
data = await db.fetch_all(query)
|
||||
trace = []
|
||||
exception = None
|
||||
try:
|
||||
for ch in bulkDataRequest.channel_ids:
|
||||
data = []
|
||||
table_energy = db.table("energy")
|
||||
query = sqlalchemy.select([table_energy.c.timestamp, table_energy.c.value]) \
|
||||
.select_from(table_energy) \
|
||||
.where(sqlalchemy.sql.and_(
|
||||
table_energy.c.channel_id == ch,
|
||||
table_energy.c.timestamp >= bulkDataRequest.fromTime,
|
||||
table_energy.c.timestamp <= bulkDataRequest.tillTime
|
||||
)
|
||||
)
|
||||
for row in db.execute(query).fetchall():
|
||||
data.append(dict(row.items()))
|
||||
bulkData.append({"channel_id": ch, "data": data})
|
||||
except OperationalError as e:
|
||||
raise HTTPException(status_code=500, detail="Database error")
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail=f"Database error: {type(e)} - {str(e)}"
|
||||
# detail=f"Database error: {str(e)}\nQuery: {str(query)}"
|
||||
)
|
||||
return {
|
||||
"bulk": bulkData,
|
||||
"msg": __name__ + " - " +str(query.compile())
|
||||
}
|
||||
|
||||
|
||||
@app.get("/energy/{channel_id}", response_model = ChannelData)
|
||||
async def getChannelData(channel_id: int):
|
||||
try:
|
||||
query = sqlalchemy.select([energy.c.timestamp, energy.c.value]).where(energy.c.channel_id == channel_id)
|
||||
result = await db.fetch_all(query)
|
||||
return {
|
||||
"channel_id": channel_id,
|
||||
"data": result
|
||||
}
|
||||
except Exception as ex:
|
||||
raise HTTPException(status_code=500, detail=f"Internal error: {type(ex)} - \"{ex}\"")
|
||||
|
||||
@app.put("/energy/{channel_id}") #, response_model = EnergyValue)
|
||||
async def putChannelData(channel_id: int, data: EnergyValue):
|
||||
query = energy.insert().values(
|
||||
timestamp=data.timestamp,
|
||||
channel_id=channel_id,
|
||||
value=data.value)
|
||||
result = await db.execute(query)
|
||||
# # return await db.fetch_all(query)
|
||||
return {
|
||||
"timestamp": datetime.datetime.now(),
|
||||
# "channel" : data.channel,
|
||||
"value": data.value,
|
||||
"msg": str(result)
|
||||
"msg": None #__name__ + " - " + str(query)
|
||||
}
|
||||
|
||||
@app.put(_restApiPath("/bulkData"))
|
||||
async def putBulkEnergyData(bulkData: BulkData):
|
||||
valuesToInsert = []
|
||||
result = "ok"
|
||||
# rows_before = {}
|
||||
# rows_after = {}
|
||||
|
||||
try:
|
||||
# rowCounter = 0
|
||||
# dbResult = db.execute( db.tables["energy"].select() )
|
||||
# for row in dbResult.fetchall():
|
||||
# rows_before[f"row_{rowCounter}"] = str(row)
|
||||
# rowCounter += 1
|
||||
|
||||
for channelData in bulkData.bulk:
|
||||
if channelData.channel_id is None:
|
||||
try:
|
||||
table_channels = db.table("channels")
|
||||
channel_id = db.execute(
|
||||
sqlalchemy.select([table_channels.c.id]) \
|
||||
.select_from(table_channels) \
|
||||
.where(table_channels.c.name == channelData.channel))
|
||||
except:
|
||||
raise HTTPException(
|
||||
status_code = 500,
|
||||
detail = f"Database error: {type(ex)} - \"{ex}\""
|
||||
)
|
||||
for measurement in channelData.data:
|
||||
valuesToInsert.append({
|
||||
"channel_id": channelData.channel_id,
|
||||
"timestamp": measurement.timestamp,
|
||||
"value": measurement.value
|
||||
})
|
||||
db.execute(db.table("energy").insert(), valuesToInsert)
|
||||
|
||||
# rowCounter = 0
|
||||
# dbResult = db.execute( db.tables["energy"].select() )
|
||||
# for row in dbResult.fetchall():
|
||||
# rows_after[f"row_{rowCounter}"] = str(row)
|
||||
# rowCounter += 1
|
||||
except Exception as e:
|
||||
result = f"Exception \"{str(e)}\""
|
||||
return {
|
||||
"result": result,
|
||||
# "rows_before": rows_before,
|
||||
# "rows_after": rows_after,
|
||||
}
|
||||
|
||||
@app.put(_restApiPath("/channels"))
|
||||
async def putChannels(channel_info: Channels):
|
||||
result = "ok"
|
||||
query = "???"
|
||||
rows_before = {}
|
||||
rows_after = {}
|
||||
|
||||
try:
|
||||
r = db.getChannels()
|
||||
rows_before = r["channels"]
|
||||
|
||||
channelNames = [c.name for c in channel_info.channels]
|
||||
res = db.addChannels(channelNames)
|
||||
result = res["result"]
|
||||
query = res["query"]
|
||||
|
||||
r = db.getChannels()
|
||||
rows_after = r["channels"]
|
||||
except Exception as e:
|
||||
result = f"Exception \"{str(e)}\""
|
||||
return {
|
||||
"result": result,
|
||||
"channels": str(channel_info.channels),
|
||||
"channelNames": channelNames,
|
||||
"query": query,
|
||||
"rows_before": rows_before,
|
||||
"rows_after": rows_after,
|
||||
}
|
||||
|
||||
@app.get(_restApiPath("/channels"))
|
||||
async def getChannels() -> dict:
|
||||
"""Return a list of all channels
|
||||
|
||||
Raises:
|
||||
HTTPException: with status 500 on a database error
|
||||
|
||||
Returns:
|
||||
dict -- the list of all channels
|
||||
"""
|
||||
try:
|
||||
result = db.getChannels()
|
||||
return {"channels": [ch["name"] for ch in result["channels"]]}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code = 500, detail = str(e))
|
||||
|
||||
@app.get(_restApiPath("/channels/{channel}/id"))
|
||||
async def getChannelId(channel: str): # -> dict:
|
||||
try:
|
||||
chId = db.getChannelId(channel)
|
||||
return {
|
||||
"channel": channel,
|
||||
"id": chId,
|
||||
# "query": str(r["query"])
|
||||
}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500,detail=f"Database error: {type(e)} - {str(e)}")
|
||||
|
||||
|
||||
# @app.get("/energy/{channel_id}", response_model = ChannelData)
|
||||
# async def getChannelData(channel_id: int):
|
||||
# try:
|
||||
# query = sqlalchemy.select([energy.c.timestamp, energy.c.value]).where(energy.c.channel_id == channel_id)
|
||||
# result = await db.fetch_all(query)
|
||||
# return {
|
||||
# "channel_id": channel_id,
|
||||
# "data": result
|
||||
# }
|
||||
# except Exception as ex:
|
||||
# raise HTTPException(status_code=500, detail=f"Internal error: {type(ex)} - \"{ex}\"")
|
||||
|
||||
# @app.put("/energy/{channel_id}") #, response_model = EnergyValue)
|
||||
# async def putChannelData(channel_id: int, data: EnergyValue):
|
||||
# query = energy.insert().values(
|
||||
# timestamp=data.timestamp,
|
||||
# channel_id=channel_id,
|
||||
# value=data.value)
|
||||
# result = await db.execute(query)
|
||||
# # # return await db.fetch_all(query)
|
||||
# return {
|
||||
# "timestamp": datetime.datetime.now(),
|
||||
# # "channel" : data.channel,
|
||||
# "value": data.value,
|
||||
# "msg": str(result)
|
||||
# }
|
||||
|
||||
@app.get(_restApiPath("/{channel_id}/count")) # response_model = ChannelData)
|
||||
async def getChannelRowCount(channel_id: int):
|
||||
info = {}
|
||||
|
||||
info["columns"] = str( db.table("energy").columns)
|
||||
|
||||
# countQuery = sqlalchemy.select([sqlalchemy.func.count()]).select_from(db.tables["energy"])
|
||||
# info["stmt"] = str(countQuery)
|
||||
# countResult = db.execute( countQuery )
|
||||
# info["count"] = countResult.fetchone()[0]
|
||||
|
||||
# info["tables"] = [t.name for t in metadata.sorted_tables]
|
||||
# for t in metadata.tables:
|
||||
# info[f"columns_{t}"] = str(type(t))
|
||||
# # info[f"columns_{t}"] = list(sqlalchemy.inspect(t).columns)
|
||||
return { "info": info }
|
||||
|
|
|
|||
|
|
@ -9,143 +9,314 @@ import urllib.parse
|
|||
#TODO Use in-memory DB to test the case that there is no table
|
||||
#TODO Add helper function to fill the in-memory DB before test
|
||||
|
||||
os.environ["DATABASE_URL"] = "sqlite:///./energyDB.sqlite"
|
||||
# os.environ["DATABASE_URL"] = "sqlite:///./testDB.sqlite"
|
||||
os.environ["DATABASE_URL"] = "sqlite://"
|
||||
|
||||
from srv import energyDB
|
||||
|
||||
class Test_energyDb:
|
||||
restApiRoot = "/energy/v1/"
|
||||
bulkTestData = [
|
||||
{
|
||||
"channel_id": 1,
|
||||
"data": (
|
||||
{ "timestamp": "2020-12-11T12:00:22", "value": 1100.1 },
|
||||
{ "timestamp": "2020-12-11T12:10:15", "value": 1109.2 },
|
||||
{ "timestamp": "2020-12-11T12:20:13", "value": 1119.3 },
|
||||
{ "timestamp": "2020-12-11T12:30:21", "value": 1131.4 },
|
||||
{ "timestamp": "2020-12-11T12:40:08", "value": 1143.5 },
|
||||
{ "timestamp": "2020-12-11T12:50:13", "value": 1152.6 },
|
||||
{ "timestamp": "2020-12-11T13:00:11", "value": 1160.7 },
|
||||
{ "timestamp": "2020-12-11T13:10:09", "value": 1169.8 },
|
||||
{ "timestamp": "2020-12-11T13:20:10", "value": 1181.9 },
|
||||
{ "timestamp": "2020-12-11T13:30:17", "value": 1190.0 },
|
||||
)
|
||||
},
|
||||
{
|
||||
"channel_id": 2,
|
||||
"data": [
|
||||
{ "timestamp": "2020-12-11T12:01:15", "value": 1200.1 },
|
||||
{ "timestamp": "2020-12-11T12:21:28", "value": 1219.2 },
|
||||
{ "timestamp": "2020-12-11T12:41:21", "value": 1243.3 },
|
||||
{ "timestamp": "2020-12-11T13:01:16", "value": 1260.4 },
|
||||
{ "timestamp": "2020-12-11T13:21:18", "value": 1281.5 },
|
||||
]
|
||||
}
|
||||
]
|
||||
class Test_energyDB:
|
||||
restApiRoot = "/energy/v1"
|
||||
testData = {
|
||||
"channels": (
|
||||
{"name": "dc_power1"},
|
||||
{"name": "daily_yield"},
|
||||
{"name": "total_yield"},
|
||||
),
|
||||
"bulkdata": (
|
||||
{
|
||||
"channel_id": 1,
|
||||
"data": (
|
||||
{ "timestamp": "2020-12-11T12:00:22", "value": 1100.1 },
|
||||
{ "timestamp": "2020-12-11T12:10:15", "value": 1109.2 },
|
||||
{ "timestamp": "2020-12-11T12:20:13", "value": 1119.3 },
|
||||
{ "timestamp": "2020-12-11T12:30:21", "value": 1131.4 },
|
||||
{ "timestamp": "2020-12-11T12:40:08", "value": 1143.5 },
|
||||
{ "timestamp": "2020-12-11T12:50:13", "value": 1152.6 },
|
||||
{ "timestamp": "2020-12-11T13:00:11", "value": 1160.7 },
|
||||
{ "timestamp": "2020-12-11T13:10:09", "value": 1169.8 },
|
||||
{ "timestamp": "2020-12-11T13:20:10", "value": 1181.9 },
|
||||
{ "timestamp": "2020-12-11T13:30:17", "value": 1190.0 },
|
||||
)
|
||||
},
|
||||
{
|
||||
"channel_id": 2,
|
||||
"data": [
|
||||
{ "timestamp": "2020-12-11T12:01:15", "value": 1200.1 },
|
||||
{ "timestamp": "2020-12-11T12:21:28", "value": 1219.2 },
|
||||
{ "timestamp": "2020-12-11T12:41:21", "value": 1243.3 },
|
||||
{ "timestamp": "2020-12-11T13:01:16", "value": 1260.4 },
|
||||
{ "timestamp": "2020-12-11T13:21:18", "value": 1281.5 },
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
client = TestClient(energyDB)
|
||||
# client = TestClient(energyDB)
|
||||
|
||||
# def setup(self):
|
||||
# self.client = TestClient(energyDB)
|
||||
def setup(self):
|
||||
self.client = TestClient(energyDB)
|
||||
|
||||
# def teardown(self):
|
||||
# self.client = None
|
||||
def teardown(self):
|
||||
self.client = None
|
||||
|
||||
def _test_bulkData_put(self):
|
||||
# response = self.client.put("/energy/bulkData", json=self.bulkTestData);
|
||||
# --- helper functions
|
||||
|
||||
def _apiUrl(self, sub_url : str):
|
||||
if sub_url.startswith("/"):
|
||||
return self.restApiRoot + sub_url
|
||||
else:
|
||||
return self.restApiRoot + "/" + sub_url
|
||||
|
||||
def _fillDatabase(self):
|
||||
response = self.client.put(
|
||||
self.restApiRoot + "bulkData",
|
||||
json={"bulk": self.bulkTestData})
|
||||
# print(f"dir(response): {dir(response)}")
|
||||
# print(f"dir(response.request): {dir(response.request)}")
|
||||
# print("---- request")
|
||||
# print(f"response.request.method: {response.request.method}")
|
||||
# print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# print(f"response.request.headers: {response.request.headers}")
|
||||
# requestJson = json.loads(response.request.body)
|
||||
# print(f"response.request.body: {json.dumps(requestJson, indent=2)}")
|
||||
print("---- response")
|
||||
print(f"response.reason: {response.reason}")
|
||||
responseJson = json.loads(response.text)
|
||||
print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
# print(f"response.text: {json.dumps(response.text, indent=2)}")
|
||||
self._apiUrl("/channels"),
|
||||
json = {"channels": self.testData["channels"]}
|
||||
)
|
||||
# self._dumpRequestAndResponse("_fillDatabase(channels)", response)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_bulkData_get(self):
|
||||
print(f"DB_URL: {os.getenv('DATABASE_URL')}")
|
||||
# response = self.client.put("/energy/bulkData", json=self.bulkTestData);
|
||||
fromTimestamp = datetime.fromisoformat("2020-12-11T12:30:00")
|
||||
tillTimestamp = datetime.fromisoformat("2020-12-11T12:30:59")
|
||||
response = self.client.get(
|
||||
self.restApiRoot + "bulkData",
|
||||
json = {
|
||||
"channel_ids": [1, 2, 3],
|
||||
"fromTime": fromTimestamp.isoformat(),
|
||||
# "tillTime": tillTimestamp.isoformat()
|
||||
})
|
||||
# print(f"dir(response): {dir(response)}")
|
||||
# print(f"dir(response.request): {dir(response.request)}")
|
||||
print("---- request")
|
||||
response = self.client.put(
|
||||
self._apiUrl("/bulkData"),
|
||||
json = {"bulk": self.testData["bulkdata"]}
|
||||
)
|
||||
# self._dumpRequestAndResponse("_fillDatabase(data)", response)
|
||||
assert response.status_code == 200
|
||||
|
||||
def _dumpRequestAndResponse(self, context : str, response):
|
||||
print("\n")
|
||||
print(f"---- request ({context})")
|
||||
print(f"response.request.method: {response.request.method}")
|
||||
print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
print(f"response.request.headers: {response.request.headers}")
|
||||
print(f"dir(response.request): {dir(response.request)}")
|
||||
print(f"response.request.body: {response.request.body}")
|
||||
# requestJson = json.loads(response.request.body)
|
||||
# print(f"response.request.body: {json.dumps(requestJson, indent=2)}")
|
||||
print("---- response")
|
||||
try:
|
||||
requestJson = json.loads(response.request.body)
|
||||
print(f"response.request.body(json): {json.dumps(requestJson, indent=2)}")
|
||||
except:
|
||||
print(f"response.request.body(plain): {response.request.body}")
|
||||
print(f"---- response ({context})")
|
||||
print(f"response.status_code: {response.status_code}")
|
||||
print(f"response.reason: {response.reason}")
|
||||
responseJson = json.loads(response.text)
|
||||
print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
# print(f"response.text: {json.dumps(response.text, indent=2)}")
|
||||
try:
|
||||
responseJson = json.loads(response.text)
|
||||
print(f"response.text(json): {json.dumps(responseJson, indent=2)}")
|
||||
except:
|
||||
print(f"response.text(plain): {response.text}")
|
||||
|
||||
# --- test functions
|
||||
|
||||
def test_invalidRoute(self):
|
||||
response = self.client.get("/")
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_getVersion(self):
|
||||
response = self.client.get(self._apiUrl("/version"))
|
||||
# self._dumpRequestAndResponse("test_getVersion", response)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["version"] == "1.0"
|
||||
|
||||
def _test_getInfo(self):
|
||||
response = self.client.get( self._apiUrl("/info" ))
|
||||
# self._dumpRequestAndResponse("test_getInfo", response)
|
||||
assert response.status_code == 200
|
||||
|
||||
@pytest.mark.skip(reason="Ignore me temporarily")
|
||||
def test_insert_energy(self):
|
||||
energyData = {
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"value": 234.5,
|
||||
}
|
||||
print(f"energyData: {energyData}")
|
||||
# response = self.client.put("/energies/1", json=energyData) #, headers={"X-Token": "coneofsilence"})
|
||||
def _test_getChannelsOfEmptyTable(self):
|
||||
response = self.client.get(self._apiUrl("/channels"))
|
||||
# self._dumpRequestAndResponse("test_getChannelsOfEmptyTable", response)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["channels"] == []
|
||||
|
||||
def _test_getBulkDataOfEmptyTable(self):
|
||||
response = self.client.get(
|
||||
self._apiUrl("/bulkData"),
|
||||
json = {
|
||||
"channel_ids": [1],
|
||||
"fromTime": "0001-01-01T00:00:00"
|
||||
}
|
||||
)
|
||||
self._dumpRequestAndResponse("test_getBulkDataOfEmptyTable", response)
|
||||
assert response.status_code == 200
|
||||
assert "bulk" in response.json()
|
||||
assert response.json()["bulk"] == [
|
||||
{
|
||||
"channel_id": 1,
|
||||
"channel": None,
|
||||
"data": [],
|
||||
"msg": None
|
||||
}
|
||||
]
|
||||
|
||||
def test_fillDatabase(self):
|
||||
self._fillDatabase()
|
||||
response = self.client.get(self._apiUrl("/1/count"))
|
||||
# self._dumpRequestAndResponse("test_fillDatabase", response)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_getChannels(self):
|
||||
response = self.client.get(self._apiUrl("/channels"))
|
||||
# self._dumpRequestAndResponse("test_getChannels", response)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_getChannelId(self):
|
||||
response = self.client.get(self._apiUrl("/channels/total_yield/id"))
|
||||
# self._dumpRequestAndResponse("test_getChannelId", response)
|
||||
assert response.status_code == 200
|
||||
|
||||
response = self.client.get(self._apiUrl("/channels/dc_power1/id"))
|
||||
# self._dumpRequestAndResponse("test_getChannelId", response)
|
||||
assert response.status_code == 200
|
||||
|
||||
response = self.client.get(self._apiUrl("/channels/daily_yield/id"))
|
||||
# self._dumpRequestAndResponse("test_getChannelId", response)
|
||||
assert response.status_code == 200
|
||||
|
||||
def test_putChannels(self):
|
||||
response = self.client.get(self._apiUrl("/channels/frequency/id"))
|
||||
# self._dumpRequestAndResponse("test_getChannelId", response)
|
||||
assert response.status_code == 500
|
||||
|
||||
response = self.client.put(
|
||||
self.restApiRoot + "2",
|
||||
# params=energyData,
|
||||
json=energyData) #, headers={"X-Token": "coneofsilence"})
|
||||
# print(f"dir(response): {dir(response)}")
|
||||
# print(f"dir(response.request): {dir(response.request)}")
|
||||
# print("---- request")
|
||||
# print(f"response.request.method: {response.request.method}")
|
||||
# print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# print(f"response.request.headers: {response.request.headers}")
|
||||
# print(f"response.request.body: {json.loads(response.request.body)}")
|
||||
# print("---- response")
|
||||
# print(f"response.reason: {response.reason}")
|
||||
# print(f"response.text: {json.loads(response.text)}")
|
||||
# print(f"request.header: \"{response.request.header}\"")
|
||||
# print(f"request.body: \"{response.request.body}\"")
|
||||
self._apiUrl("/channels"),
|
||||
json = {"channels": [{"name": "frequency"}]}
|
||||
)
|
||||
# self._dumpRequestAndResponse("test_fillDatabase", response)
|
||||
assert response.status_code == 200
|
||||
# assert response.json()["msg"] == ""
|
||||
|
||||
@pytest.mark.skip(reason="Ignore me temporarily")
|
||||
def test_get_energy(self):
|
||||
response = self.client.get(self.restApiRoot + "1")
|
||||
# print(f"dir(response): {dir(response)}")
|
||||
# print(f"dir(response.request): {dir(response.request)}")
|
||||
# print("---- request")
|
||||
# print(f"response.request.method: {response.request.method}")
|
||||
# print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# print(f"response.request.headers: {response.request.headers}")
|
||||
# print("---- response")
|
||||
# print(f"response.reason: {response.reason}")
|
||||
responseJson = json.loads(response.text)
|
||||
print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
data = response.json()
|
||||
# print(f"data: {type(data)}")
|
||||
# for k,v in data.items():
|
||||
# print(f"key: {k} -> value: {v}")
|
||||
print(f"data of channel: {data['channel_id']}")
|
||||
for r in data["data"]:
|
||||
print(f"r: {r}")
|
||||
response = self.client.get(self._apiUrl("/channels/frequency/id"))
|
||||
# self._dumpRequestAndResponse("test_getChannelId", response)
|
||||
assert response.status_code == 200
|
||||
# assert response.json()["msg"] == ""
|
||||
|
||||
def _test_putBulkData(self):
|
||||
response = self.client.put(
|
||||
self._apiUrl("/bulkData"),
|
||||
json = {"bulk": {
|
||||
"channel_id": None,
|
||||
"channel": "total_yield",
|
||||
"data": [
|
||||
{ "timestamp": "2020-12-11T12:01:20", "value": 120120.1 },
|
||||
{ "timestamp": "2020-12-11T12:30:25", "value": 123025.2 },
|
||||
]
|
||||
}}
|
||||
)
|
||||
self._dumpRequestAndResponse("test_putBulkData", response)
|
||||
assert response.status_code == 200
|
||||
|
||||
# def test_getRecordCount(self):
|
||||
# response = self.client.get(self._apiUrl("/1/count"))
|
||||
# self._dumpRequestAndResponse("test_getRecordCount", response)
|
||||
# assert response.status_code == 200
|
||||
# assert response.json()["info"] == {"columns"}
|
||||
|
||||
# def _test_bulkData_put(self):
|
||||
# # response = self.client.put("/energy/bulkData", json=self.bulkTestData);
|
||||
# response = self.client.put(
|
||||
# self.restApiRoot + "bulkData",
|
||||
# json={"bulk": self.bulkTestData})
|
||||
# # print(f"dir(response): {dir(response)}")
|
||||
# # print(f"dir(response.request): {dir(response.request)}")
|
||||
# # print("---- request")
|
||||
# # print(f"response.request.method: {response.request.method}")
|
||||
# # print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# # print(f"response.request.headers: {response.request.headers}")
|
||||
# # requestJson = json.loads(response.request.body)
|
||||
# # print(f"response.request.body: {json.dumps(requestJson, indent=2)}")
|
||||
# print("---- response")
|
||||
# print(f"response.reason: {response.reason}")
|
||||
# responseJson = json.loads(response.text)
|
||||
# print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
# # print(f"response.text: {json.dumps(response.text, indent=2)}")
|
||||
# assert response.status_code == 200
|
||||
|
||||
# def _test_getInfo2(self):
|
||||
# response = self.client.get( self.restApiRoot + "info" )
|
||||
# # print(f"dir(response): {dir(response)}")
|
||||
# # print(f"dir(response.request): {dir(response.request)}")
|
||||
# print("---- request")
|
||||
# print(f"response.request.method: {response.request.method}")
|
||||
# print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# print(f"response.request.headers: {response.request.headers}")
|
||||
# # print(f"dir(response.request): {dir(response.request)}")
|
||||
# print("---- response")
|
||||
# print(f"response.reason: {response.reason}")
|
||||
# # print(f"response.text: {response.text}")
|
||||
# responseJson = json.loads(response.text)
|
||||
# print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
# assert False #response.status_code == 404
|
||||
|
||||
# def _test_bulkData_get(self):
|
||||
# print(f"DB_URL: {os.getenv('DATABASE_URL')}")
|
||||
# # response = self.client.put("/energy/bulkData", json=self.bulkTestData);
|
||||
# fromTimestamp = datetime.fromisoformat("2020-12-11T12:30:00")
|
||||
# tillTimestamp = datetime.fromisoformat("2020-12-11T12:30:59")
|
||||
# response = self.client.get(
|
||||
# self.restApiRoot + "bulkData",
|
||||
# json = {
|
||||
# "channel_ids": [1, 2, 3],
|
||||
# "fromTime": fromTimestamp.isoformat(),
|
||||
# # "tillTime": tillTimestamp.isoformat()
|
||||
# })
|
||||
# # print(f"dir(response): {dir(response)}")
|
||||
# # print(f"dir(response.request): {dir(response.request)}")
|
||||
# print("---- request")
|
||||
# print(f"response.request.method: {response.request.method}")
|
||||
# print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# print(f"response.request.headers: {response.request.headers}")
|
||||
# print(f"dir(response.request): {dir(response.request)}")
|
||||
# print(f"response.request.body: {response.request.body}")
|
||||
# # requestJson = json.loads(response.request.body)
|
||||
# # print(f"response.request.body: {json.dumps(requestJson, indent=2)}")
|
||||
# print("---- response")
|
||||
# print(f"response.reason: {response.reason}")
|
||||
# responseJson = json.loads(response.text)
|
||||
# print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
# # print(f"response.text: {json.dumps(response.text, indent=2)}")
|
||||
# assert response.status_code == 200
|
||||
|
||||
# @pytest.mark.skip(reason="Ignore me temporarily")
|
||||
# def test_insert_energy(self):
|
||||
# energyData = {
|
||||
# "timestamp": datetime.now().isoformat(),
|
||||
# "value": 234.5,
|
||||
# }
|
||||
# print(f"energyData: {energyData}")
|
||||
# # response = self.client.put("/energies/1", json=energyData) #, headers={"X-Token": "coneofsilence"})
|
||||
# response = self.client.put(
|
||||
# self.restApiRoot + "2",
|
||||
# # params=energyData,
|
||||
# json=energyData) #, headers={"X-Token": "coneofsilence"})
|
||||
# # print(f"dir(response): {dir(response)}")
|
||||
# # print(f"dir(response.request): {dir(response.request)}")
|
||||
# # print("---- request")
|
||||
# # print(f"response.request.method: {response.request.method}")
|
||||
# # print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# # print(f"response.request.headers: {response.request.headers}")
|
||||
# # print(f"response.request.body: {json.loads(response.request.body)}")
|
||||
# # print("---- response")
|
||||
# # print(f"response.reason: {response.reason}")
|
||||
# # print(f"response.text: {json.loads(response.text)}")
|
||||
# # print(f"request.header: \"{response.request.header}\"")
|
||||
# # print(f"request.body: \"{response.request.body}\"")
|
||||
# assert response.status_code == 200
|
||||
# # assert response.json()["msg"] == ""
|
||||
|
||||
# @pytest.mark.skip(reason="Ignore me temporarily")
|
||||
# def test_get_energy(self):
|
||||
# response = self.client.get(self.restApiRoot + "1")
|
||||
# # print(f"dir(response): {dir(response)}")
|
||||
# # print(f"dir(response.request): {dir(response.request)}")
|
||||
# # print("---- request")
|
||||
# # print(f"response.request.method: {response.request.method}")
|
||||
# # print(f"response.request.url: {urllib.parse.unquote(response.request.url)}")
|
||||
# # print(f"response.request.headers: {response.request.headers}")
|
||||
# # print("---- response")
|
||||
# # print(f"response.reason: {response.reason}")
|
||||
# responseJson = json.loads(response.text)
|
||||
# print(f"response.text: {json.dumps(responseJson, indent=2)}")
|
||||
# data = response.json()
|
||||
# # print(f"data: {type(data)}")
|
||||
# # for k,v in data.items():
|
||||
# # print(f"key: {k} -> value: {v}")
|
||||
# print(f"data of channel: {data['channel_id']}")
|
||||
# for r in data["data"]:
|
||||
# print(f"r: {r}")
|
||||
# assert response.status_code == 200
|
||||
# # assert response.json()["msg"] == ""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue