test_asset_crud.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. from flask import url_for
  2. import pytest
  3. from flexmeasures.data.services.users import find_user_by_email
  4. from flexmeasures.ui.tests.utils import mock_asset_response, mock_api_data_as_form_input
  5. from flexmeasures.ui.views.assets import get_assets_by_account
  6. """
  7. Testing if our asset UI proceeds with the expected round trip.
  8. Here, we mock the API responses (we have to, as our UI layer contacts FlexMeasures as a server, which does not run during tests).
  9. The real logic tests are done in the api package, which is also the better place for that.
  10. """
  11. api_path_assets = "http://localhost//api/v3_0/assets"
  12. def test_assets_page_empty(db, client, requests_mock, as_prosumer_user1):
  13. requests_mock.get(f"{api_path_assets}", status_code=200, json=[])
  14. requests_mock.get(f"{api_path_assets}/public", status_code=200, json=[])
  15. asset_index = client.get(url_for("AssetCrudUI:index"), follow_redirects=True)
  16. assert asset_index.status_code == 200
  17. def test_get_assets_by_account(db, client, requests_mock, as_prosumer_user1):
  18. mock_assets = mock_asset_response(multiple=True)
  19. requests_mock.get(f"{api_path_assets}", status_code=200, json=mock_assets)
  20. assert get_assets_by_account(1)[1].name == "TestAsset2"
  21. def test_new_asset_page(client, setup_assets, as_admin):
  22. asset_page = client.get(url_for("AssetCrudUI:get", id="new"), follow_redirects=True)
  23. assert asset_page.status_code == 200
  24. assert b"Creating a new asset" in asset_page.data
  25. def test_asset_page(db, client, setup_assets, requests_mock, as_prosumer_user1):
  26. user = find_user_by_email("test_prosumer_user@seita.nl")
  27. asset = user.account.generic_assets[0]
  28. db.session.expunge(user)
  29. mock_asset = mock_asset_response(as_list=False)
  30. mock_asset["latitude"] = asset.latitude
  31. mock_asset["longitude"] = asset.longitude
  32. requests_mock.get(f"{api_path_assets}/{asset.id}", status_code=200, json=mock_asset)
  33. asset_page = client.get(
  34. url_for(
  35. "AssetCrudUI:get",
  36. id=asset.id,
  37. start_time="2022-10-01T00:00:00+02:00",
  38. end_time="2022-10-02T00:00:00+02:00",
  39. ),
  40. follow_redirects=True,
  41. )
  42. assert ("Show sensors").encode() in asset_page.data
  43. assert ("Edit flex-context").encode() in asset_page.data
  44. assert ("Structure").encode() in asset_page.data
  45. assert ("Location").encode() in asset_page.data
  46. @pytest.mark.parametrize(
  47. "args, error",
  48. [
  49. (
  50. {"start_time": "2022-10-01T00:00:00+02:00"},
  51. "Both start_time and end_time must be provided together.",
  52. ),
  53. (
  54. {"end_time": "2022-10-01T00:00:00+02:00"},
  55. "Both start_time and end_time must be provided together.",
  56. ),
  57. (
  58. {
  59. "start_time": "2022-10-01T00:00:00+02:00",
  60. "end_time": "2022-10-01T00:00:00+02:00",
  61. },
  62. "start_time must be before end_time.",
  63. ),
  64. (
  65. {
  66. "start_time": "2022-10-01T00:00:00",
  67. "end_time": "2022-10-02T00:00:00+02:00",
  68. },
  69. "Not a valid aware datetime",
  70. ),
  71. ],
  72. )
  73. def test_asset_page_dates_validation(
  74. db, client, setup_assets, requests_mock, as_prosumer_user1, args, error
  75. ):
  76. user = find_user_by_email("test_prosumer_user@seita.nl")
  77. asset = user.account.generic_assets[0]
  78. db.session.expunge(user)
  79. mock_asset = mock_asset_response(as_list=False)
  80. requests_mock.get(f"{api_path_assets}/{asset.id}", status_code=200, json=mock_asset)
  81. asset_page = client.get(
  82. url_for(
  83. "AssetCrudUI:graphs",
  84. id=asset.id,
  85. **args,
  86. ),
  87. follow_redirects=True,
  88. )
  89. assert error.encode() in asset_page.data
  90. assert "UNPROCESSABLE_ENTITY".encode() in asset_page.data
  91. def test_edit_asset(db, client, setup_assets, requests_mock, as_admin):
  92. mock_asset = mock_asset_response(as_list=False)
  93. requests_mock.patch(f"{api_path_assets}/1", status_code=200, json=mock_asset)
  94. requests_mock.get(f"{api_path_assets}/1", status_code=200, json=mock_asset)
  95. response = client.post(
  96. url_for("AssetCrudUI:post", id=1),
  97. follow_redirects=True,
  98. data=mock_api_data_as_form_input(mock_asset),
  99. )
  100. assert response.status_code == 200
  101. assert b"Editing was successful" in response.data
  102. assert mock_asset["name"] in str(response.data)
  103. assert str(mock_asset["latitude"]) in str(response.data)
  104. assert str(mock_asset["longitude"]) in str(response.data)
  105. def test_add_asset(db, client, setup_assets, requests_mock, as_admin):
  106. """Add a new asset"""
  107. user = find_user_by_email("test_prosumer_user@seita.nl")
  108. mock_asset = mock_asset_response(account_id=user.account.id, as_list=False)
  109. del mock_asset[
  110. "generic_asset_type"
  111. ] # API gives back more info here than a POST sends
  112. mock_asset["generic_asset_type_id"] = 1
  113. requests_mock.post(api_path_assets, status_code=201, json=mock_asset)
  114. # Mock the GET request to fetch the asset (this is the missing mock)
  115. requests_mock.get(f"{api_path_assets}/2", status_code=200, json=mock_asset)
  116. response = client.post(
  117. url_for("AssetCrudUI:post", id="create"),
  118. follow_redirects=True,
  119. data=mock_api_data_as_form_input(mock_asset),
  120. )
  121. assert response.status_code == 200 # response is HTML form
  122. assert "html" in response.content_type
  123. assert b"Creation was successful" in response.data
  124. assert mock_asset["name"] in str(response.data)
  125. assert str(mock_asset["latitude"]) in str(response.data)
  126. assert str(mock_asset["longitude"]) in str(response.data)
  127. def test_delete_asset(client, db, requests_mock, as_admin):
  128. """Delete an asset"""
  129. requests_mock.delete(f"{api_path_assets}/1", status_code=204, json={})
  130. requests_mock.get(api_path_assets, status_code=200, json={})
  131. requests_mock.get(f"{api_path_assets}/public", status_code=200, json={})
  132. response = client.get(
  133. url_for("AssetCrudUI:delete_with_data", id=1),
  134. follow_redirects=True,
  135. )
  136. assert response.status_code == 200
  137. assert b"have been deleted" in response.data