def test_get_assets(client, add_charging_station_assets, use_owner_id, num_assets): """ Get assets, either for all users (our user here is admin, so is allowed to see all 7 assets) or for a unique one (prosumer user 2 has one asset ― "Test battery"). """ auth_token = get_auth_token(client, "*****@*****.**", "testtest") test_prosumer2_id = find_user_by_email("*****@*****.**").id query = {} if use_owner_id: query["owner_id"] = test_prosumer2_id get_assets_response = client.get( url_for("flexmeasures_api_v2_0.get_assets"), query_string=query, headers={ "content-type": "application/json", "Authorization": auth_token }, ) print("Server responded with:\n%s" % get_assets_response.json) assert get_assets_response.status_code == 200 assert len(get_assets_response.json) == num_assets battery = {} for asset in get_assets_response.json: if asset["name"] == "Test battery": battery = asset assert battery assert pd.Timestamp( battery["soc_datetime"]) == pd.Timestamp("2015-01-01T00:00:00+00:00") assert battery["owner_id"] == test_prosumer2_id assert battery["capacity_in_mw"] == 2
def test_user_crud_as_non_admin(client, as_prosumer, view): user_index = client.get(url_for("UserCrudUI:index"), follow_redirects=True) assert user_index.status_code == 403 prosumer2_id = find_user_by_email("*****@*****.**").id user_page = client.get(url_for(f"UserCrudUI:{view}", id=prosumer2_id), follow_redirects=True) assert user_page.status_code == 403
def setup_assets(db, setup_roles_users, setup_markets): """Make some asset types and add assets to known test users.""" data_source = DataSource(name="Seita", type="demo script") db.session.add(data_source) db.session.add( AssetType( name="solar", is_producer=True, can_curtail=True, daily_seasonality=True, yearly_seasonality=True, ) ) db.session.add( AssetType( name="wind", is_producer=True, can_curtail=True, daily_seasonality=True, yearly_seasonality=True, ) ) test_prosumer = find_user_by_email("*****@*****.**") test_market = Market.query.filter_by(name="epex_da").one_or_none() for asset_name in ["wind-asset-1", "wind-asset-2", "solar-asset-1"]: asset = Asset( name=asset_name, asset_type_name="wind" if "wind" in asset_name else "solar", event_resolution=timedelta(minutes=15), capacity_in_mw=1, latitude=10, longitude=100, min_soc_in_mwh=0, max_soc_in_mwh=0, soc_in_mwh=0, unit="MW", market_id=test_market.id, ) asset.owner = test_prosumer db.session.add(asset) # one day of test data (one complete sine curve) time_slots = pd.date_range( datetime(2015, 1, 1), datetime(2015, 1, 1, 23, 45), freq="15T" ) values = [random() * (1 + np.sin(x / 15)) for x in range(len(time_slots))] for dt, val in zip(time_slots, values): p = Power( datetime=as_server_time(dt), horizon=parse_duration("PT0M"), value=val, data_source_id=data_source.id, ) p.asset = asset db.session.add(p)
def delete_user_and_data(email: str): """ Delete a user, which also deletes their data. """ the_user = find_user_by_email(email) if the_user is None: print(f"Could not find user with email address '{email}' ...") return delete_user(the_user) app.db.session.commit()
def test_delete_user(app): """Assert user has assets and power measurements. Deleting removes all of that.""" prosumer: User = find_user_by_email("*****@*****.**") num_users_before = User.query.count() user_assets_with_measurements_before = Asset.query.filter( Asset.owner_id == prosumer.id, Asset.asset_type_name.in_(["wind", "solar"]) ).all() asset_ids = [asset.id for asset in user_assets_with_measurements_before] for asset_id in asset_ids: num_power_measurements = Power.query.filter(Power.asset_id == asset_id).count() assert num_power_measurements == 96 delete_user(prosumer) assert find_user_by_email("*****@*****.**") is None user_assets_after = Asset.query.filter(Asset.owner_id == prosumer.id).all() assert len(user_assets_after) == 0 assert User.query.count() == num_users_before - 1 for asset_id in asset_ids: num_power_measurements = Power.query.filter(Power.asset_id == asset_id).count() assert num_power_measurements == 0
def test_edit_user(client): with UserContext("*****@*****.**") as supplier: supplier_auth_token = supplier.get_auth_token() # supplier is no admin supplier_id = supplier.id with UserContext("*****@*****.**") as prosumer: prosumer_auth_token = prosumer.get_auth_token() # prosumer is an admin prosumer_id = prosumer.id # without being the user themselves or an admin, the user cannot be edited user_edit_response = client.patch( url_for("flexmeasures_api_v2_0.patch_user", id=prosumer_id), headers={ "content-type": "application/json", "Authorization": supplier_auth_token, }, json={}, ) assert user_edit_response.status_code == 403 user_edit_response = client.patch( url_for("flexmeasures_api_v2_0.patch_user", id=supplier_id), headers={"content-type": "application/json"}, json={}, ) assert user_edit_response.status_code == 401 # admin can deactivate supplier, other changes will be ignored # (id is in the Userschema of the API, but we ignore it) headers = { "content-type": "application/json", "Authorization": prosumer_auth_token } user_edit_response = client.patch( url_for("flexmeasures_api_v2_0.patch_user", id=supplier_id), headers=headers, json={ "active": False, "id": 888 }, ) print("Server responded with:\n%s" % user_edit_response.json) assert user_edit_response.status_code == 200 assert user_edit_response.json["active"] is False supplier = find_user_by_email("*****@*****.**") assert supplier.active is False assert supplier.id == supplier_id # admin can edit themselves but not sensitive fields headers = { "content-type": "application/json", "Authorization": prosumer_auth_token } user_edit_response = client.patch( url_for("flexmeasures_api_v2_0.patch_user", id=prosumer_id), headers=headers, json={"active": False}, ) print("Server responded with:\n%s" % user_edit_response.json) assert user_edit_response.status_code == 403
def get_asset_post_data() -> dict: post_data = { "name": "Test battery 2", "unit": "MW", "capacity_in_mw": 3, "event_resolution": timedelta(minutes=10).seconds / 60, "latitude": 30.1, "longitude": 100.42, "asset_type_name": "battery", "owner_id": find_user_by_email("*****@*****.**").id, "market_id": Sensor.query.filter_by(name="epex_da").one_or_none().id, } return post_data
def test_reset_password(client, as_admin, requests_mock): """Test it does not fail (logic is tested in API tests) and displays an answer.""" user2 = find_user_by_email("*****@*****.**", keep_in_session=False) requests_mock.patch( f"http://localhost//api/v3_0/users/{user2.id}/password-reset", status_code=200, ) user_page = client.get( url_for("UserCrudUI:reset_password_for", id=user2.id), follow_redirects=True, ) assert user_page.status_code == 200 assert b"has been changed to a random password" in user_page.data
def delete_a_user(email: str, force: bool): """ Delete a user & also their assets and data. """ if not force: prompt = f"Delete user '{email}'?" click.confirm(prompt, abort=True) the_user = find_user_by_email(email) if the_user is None: print(f"Could not find user with email address '{email}' ...") return delete_user(the_user) db.session.commit()
def test_get_one_user(client, requesting_user, status_code): test_user2_id = find_user_by_email("*****@*****.**").id headers = {"content-type": "application/json"} if requesting_user: headers["Authorization"] = get_auth_token(client, requesting_user, "testtest") get_user_response = client.get( url_for("UserAPI:get", id=test_user2_id), headers=headers, ) print("Server responded with:\n%s" % get_user_response.data) assert get_user_response.status_code == status_code if status_code == 200: assert get_user_response.json["username"] == "Test Prosumer User 2"
def test_deactivate_user(client, as_admin, requests_mock): """Test it does not fail (logic is tested in API tests) and displays an answer.""" user2 = find_user_by_email("*****@*****.**", keep_in_session=False) requests_mock.patch( f"http://localhost//api/v3_0/users/{user2.id}", status_code=200, json={"active": False}, ) # de-activate user_page = client.get( url_for("UserCrudUI:toggle_active", id=user2.id), follow_redirects=True ) assert user_page.status_code == 200 assert user2.username in str(user_page.data) assert b"new activation status is now False" in user_page.data
def test_add_asset(db, client, setup_assets, requests_mock, as_admin): """Add a new asset""" user = find_user_by_email("*****@*****.**") mock_asset = mock_asset_response(account_id=user.account.id, as_list=False) requests_mock.post(api_path_assets, status_code=201, json=mock_asset) response = client.post( url_for("AssetCrudUI:post", id="create"), follow_redirects=True, data=mock_api_data_as_form_input(mock_asset), ) assert response.status_code == 200 # response is HTML form assert "html" in response.content_type assert b"Creation was successful" in response.data assert mock_asset["name"] in str(response.data) assert str(mock_asset["latitude"]) in str(response.data) assert str(mock_asset["longitude"]) in str(response.data)
def test_get_one_user(client): test_supplier_id = find_user_by_email("*****@*****.**").id headers = { "content-type": "application/json", "Authorization": get_auth_token(client, "*****@*****.**", "testtest"), } get_user_response = client.get( url_for("flexmeasures_api_v2_0.get_user", id=test_supplier_id), headers=headers, ) print("Server responded with:\n%s" % get_user_response.data) assert get_user_response.status_code == 200 assert get_user_response.json["username"] == "Test Supplier"
def test_edit_user(client): with UserContext("*****@*****.**") as user2: user2_auth_token = user2.get_auth_token() # user2 is no admin user2_id = user2.id with UserContext("*****@*****.**") as admin: admin_auth_token = admin.get_auth_token() admin_id = admin.id # without being the user themselves or an admin, the user cannot be edited user_edit_response = client.patch( url_for("UserAPI:patch", id=admin_id), headers={ "content-type": "application/json", "Authorization": user2_auth_token, }, json={}, ) assert user_edit_response.status_code == 403 user_edit_response = client.patch( url_for("UserAPI:patch", id=user2_id), headers={"content-type": "application/json"}, json={}, ) assert user_edit_response.status_code == 401 # admin can deactivate user2 admin_headers = { "content-type": "application/json", "Authorization": admin_auth_token, } user_edit_response = client.patch( url_for("UserAPI:patch", id=user2_id), headers=admin_headers, json={"active": False}, ) print("Server responded with:\n%s" % user_edit_response.json) assert user_edit_response.status_code == 200 assert user_edit_response.json["active"] is False user2 = find_user_by_email("*****@*****.**") assert user2.active is False assert user2.id == user2_id # admin can edit themselves but not sensitive fields user_edit_response = client.patch( url_for("UserAPI:patch", id=admin_id), headers=admin_headers, json={"active": False}, ) print("Server responded with:\n%s" % user_edit_response.json) assert user_edit_response.status_code == 403
def test_add_asset_with_new_owner(client, requests_mock, as_admin): """Test roundtrip and expect new user (new owner) in db""" mock_asset = mock_asset_response(owner_id=-1, as_list=False) requests_mock.post("http://localhost//api/v2_0/assets", status_code=201, json=mock_asset) new_user_email = "*****@*****.**" data = copy.deepcopy(mock_asset) data["new_owner_email"] = new_user_email response = client.post( url_for("AssetCrudUI:post", id="create"), follow_redirects=True, data=mock_api_data_as_form_input(data), ) assert response.status_code == 200 assert b"Creation was successful" in response.data assert find_user_by_email(new_user_email)
def test_asset_page(db, client, setup_assets, requests_mock, as_prosumer_user1): user = find_user_by_email("*****@*****.**") asset = user.assets[0] db.session.expunge(user) mock_asset = mock_asset_response(as_list=False) mock_asset["latitude"] = asset.latitude mock_asset["longitude"] = asset.longitude requests_mock.get(f"{api_path_assets}/{asset.id}", status_code=200, json=mock_asset) asset_page = client.get(url_for("AssetCrudUI:get", id=asset.id), follow_redirects=True) assert ("Edit asset %s" % mock_asset["name"]).encode() in asset_page.data assert str(mock_asset["latitude"]).encode() in asset_page.data assert str(mock_asset["longitude"]).encode() in asset_page.data
def test_asset_page(db, client, requests_mock, as_prosumer): prosumer = find_user_by_email("*****@*****.**") asset = prosumer.assets[0] db.session.expunge(prosumer) mock_asset = mock_asset_response(as_list=False) mock_asset["capacity_in_mw"] = asset.capacity_in_mw mock_asset["latitude"] = asset.latitude mock_asset["longitude"] = asset.longitude requests_mock.get(f"http://localhost//api/v2_0/asset/{asset.id}", status_code=200, json=mock_asset) asset_page = client.get(url_for("AssetCrudUI:get", id=asset.id), follow_redirects=True) assert ("Edit asset %s" % mock_asset["display_name"]).encode() in asset_page.data assert str(mock_asset["capacity_in_mw"]).encode() in asset_page.data assert str(mock_asset["latitude"]).encode() in asset_page.data assert str(mock_asset["longitude"]).encode() in asset_page.data
def test_user_reset_password(app, client, sender): """ Reset the password of supplier. Only the prosumer is allowed to do that (as admin). """ with UserContext("*****@*****.**") as supplier: supplier_id = supplier.id old_password = supplier.password headers = {"content-type": "application/json"} if sender != "": headers["Authorization"] = (get_auth_token(client, sender, "testtest"), ) with app.mail.record_messages() as outbox: pwd_reset_response = client.patch( url_for("flexmeasures_api_v2_0.reset_user_password", id=supplier_id), query_string={}, headers=headers, ) print("Server responded with:\n%s" % pwd_reset_response.json) if sender == "": assert pwd_reset_response.status_code == 401 return if sender == "*****@*****.**": assert pwd_reset_response.status_code == 403 return assert pwd_reset_response.status_code == 200 supplier = find_user_by_email("*****@*****.**") assert len(outbox) == 2 assert "has been reset" in outbox[0].subject pwd_reset_instructions = outbox[1] assert old_password != supplier.password assert "reset instructions" in pwd_reset_instructions.subject assert ("reset your password:\n\n%sreset/" % request.host_url in pwd_reset_instructions.body)
def test_user_reset_password(app, client, setup_inactive_user, sender): """ Reset the password of User 2. Only the admin user and User 2 themselves are allowed to do that. """ with UserContext("*****@*****.**") as user2: user2_id = user2.id old_password = user2.password headers = {"content-type": "application/json"} if sender != "": headers["Authorization"] = (get_auth_token(client, sender, "testtest"),) with app.mail.record_messages() as outbox: pwd_reset_response = client.patch( url_for("UserAPI:reset_user_password", id=user2_id), query_string={}, headers=headers, ) print("Server responded with:\n%s" % pwd_reset_response.json) if sender in ("", "*****@*****.**"): assert pwd_reset_response.status_code == 401 return if sender == "*****@*****.**": assert pwd_reset_response.status_code == 403 return assert pwd_reset_response.status_code == 200 user2 = find_user_by_email("*****@*****.**") assert len(outbox) == 2 assert "has been reset" in outbox[0].subject pwd_reset_instructions = outbox[1] assert old_password != user2.password assert "reset instructions" in pwd_reset_instructions.subject assert ( "reset your password:\n\n%sreset/" % request.host_url in pwd_reset_instructions.body )
def test_get_assets_badauth(client, setup_api_test_data, use_auth): """ Attempt to get assets with wrong or missing auth. """ # the case without auth: authentication will fail headers = {"content-type": "application/json"} query = {} if use_auth: # in this case, we successfully authenticate, but fail authorization headers["Authorization"] = get_auth_token( client, "*****@*****.**", "testtest" ) test_prosumer = find_user_by_email("*****@*****.**") query = {"account_id": test_prosumer.account.id} get_assets_response = client.get( url_for("AssetAPI:index"), query_string=query, headers=headers ) print("Server responded with:\n%s" % get_assets_response.json) if use_auth: assert get_assets_response.status_code == 403 else: assert get_assets_response.status_code == 401
def __init__(self, user_email: str): self.the_user = find_user_by_email(user_email)