559 lines
18 KiB
Python
559 lines
18 KiB
Python
from collections import OrderedDict
|
|
import os
|
|
import unittest
|
|
from unittest.mock import MagicMock
|
|
from nose.tools import eq_
|
|
from helix.constants.anchor_type import AnchorType
|
|
from helix.constants.module_type import ModuleType
|
|
from helix.constants.panel_type import PanelType
|
|
from helix.constants.version import version
|
|
|
|
from helix.doc_gen_params_builder import DocGenParamsBuilder
|
|
from helix.models.coordinate import Coordinate
|
|
from helix.models.panel import Panel
|
|
from helix.models.sql.inverters import Inverter
|
|
from helix.models.sql.power_stations import PowerStation
|
|
from helix.models.sql.sites import Site
|
|
from helix.models.sql.standalone_inverters import StandaloneInverter
|
|
from helix.models.subarray import Subarray
|
|
from helix.user_values import UserValues
|
|
|
|
|
|
class DocGenParamsBuilderTest(unittest.TestCase):
|
|
def setUp(self):
|
|
self.site = Site(system_type='1')
|
|
|
|
self.site.project_name = ''
|
|
self.site.building_height = 0
|
|
self.site.building_width = 0
|
|
self.site.building_length = 0
|
|
self.site.parapet_height = 0
|
|
self.site.ballast_block_weight = 0
|
|
self.site.max_psf = 0
|
|
self.site.anchor_type = AnchorType.OMG_PowerGrip_Plus.value
|
|
self.site.exposure_category = 'C'
|
|
self.site.wind_speed = 0
|
|
self.site.spectral_response = 1
|
|
self.site.importance_factor = 1
|
|
self.site.module_type = ModuleType.Cell96.value
|
|
|
|
self.user_values = UserValues(None, self.site)
|
|
self.calculator = MagicMock()
|
|
self.image_presenter = MagicMock()
|
|
os.environ['SP_DOCGEN_API_KEY'] = 'TestDocGenApiKey'
|
|
|
|
def tearDown(self):
|
|
os.environ['SP_DOCGEN_API_KEY'] = ''
|
|
|
|
def test_build_single_tilt(self):
|
|
self.site.system_type = '0'
|
|
subject = DocGenParamsBuilder(self.user_values, self.user_values.system_type(), self.calculator, self.image_presenter)
|
|
|
|
self.calculator.L_B.return_value = 0.001
|
|
self.calculator.k_z.return_value = 0.949932
|
|
self.calculator.q_z.return_value = 0.12453
|
|
self.calculator.get_computed_csv_columns.return_value = []
|
|
self.calculator.documentation_summary_values.return_value = {'summary': 'foo'}
|
|
self.calculator.summary_table.return_value = OrderedDict({PanelType.Corner:
|
|
{'anchors': [1],
|
|
'ballast blocks': [6],
|
|
'pressure': ['4.46']}})
|
|
self.calculator.minimum_array_sizes.return_value = [123]
|
|
self.calculator.documentation_bom.return_value = []
|
|
self.calculator.documentation_bom.return_value = [
|
|
('88764', 9),
|
|
('modules', 0)
|
|
]
|
|
self.image_presenter.generate_image.return_value = "".encode("utf-8")
|
|
|
|
params = subject.build()
|
|
|
|
expected = {
|
|
'apiKey': 'TestDocGenApiKey',
|
|
'templateName': 'Helix_Single_Tilt_Template',
|
|
'nameValuePairs': [
|
|
{'name': '1_a_anc', 'value': 1},
|
|
{'name': '1_a_bb', 'value': 6},
|
|
{'name': '1_a_psf', 'value': '4.46'},
|
|
{'name': 'anchor_type', 'value': 'OMG PowerGrip Plus'},
|
|
{'name': 'ballast_block_weight', 'value': 0.0},
|
|
{'name': 'building_height', 'value': 0.0},
|
|
{'name': 'building_length', 'value': 0.0},
|
|
{'name': 'building_width', 'value': 0.0},
|
|
{'name': 'exposure_category', 'value': 'C'},
|
|
{'name': 'exposure_category_transition_distance', 'value': 0},
|
|
{'name': 'kz', 'value': 0.95},
|
|
{'name': 'lb', 'value': 0.0},
|
|
{'name': 'max_allowable_system_pressure', 'value': 0.0},
|
|
{'name': 'min_a', 'value': 123},
|
|
{'name': 'module_type', 'value': '96 Cell'},
|
|
{'name': 'parapet_height', 'value': 0.0},
|
|
{'name': 'power_station_string', 'value': ''},
|
|
{'name': 'project_name', 'value': ''},
|
|
{'name': 'qz', 'value': 0.12},
|
|
{'name': 'seismic_importance_factor', 'value': 1.0},
|
|
{'name': 'spectral_response', 'value': 1.0},
|
|
{'name': 'standalone_inverter_string', 'value': ''},
|
|
{'name': 'subarrays_string', 'value': ''},
|
|
{'name': 'summary', 'value': 'foo'},
|
|
{'name': 'system_type', 'value': 'Single-Tilt'},
|
|
{'name': 'total_88764', 'value': 9},
|
|
{'name': 'total_modules', 'value': 0},
|
|
{'name': 'version', 'value': version()},
|
|
{'name': 'wind_speed', 'value': 0.0},
|
|
],
|
|
'dynamicImages': [
|
|
{'imageKey': 'array_image', 'base64encodedImage': ''}
|
|
]
|
|
}
|
|
|
|
eq_(params, expected)
|
|
|
|
def test_build_dual_tilt(self):
|
|
self.site.system_type = '1'
|
|
subject = DocGenParamsBuilder(self.user_values, self.user_values.system_type(), self.calculator, self.image_presenter)
|
|
|
|
self.calculator.L_B.return_value = 0
|
|
self.calculator.k_z.return_value = 0
|
|
self.calculator.q_z.return_value = 0
|
|
self.calculator.get_computed_csv_columns.return_value = []
|
|
self.calculator.documentation_summary_values.return_value = {'summary': 'foo'}
|
|
self.image_presenter.generate_image.return_value = "".encode("utf-8")
|
|
|
|
params = subject.build()
|
|
|
|
eq_(sorted(params.keys()), ['apiKey', 'dynamicImages', 'nameValuePairs', 'templateName'])
|
|
eq_(params['apiKey'], 'TestDocGenApiKey')
|
|
eq_(params['templateName'], 'Helix_Dual_Tilt_Template')
|
|
|
|
def test_site_characterization(self):
|
|
self.site.system_type = '0'
|
|
self.site.project_name = 'Test Project Name'
|
|
self.site.building_height = 100
|
|
self.site.building_width = 1000
|
|
self.site.building_length = 1500
|
|
self.site.parapet_height = 0
|
|
self.site.ballast_block_weight = 20
|
|
self.site.max_psf = 17
|
|
self.site.anchor_type = AnchorType.EcoFasten.value
|
|
self.site.exposure_category = 'D'
|
|
self.site.wind_speed = 110
|
|
self.site.spectral_response = 1
|
|
self.site.importance_factor = 1
|
|
self.site.module_type = ModuleType.Cell96.value
|
|
|
|
self.calculator.L_B.return_value = 23
|
|
self.calculator.k_z.return_value = 34
|
|
self.calculator.q_z.return_value = 45
|
|
self.calculator.get_computed_csv_columns.return_value = [
|
|
Panel(),
|
|
Panel()
|
|
]
|
|
subject = DocGenParamsBuilder(self.user_values, self.user_values.system_type(), self.calculator, self.image_presenter)
|
|
|
|
expected_site_characterization = {
|
|
'project_name': 'Test Project Name',
|
|
'building_height': 100.0,
|
|
'building_width': 1000.0,
|
|
'building_length': 1500.0,
|
|
'parapet_height': 0.0,
|
|
'ballast_block_weight': 20.0,
|
|
'max_allowable_system_pressure': 17,
|
|
'anchor_type': 'EcoFasten Eco 65',
|
|
'exposure_category': 'D',
|
|
'exposure_category_transition_distance': 0,
|
|
'wind_speed': 110,
|
|
'spectral_response': 1,
|
|
'seismic_importance_factor': 1,
|
|
'module_type': '96 Cell',
|
|
'system_type': 'Single-Tilt',
|
|
|
|
'total_modules': 2,
|
|
'version': version(),
|
|
'lb': 23,
|
|
'kz': 34,
|
|
'qz': 45
|
|
}
|
|
|
|
eq_(subject.site_characterization(), expected_site_characterization)
|
|
|
|
def test_build_panel_attributes_dual_tilt(self):
|
|
self.site.system_type = '1'
|
|
self.calculator.summary_table.return_value = OrderedDict({
|
|
PanelType.Corner:
|
|
{'anchors': [1, 1, 0, 0, 0],
|
|
'ballast blocks': [6, 0, 13, 5, 0],
|
|
'pressure': ['4.46', '2.40', '6.86', '4.08', '2.40']},
|
|
PanelType.NorthSouth:
|
|
{'anchors': [1, 0, 0, 0, 0],
|
|
'ballast blocks': [0, 19, 9, 3, 0],
|
|
'pressure': ['2.40', '8.94', '5.47', '3.41', '2.40']},
|
|
PanelType.EastWest:
|
|
{'anchors': [1, 0, 0, 0, 0],
|
|
'ballast blocks': [0, 19, 9, 3, 0],
|
|
'pressure': ['2.26', '8.77', '5.35', '3.27', '2.26']},
|
|
PanelType.Middle:
|
|
{'anchors': [0, 0, 0, 0, 0],
|
|
'ballast blocks': [16, 8, 3, 0, 0],
|
|
'pressure': ['7.76', '5.01', '3.27', '2.26', '2.26']}
|
|
})
|
|
|
|
self.calculator.minimum_array_sizes.return_value = [22, 19, 23, 19, 6]
|
|
|
|
subject = DocGenParamsBuilder(self.user_values, self.user_values.system_type(), self.calculator, self.image_presenter)
|
|
|
|
expected = {
|
|
'1_a_bb': 6,
|
|
'1_b_bb': 0,
|
|
'1_c_bb': 13,
|
|
'1_d_bb': 5,
|
|
'1_e_bb': 0,
|
|
|
|
'1_a_anc': 1,
|
|
'1_b_anc': 1,
|
|
'1_c_anc': 0,
|
|
'1_d_anc': 0,
|
|
'1_e_anc': 0,
|
|
|
|
'1_a_psf': '4.46',
|
|
'1_b_psf': '2.40',
|
|
'1_c_psf': '6.86',
|
|
'1_d_psf': '4.08',
|
|
'1_e_psf': '2.40',
|
|
|
|
'2_a_bb': 0,
|
|
'2_b_bb': 19,
|
|
'2_c_bb': 9,
|
|
'2_d_bb': 3,
|
|
'2_e_bb': 0,
|
|
|
|
'2_a_anc': 1,
|
|
'2_b_anc': 0,
|
|
'2_c_anc': 0,
|
|
'2_d_anc': 0,
|
|
'2_e_anc': 0,
|
|
|
|
'2_a_psf': '2.40',
|
|
'2_b_psf': '8.94',
|
|
'2_c_psf': '5.47',
|
|
'2_d_psf': '3.41',
|
|
'2_e_psf': '2.40',
|
|
|
|
'3_a_bb': 0,
|
|
'3_b_bb': 19,
|
|
'3_c_bb': 9,
|
|
'3_d_bb': 3,
|
|
'3_e_bb': 0,
|
|
|
|
'3_a_anc': 1,
|
|
'3_b_anc': 0,
|
|
'3_c_anc': 0,
|
|
'3_d_anc': 0,
|
|
'3_e_anc': 0,
|
|
|
|
'3_a_psf': '2.26',
|
|
'3_b_psf': '8.77',
|
|
'3_c_psf': '5.35',
|
|
'3_d_psf': '3.27',
|
|
'3_e_psf': '2.26',
|
|
|
|
'4_a_bb': 16,
|
|
'4_b_bb': 8,
|
|
'4_c_bb': 3,
|
|
'4_d_bb': 0,
|
|
'4_e_bb': 0,
|
|
|
|
'4_a_anc': 0,
|
|
'4_b_anc': 0,
|
|
'4_c_anc': 0,
|
|
'4_d_anc': 0,
|
|
'4_e_anc': 0,
|
|
|
|
'4_a_psf': '7.76',
|
|
'4_b_psf': '5.01',
|
|
'4_c_psf': '3.27',
|
|
'4_d_psf': '2.26',
|
|
'4_e_psf': '2.26',
|
|
|
|
'min_a': 22,
|
|
'min_b': 19,
|
|
'min_c': 23,
|
|
'min_d': 19,
|
|
'min_e': 6
|
|
}
|
|
|
|
eq_(subject.panel_attributes(), expected)
|
|
|
|
def test_build_bom(self):
|
|
self.calculator.documentation_bom.return_value = [
|
|
('512200', 480),
|
|
('513832', 0),
|
|
('513833', 790),
|
|
('513836', 0),
|
|
('521794', 196),
|
|
|
|
('anchors', 262),
|
|
('ballast', 6786),
|
|
('modules', 1726)
|
|
]
|
|
|
|
subject = DocGenParamsBuilder(self.user_values, self.user_values.system_type(), self.calculator, self.image_presenter)
|
|
|
|
expected = {
|
|
'total_512200': 480,
|
|
'total_513832': 0,
|
|
'total_513833': 790,
|
|
'total_513836': 0,
|
|
'total_521794': 196,
|
|
'total_anchors': 262,
|
|
'total_ballast': 6786,
|
|
'total_modules': 1726
|
|
}
|
|
|
|
eq_(subject.bom(), expected)
|
|
|
|
def test_build_power_station(self):
|
|
power_station_1 = PowerStation(
|
|
description='1',
|
|
quantity=1,
|
|
ac_run_length=55,
|
|
inverters=[
|
|
Inverter(
|
|
model='4',
|
|
strings_per_inverter=2,
|
|
sunshade=True,
|
|
dc_switch=False
|
|
),
|
|
Inverter(
|
|
model='5',
|
|
strings_per_inverter=5,
|
|
sunshade=False,
|
|
dc_switch=False
|
|
)
|
|
]
|
|
)
|
|
|
|
power_station_2 = PowerStation(
|
|
description='2',
|
|
quantity=3,
|
|
ac_run_length=89,
|
|
inverters=[
|
|
Inverter(
|
|
model='6',
|
|
strings_per_inverter=6,
|
|
sunshade=False,
|
|
dc_switch=True
|
|
),
|
|
Inverter(
|
|
model='8',
|
|
strings_per_inverter=8,
|
|
sunshade=False,
|
|
dc_switch=False
|
|
)
|
|
]
|
|
)
|
|
|
|
self.site.power_stations = [power_station_1, power_station_2]
|
|
|
|
expected = {
|
|
'power_station_string': """
|
|
Description: 1
|
|
\tQuantity: 1
|
|
\tAC Run Length: 55
|
|
\tInverters:
|
|
\t\tModel: 12kW SMA Tripower - 514686
|
|
\t\tStrings per inverter: 2
|
|
\t\tSunShade: Yes
|
|
|
|
\t\tModel: 15kW SMA Tripower - 514687
|
|
\t\tStrings per inverter: 5
|
|
|
|
Description: 2
|
|
\tQuantity: 3
|
|
\tAC Run Length: 89
|
|
\tInverters:
|
|
\t\tModel: 20kW SMA Tripower - 512676
|
|
\t\tStrings per inverter: 6
|
|
\t\tDC Switch: Yes
|
|
|
|
\t\tModel: 24kW SMA Tripower - 514685
|
|
\t\tStrings per inverter: 8
|
|
|
|
"""
|
|
}
|
|
|
|
subject = DocGenParamsBuilder(self.user_values, self.user_values.system_type(), self.calculator, self.image_presenter)
|
|
eq_(subject.power_stations(), expected)
|
|
|
|
def test_standalone_inverters(self):
|
|
power_station = PowerStation(
|
|
description='My Power Station',
|
|
quantity=1,
|
|
ac_run_length=45,
|
|
inverters=[
|
|
Inverter(
|
|
model='8',
|
|
strings_per_inverter=7,
|
|
sunshade=True,
|
|
dc_switch=True
|
|
),
|
|
Inverter(
|
|
model='4',
|
|
strings_per_inverter=2,
|
|
sunshade=False,
|
|
dc_switch=False
|
|
)
|
|
]
|
|
)
|
|
|
|
standalone_inverter_1 = StandaloneInverter(
|
|
inverter=[Inverter(model='6', strings_per_inverter='5', sunshade=True, dc_switch=False)],
|
|
ac_run_length=45,
|
|
attachment_point=power_station,
|
|
)
|
|
|
|
standalone_inverter_2 = StandaloneInverter(
|
|
inverter=[Inverter(model='4', strings_per_inverter='3', sunshade=False, dc_switch=True)],
|
|
ac_run_length=45,
|
|
attachment_point=None,
|
|
)
|
|
|
|
self.site.power_stations = [power_station]
|
|
self.site.standalone_inverters = [standalone_inverter_1, standalone_inverter_2]
|
|
|
|
subject = DocGenParamsBuilder(self.user_values, self.user_values.system_type(), self.calculator, self.image_presenter)
|
|
"""
|
|
AC Run Length: 3
|
|
Attachment Point: Switch Gear
|
|
Model: 20kW SMA Tripower - 512676
|
|
Strings per inverter: 6
|
|
Sunshade: Yes
|
|
DC Switch: Yes
|
|
"""
|
|
|
|
expected = {
|
|
'standalone_inverter_string': """
|
|
\tAC Run Length: 45
|
|
\tAttachment Point: My Power Station
|
|
\tModel: 20kW SMA Tripower - 512676
|
|
\tStrings per inverter: 5
|
|
\tSunShade: Yes
|
|
|
|
\tAC Run Length: 45
|
|
\tAttachment Point: Switch Gear
|
|
\tModel: 12kW SMA Tripower - 514686
|
|
\tStrings per inverter: 3
|
|
\tDC Switch: Yes
|
|
"""
|
|
}
|
|
eq_(subject.standalone_inverters(), expected)
|
|
|
|
def test_subarray_summary(self):
|
|
self.calculator.subarray_summary.return_value = [
|
|
Subarray(subarray_number=1, origin=Coordinate(0, 0), required_seismic_anchors=11, weight=23782.67, start_row=0,
|
|
size=192),
|
|
Subarray(subarray_number=2, origin=Coordinate(0, 0), required_seismic_anchors=0, weight=13113.05,
|
|
start_row=192, size=96)
|
|
]
|
|
|
|
subject = DocGenParamsBuilder(self.user_values, self.user_values.system_type(), self.calculator, self.image_presenter)
|
|
|
|
expected = {
|
|
'subarrays_string': """
|
|
\tSubarray: 1
|
|
\tSeismic Anchors: 11
|
|
\tWeight: 23,783 lbs
|
|
|
|
\tSubarray: 2
|
|
\tSeismic Anchors: 0
|
|
\tWeight: 13,113 lbs
|
|
"""
|
|
}
|
|
eq_(subject.subarray_summary(), expected)
|
|
|
|
def test_array_image(self):
|
|
panels = [
|
|
Panel(id=1)
|
|
]
|
|
subarrays = [
|
|
Subarray(subarray_number=1)
|
|
]
|
|
self.calculator.get_computed_csv_columns.return_value = panels
|
|
self.calculator.subarrays = subarrays
|
|
self.image_presenter.generate_image.return_value = "hello world".encode("utf-8")
|
|
|
|
subject = DocGenParamsBuilder(self.user_values, self.user_values.system_type(), self.calculator, self.image_presenter)
|
|
|
|
expected = {'array_image': 'aGVsbG8gd29ybGQ='}
|
|
|
|
eq_(subject.array_image(), expected)
|
|
|
|
self.image_presenter.generate_image.assert_called_once_with(panels, subarrays)
|
|
|
|
def test_convert_list_params_to_dict(self):
|
|
list_params = [
|
|
{
|
|
'name': 'foo',
|
|
'value': 'bar'
|
|
},
|
|
{
|
|
'name': 'cat',
|
|
'value': 'dog'
|
|
}
|
|
]
|
|
|
|
expected = {
|
|
'foo': 'bar',
|
|
'cat': 'dog'
|
|
}
|
|
|
|
eq_(DocGenParamsBuilder.convert_list_params_to_dict(list_params), expected)
|
|
|
|
def test_convert_dict_params_to_list(self):
|
|
dict_params = {
|
|
'foo': 'bar',
|
|
'cat': 'dog',
|
|
'fast': 'slow',
|
|
}
|
|
|
|
expected = sorted([
|
|
{
|
|
'name': 'foo',
|
|
'value': 'bar'
|
|
},
|
|
{
|
|
'name': 'cat',
|
|
'value': 'dog'
|
|
},
|
|
{
|
|
'name': 'fast',
|
|
'value': 'slow'
|
|
}
|
|
], key=lambda k: k['name'])
|
|
|
|
eq_(DocGenParamsBuilder.convert_dict_params_to_list(dict_params), expected)
|
|
|
|
def test_convert_dict_parms_to_list_other_names(self):
|
|
dict_params = {
|
|
'foo': 'bar',
|
|
'cat': 'dog',
|
|
'fast': 'slow',
|
|
}
|
|
|
|
expected = sorted([
|
|
{
|
|
'baz': 'foo',
|
|
'qux': 'bar'
|
|
},
|
|
{
|
|
'baz': 'cat',
|
|
'qux': 'dog'
|
|
},
|
|
{
|
|
'baz': 'fast',
|
|
'qux': 'slow'
|
|
}
|
|
], key=lambda k: k['baz'])
|
|
|
|
eq_(DocGenParamsBuilder.convert_dict_params_to_list(dict_params, key_name='baz', value_name='qux'), expected)
|