"""Portfolio CRUD and the account set over HTTP.""" from factories import make_account URL = "/api/v1/portfolios" async def test_create_list_and_replace_accounts(client, auth_headers): a = await make_account(name="Брокер 1") b = await make_account(name="Брокер 2") r = await client.post( URL, json={"name": " Основной ", "account_ids": [b, a]}, headers=auth_headers ) assert r.status_code == 201, r.text created = r.json() assert created["name"] == "Основной" assert created["base_currency"] == "RUB" assert created["account_ids"] == sorted([a, b]) r = await client.get(URL, headers=auth_headers) assert [p["id"] for p in r.json()] == [created["id"]] r = await client.put( f"{URL}/{created['id']}/accounts", json={"account_ids": [b]}, headers=auth_headers ) assert r.status_code == 200, r.text assert r.json()["account_ids"] == [b] r = await client.put( f"{URL}/{created['id']}/accounts", json={"account_ids": []}, headers=auth_headers ) assert r.json()["account_ids"] == [] async def test_create_without_accounts_is_allowed(client, auth_headers): r = await client.post(URL, json={"name": "Пустой"}, headers=auth_headers) assert r.status_code == 201 assert r.json()["account_ids"] == [] async def test_duplicate_name_is_a_conflict(client, auth_headers): await client.post(URL, json={"name": "Основной"}, headers=auth_headers) r = await client.post(URL, json={"name": "Основной"}, headers=auth_headers) assert r.status_code == 409 assert r.headers["content-type"].startswith("application/problem+json") async def test_rename_and_rename_conflict(client, auth_headers): first = (await client.post(URL, json={"name": "Один"}, headers=auth_headers)).json() await client.post(URL, json={"name": "Два"}, headers=auth_headers) r = await client.patch( f"{URL}/{first['id']}", json={"name": "Один и один"}, headers=auth_headers ) assert r.status_code == 200 assert r.json()["name"] == "Один и один" r = await client.patch(f"{URL}/{first['id']}", json={"name": "Два"}, headers=auth_headers) assert r.status_code == 409 r = await client.patch( f"{URL}/{first['id']}", json={"name": "Один и один"}, headers=auth_headers ) assert r.status_code == 200 # keeping its own name is not a conflict async def test_blank_name_is_rejected(client, auth_headers): r = await client.post(URL, json={"name": " "}, headers=auth_headers) assert r.status_code == 400 async def test_unknown_account_is_rejected_and_nothing_is_saved(client, auth_headers): real = await make_account(name="Брокер") r = await client.post( URL, json={"name": "Х", "account_ids": [real, 99999]}, headers=auth_headers ) assert r.status_code == 400 assert "99999" in r.json()["detail"] assert (await client.get(URL, headers=auth_headers)).json() == [] created = ( await client.post(URL, json={"name": "Х", "account_ids": [real]}, headers=auth_headers) ).json() r = await client.put( f"{URL}/{created['id']}/accounts", json={"account_ids": [99999]}, headers=auth_headers ) assert r.status_code == 400 listed = (await client.get(URL, headers=auth_headers)).json() assert listed[0]["account_ids"] == [real] async def test_delete_removes_the_portfolio_but_not_its_accounts(client, auth_headers): a = await make_account(name="Брокер") created = ( await client.post(URL, json={"name": "Х", "account_ids": [a]}, headers=auth_headers) ).json() r = await client.delete(f"{URL}/{created['id']}", headers=auth_headers) assert r.status_code == 204 assert (await client.get(URL, headers=auth_headers)).json() == [] accounts = (await client.get("/api/v1/accounts", headers=auth_headers)).json() assert [x["id"] for x in accounts] == [a] async def test_missing_portfolio_is_404(client, auth_headers): assert ( await client.patch(f"{URL}/999", json={"name": "Х"}, headers=auth_headers) ).status_code == 404 assert ( await client.put(f"{URL}/999/accounts", json={"account_ids": []}, headers=auth_headers) ).status_code == 404 assert (await client.delete(f"{URL}/999", headers=auth_headers)).status_code == 404