Skip to content

Commit

Permalink
Merge branch 'develop' into buildstock
Browse files Browse the repository at this point in the history
  • Loading branch information
tanushree04 committed Jan 22, 2024
2 parents 92daa9b + a1ea05b commit 525a428
Show file tree
Hide file tree
Showing 16 changed files with 18,451 additions and 265 deletions.
20 changes: 16 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,15 @@ jobs:
- name: Dump docker logs before tests
uses: jwalton/gh-docker-logs@v1

- name: Run tests with pytest
- name: Install dependencies
run: poetry install

- name: Run API tests with pytest
run: |
poetry run pytest --timeout=120 -m api
- name: Run integration tests with pytest
run: |
poetry install
poetry run pytest --timeout=600 -m "integration"
- name: Run worker scale tests with pytest
Expand Down Expand Up @@ -230,9 +236,15 @@ jobs:
- name: Dump docker logs before tests
uses: jwalton/gh-docker-logs@v1

- name: Run tests with pytest
- name: Install dependencies
run: poetry install

- name: Run API tests with pytest
run: |
poetry run pytest --timeout=120 -m api
- name: Run integration tests with pytest
run: |
poetry install
poetry run pytest --timeout=600 -m "integration"
- name: Run worker scale tests with pytest
Expand Down
15 changes: 11 additions & 4 deletions alfalfa_web/server/api-v2.js
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,14 @@ router.get("/runs/:runId/points/:pointId", (req, res, next) => {
* description: The point was successfully updated
*/
router.put("/runs/:runId/points/:pointId", (req, res, next) => {
// TODO Confirm that point isn't an OUTPUT type
const { value } = req.body;

if (req.point.point_type == "OUTPUT") {
return res
.status(400)
.json({ message: `Point '${req.point.ref_id}' is of type '${req.point.point_type}' and cannot be written to` });
}

if (value !== null) {
const error = validate(
{ value },
Expand Down Expand Up @@ -687,7 +694,7 @@ router.delete("/runs/:runId", (req, res, next) => {
* schema:
* $ref: '#/components/schemas/Error'
*/
router.post("/runs/:runId/start", async (req, res, next) => {
router.post("/runs/:runId/start", (req, res, next) => {
const { body } = req;

const timeValidator = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
Expand Down Expand Up @@ -777,7 +784,7 @@ router.post("/runs/:runId/advance", (req, res, next) => {
*/
router.post("/runs/:runId/stop", (req, res, next) => {
// If the run is already stopping or stopped there is no need to send message
if (["STOPPING", "STOPPED", "COMPLETE"].includes(req.run.status)) {
if (["STOPPING", "COMPLETE", "ERROR", "READY"].includes(req.run.status)) {
res.sendStatus(204);
}
api
Expand Down Expand Up @@ -1220,7 +1227,7 @@ router.get("/simulations", async (req, res, next) => {
.catch(next);
});

router.get("*", (req, res) => res.status(404).json({ message: "Page not found" }));
router.all("*", (req, res) => res.status(404).json({ message: "Page not found" }));

router.use(errorHandler);

Expand Down
9 changes: 5 additions & 4 deletions alfalfa_web/server/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class AlfalfaAPI {
getPointsById = async (run, pointIds) => {
return Promise.all(
pointIds.map((pointId) => {
this.getPointById(run, pointId);
return this.getPointById(run, pointId);
})
);
};
Expand Down Expand Up @@ -173,7 +173,7 @@ class AlfalfaAPI {

removeRun = async (run) => {
// Delete run
const { deletedCount } = await this.run.deleteOne({ _id: run._id });
const { deletedCount } = await this.runs.deleteOne({ _id: run._id });

if (deletedCount == 1) {
// Delete points
Expand Down Expand Up @@ -258,7 +258,8 @@ class AlfalfaAPI {
};

listModels = async () => {
return this.getModels().map(this.formatModel);
const models = await this.getModels();
return models.map(this.formatModel);
};

getModels = async () => {
Expand All @@ -285,7 +286,7 @@ class AlfalfaAPI {
new GetObjectCommand({
Bucket: process.env.S3_BUCKET,
Key: `uploads/${model.ref_id}/${model.model_name}`,
ResponseContentDisposition: `attachment; filename="${run.ref_id}.tar.gz"`
ResponseContentDisposition: `attachment; filename="${model.ref_id}.tar.gz"`
}),
{
expiresIn: 86400
Expand Down
503 changes: 252 additions & 251 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ influxdb = "^5.3.1"
# required for tests to pass right now. There are often issues when pinning to a branch
# and calling poetry update. I have had to completely remove my venv and reinstall in order
# to get the latest updates.
alfalfa-client = { git = "https://github.com/nrel/alfalfa-client.git", branch = "boptest_alignment" }
alfalfa-client = { git = "https://github.com/nrel/alfalfa-client.git", branch = "upload_model_check" }
# alfalfa-client = "~0.5.0"
autopep8 = "~2.0"
pre-commit = "~2.21"
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ extras = True
addopts =
--cov alfalfa_worker --cov-report term-missing
--verbose
-m "not integration and not fmu and not docker and not scale"
-m "not integration and not fmu and not docker and not scale and not api"
markers =
integration: marks tests as integration tests (deselect with '-m "not integration"')
fmu: mark tests that require fmu support, e.g., pyfmi (deselect with '-m "not fmu"')
Expand Down
1 change: 1 addition & 0 deletions tests/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""This module includes tests for the mechanical aspects of the api, but not necessarily all of the functionality."""
37 changes: 37 additions & 0 deletions tests/api/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os
from pathlib import Path

import pytest
from alfalfa_client import AlfalfaClient
from requests import HTTPError


@pytest.fixture
def base_url():
return 'http://localhost/api/v2'


@pytest.fixture
def alfalfa_client():
return AlfalfaClient()


@pytest.fixture
def model_path():
return Path(os.path.dirname(__file__)) / "models" / "small_office"


@pytest.fixture
def model_id(alfalfa_client: AlfalfaClient, model_path):
return alfalfa_client.upload_model(model_path)


@pytest.fixture
def run_id(alfalfa_client: AlfalfaClient, model_path):
run_id = alfalfa_client.submit(model_path)
yield run_id
try:
if alfalfa_client.status(run_id) not in ["COMPLETE", "ERROR", "STOPPING", "READY"]:
alfalfa_client.stop(run_id)
except HTTPError:
pass
92 changes: 92 additions & 0 deletions tests/api/models/small_office/measures/alfalfa_vars/measure.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# insert your copyright here

# see the URL below for information on how to write OpenStudio measures
# http://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/

# start the measure
class AlfalfaVariables < OpenStudio::Measure::ModelMeasure
# human readable name
def name
return 'AlfalfaVariables'
end

# human readable description
def description
return 'Add custom variables for Alfalfa'
end

# human readable description of modeling approach
def modeler_description
return 'Add EMS global variables required by Alfalfa'
end

# define the arguments that the user will input
def arguments(model)
args = OpenStudio::Measure::OSArgumentVector.new
return args
end

def create_input(model, name, freq)
# The purpose of this function is to create an Alfalfa input that is accessible via python plugins

global = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, name)
global.setExportToBCVTB(true)

# The global variable's value must be sent to output an variable so that python programs can read it
# don't be mistaken, An OuputVariable object is created, but this is "input" to the simulation, from Alfalfa clients
global_ems_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, global)
global_ems_output.setName(name + "_EMS_Value")
global_ems_output.setUpdateFrequency("SystemTimestep")

# Request the custom ems output var creaed in the previous step
global_output = OpenStudio::Model::OutputVariable.new(global_ems_output.nameString(), model)
global_output.setName(name + "_Value")
global_output.setReportingFrequency(freq)
global_output.setKeyValue("EMS")
# Setting exportToBCVTB to true is optional, and will result in the output variable showing up in the Alfalfa api,
# this might be useful for confirmation of the input
global_output.setExportToBCVTB(true)

# repeat the previous steps for an "Enable" input
# This value will be 1 (instead of 0) anytime a client writes to the input via the Alfalfa api
global_enable = OpenStudio::Model::EnergyManagementSystemGlobalVariable.new(model, name + "_Enable")
global_enable.setExportToBCVTB(true)

global_enable_ems_output = OpenStudio::Model::EnergyManagementSystemOutputVariable.new(model, global_enable)
global_enable_ems_output.setName(name + "_Enable_EMS_Value")
global_enable_ems_output.setUpdateFrequency("SystemTimestep")

global_enable_output = OpenStudio::Model::OutputVariable.new(global_enable_ems_output.nameString(), model)
global_enable_output.setName(name + "_Enable_Value")
global_enable_output.setReportingFrequency(freq)
global_enable_output.setKeyValue("EMS")
global_enable_output.setExportToBCVTB(true)
end

def create_output(model, var, key, name, freq)
new_var = OpenStudio::Model::OutputVariable.new(var, model)
new_var.setName(name)
new_var.setReportingFrequency(freq)
new_var.setKeyValue(key)
new_var.setExportToBCVTB(true)
end

# define what happens when the measure is run
def run(model, runner, user_arguments)
super(model, runner, user_arguments)

# Alfalfa inputs
# These can be set through the Alfalfa API, they will be available as OutputVariables
# in the simulation. Use them as you will
# Also see comments on the create_input method
create_input(model, "Test_Point_1", "Timestep")

# other OutputVariables might be custom python defined output variables,
# you should still be able to request them here, and as long as exportToBCVTB is true they will be available via Alfalfa

return true
end
end

# register the measure to be used by the application
AlfalfaVariables.new.registerWithApplication
54 changes: 54 additions & 0 deletions tests/api/models/small_office/measures/alfalfa_vars/measure.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0"?>
<measure>
<schema_version>3.0</schema_version>
<name>alfalfa_variables</name>
<uid>86d51823-68a5-478a-b60b-60891c3c9b5f</uid>
<version_id>5c94ef46-d8e9-4ae9-864e-d884aba51509</version_id>
<version_modified>20201216T214230Z</version_modified>
<xml_checksum>356BE47F</xml_checksum>
<class_name>AlfalfaVariables</class_name>
<display_name>AlfalfaVariables</display_name>
<description>Add custom variables for Alfalfa</description>
<modeler_description>Add EMS global variables required by Alfalfa</modeler_description>
<arguments />
<outputs />
<provenances />
<tags>
<tag>HVAC.HVAC Controls</tag>
</tags>
<attributes>
<attribute>
<name>Measure Type</name>
<value>ModelMeasure</value>
<datatype>string</datatype>
</attribute>
<attribute>
<name>Intended Software Tool</name>
<value>Apply Measure Now</value>
<datatype>string</datatype>
</attribute>
<attribute>
<name>Intended Software Tool</name>
<value>OpenStudio Application</value>
<datatype>string</datatype>
</attribute>
<attribute>
<name>Intended Software Tool</name>
<value>Parametric Analysis Tool</value>
<datatype>string</datatype>
</attribute>
</attributes>
<files>
<file>
<version>
<software_program>OpenStudio</software_program>
<identifier>3.1.0</identifier>
<min_compatible>3.1.0</min_compatible>
</version>
<filename>measure.rb</filename>
<filetype>rb</filetype>
<usage_type>script</usage_type>
<checksum>A9E1EEF2</checksum>
</file>
</files>
</measure>
Loading

0 comments on commit 525a428

Please sign in to comment.