Newer
Older
from unittest.mock import patch
from uuid import uuid4
import pytest
from orchestrator.db import SubscriptionTable
from orchestrator.services import subscriptions
from gso.products.product_blocks.iptrunk import IptrunkType, PhysicalPortCapacity
from gso.products.product_blocks.router import RouterRole
from gso.products.product_blocks.site import SiteTier
from gso.utils.helpers import iso_from_ipv4
from gso.utils.shared_enums import Vendor
SITE_IMPORT_ENDPOINT = "/api/v1/imports/sites"
ROUTER_IMPORT_ENDPOINT = "/api/v1/imports/routers"
IPTRUNK_IMPORT_API_URL = "/api/v1/imports/iptrunks"
SUPER_POP_SWITCH_IMPORT_API_URL = "/api/v1/imports/super-pop-switches"
OFFICE_ROUTER_IMPORT_API_URL = "/api/v1/imports/office-routers"
Karel van Klink
committed
@pytest.fixture()
def iptrunk_data(nokia_router_subscription_factory, faker):
router_side_a = nokia_router_subscription_factory()
router_side_b = nokia_router_subscription_factory()
"geant_s_sid": faker.geant_sid(),
"iptrunk_speed": PhysicalPortCapacity.HUNDRED_GIGABIT_PER_SECOND,
"iptrunk_isis_metric": 500,
Karel van Klink
committed
"side_a_node_id": router_side_a,
"side_a_ae_iface": faker.network_interface(),
"side_a_ae_geant_a_sid": faker.geant_sid(),
Karel van Klink
committed
"side_a_ae_members": [
Karel van Klink
committed
{
"interface_name": faker.network_interface(),
"interface_description": faker.sentence(),
}
for _ in range(5)
Karel van Klink
committed
],
"side_b_node_id": router_side_b,
"side_b_ae_iface": faker.network_interface(),
"side_b_ae_geant_a_sid": faker.geant_sid(),
Karel van Klink
committed
"side_b_ae_members": [
Karel van Klink
committed
{
"interface_name": faker.network_interface(),
"interface_description": faker.sentence(),
}
for _ in range(5)
Karel van Klink
committed
],
"iptrunk_ipv4_network": str(faker.ipv4(network=True)),
"iptrunk_ipv6_network": str(faker.ipv6(network=True)),
Karel van Klink
committed
@pytest.fixture()
with patch("gso.services.subscriptions.get_active_router_subscriptions") as mock_get_active_router_subscriptions:
def _active_router_subscriptions(*args, **kwargs):
if kwargs["includes"] == ["subscription_id", "description"]:
{
"subscription_id": iptrunk_data["side_a_node_id"],
"description": "iptrunk_sideA_node_id description",
},
{
"subscription_id": iptrunk_data["side_b_node_id"],
"description": "iptrunk_sideB_node_id description",
},
Karel van Klink
committed
{
"subscription_id": str(uuid4()),
"description": "random description",
},
return [
{"subscription_id": iptrunk_data["side_a_node_id"]},
{"subscription_id": iptrunk_data["side_b_node_id"]},
{"subscription_id": str(uuid4())},
]
mock_get_active_router_subscriptions.side_effect = _active_router_subscriptions
yield mock_get_active_router_subscriptions
@patch("gso.api.v1.imports._start_process")
def test_import_iptrunk_successful_with_mocked_process(mock_start_process, test_client, mock_routers, iptrunk_data):
mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
assert response.status_code == 201
assert response.json()["pid"] == "123e4567-e89b-12d3-a456-426655440000"
Karel van Klink
committed
@pytest.fixture()
"site_name": faker.site_name(),
"site_city": faker.city(),
"site_country": faker.country(),
"site_country_code": faker.country_code(),
"site_latitude": float(faker.latitude()),
"site_longitude": float(faker.longitude()),
"site_bgp_community_id": faker.pyint(),
"site_internal_id": faker.pyint(),
"site_tier": SiteTier.TIER1,
"site_ts_address": faker.ipv4(),
Karel van Klink
committed
@pytest.fixture()
mock_ipv4 = faker.ipv4()
return {
"hostname": "127.0.0.1",
"router_role": RouterRole.PE,
"router_vendor": Vendor.JUNIPER,
"router_site": site_data["site_name"],
"ts_port": 1234,
"router_lo_ipv4_address": mock_ipv4,
"router_lo_iso_address": iso_from_ipv4(mock_ipv4),
@pytest.fixture()
def super_pop_switch_data(faker, site_data):
mock_ipv4 = faker.ipv4()
return {
"hostname": "127.0.0.1",
"super_pop_switch_site": site_data["site_name"],
"super_pop_switch_ts_port": 1234,
"super_pop_switch_mgmt_ipv4_address": mock_ipv4,
}
@pytest.fixture()
def office_router_data(faker, site_data):
return {
"office_router_fqdn": "127.0.0.1",
"office_router_site": site_data["site_name"],
"office_router_ts_port": 1234,
"office_router_lo_ipv4_address": faker.ipv4(),
"office_router_lo_ipv6_address": faker.ipv6(),
}
def test_import_site_endpoint(test_client, site_data):
assert SubscriptionTable.query.all() == []
# Post data to the endpoint
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
assert response.status_code == 201
assert "detail" in response.json()
assert "pid" in response.json()
subscription = subscriptions.retrieve_subscription_by_subscription_instance_value(
Karel van Klink
committed
resource_type="site_name",
value=site_data["site_name"],
)
assert subscription is not None
def test_import_site_endpoint_with_existing_site(test_client, site_data):
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
assert SubscriptionTable.query.count() == 1
assert response.status_code == 201
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
assert SubscriptionTable.query.count() == 1
def test_import_site_endpoint_with_invalid_data(test_client, site_data):
# invalid data, missing site_latitude and invalid site_longitude
site_data.pop("site_latitude")
site_data["site_longitude"] = "invalid"
assert SubscriptionTable.query.count() == 0
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
assert response.status_code == 422
assert SubscriptionTable.query.count() == 0
response = response.json()
assert response["detail"][0]["loc"] == ["body", "site_latitude"]
assert response["detail"][0]["msg"] == "field required"
assert response["detail"][1]["loc"] == ["body", "site_longitude"]
assert response["detail"][1]["msg"] == "value is not a valid float"
def test_import_router_endpoint(test_client, site_data, router_data):
# Create a site first
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
assert response.status_code == 201
assert SubscriptionTable.query.count() == 1
response = test_client.post(ROUTER_IMPORT_ENDPOINT, json=router_data)
assert response.status_code == 201
assert SubscriptionTable.query.count() == 2
def test_import_router_endpoint_with_invalid_data(test_client, site_data, router_data):
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
assert response.status_code == 201
assert SubscriptionTable.query.count() == 1
# invalid data, missing hostname and invalid router_lo_ipv6_address
router_data.pop("hostname")
router_data["router_lo_ipv6_address"] = "invalid"
response = test_client.post(ROUTER_IMPORT_ENDPOINT, json=router_data)
assert response.status_code == 422
assert SubscriptionTable.query.count() == 1
response = response.json()
assert response["detail"][0]["loc"] == ["body", "hostname"]
assert response["detail"][0]["msg"] == "field required"
assert response["detail"][1]["loc"] == ["body", "router_lo_ipv6_address"]
assert response["detail"][1]["msg"] == "value is not a valid IPv6 address"
def test_import_iptrunk_successful_with_real_process(test_client, mock_routers, iptrunk_data):
response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
assert response.status_code == 201
response = response.json()
assert "detail" in response
assert "pid" in response
subscription = subscriptions.retrieve_subscription_by_subscription_instance_value(
Karel van Klink
committed
resource_type="geant_s_sid",
value=iptrunk_data["geant_s_sid"],
)
assert subscription is not None
@patch("gso.api.v1.imports._start_process")
def test_import_iptrunk_invalid_partner(mock_start_process, test_client, mock_routers, iptrunk_data):
iptrunk_data["partner"] = "not_existing_partner"
mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
assert response.status_code == 422
assert response.json() == {
"detail": [
Karel van Klink
committed
{
"loc": ["body", "partner"],
"msg": "partner not_existing_partner not found",
Karel van Klink
committed
"type": "value_error",
},
],
}
@patch("gso.api.v1.imports._start_process")
def test_import_iptrunk_invalid_router_id_side_a_and_b(mock_start_process, test_client, iptrunk_data):
iptrunk_data["side_a_node_id"] = "NOT FOUND"
iptrunk_data["side_b_node_id"] = "NOT FOUND"
mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"loc": ["body", "side_a_node_id"],
"msg": f"Router {iptrunk_data['side_a_node_id']} not found",
"type": "value_error",
},
{
"loc": ["body", "side_b_node_id"],
"msg": f"Router {iptrunk_data['side_b_node_id']} not found",
"type": "value_error",
},
Karel van Klink
committed
],
}
@patch("gso.api.v1.imports._start_process")
def test_import_iptrunk_non_unique_members_side_a(mock_start_process, test_client, mock_routers, iptrunk_data, faker):
mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
Karel van Klink
committed
repeat_interface_a = {
"interface_name": faker.network_interface(),
"interface_description": faker.sentence(),
}
repeat_interface_b = {
"interface_name": faker.network_interface(),
"interface_description": faker.sentence(),
}
iptrunk_data["side_a_ae_members"] = [repeat_interface_a for _ in range(5)]
iptrunk_data["side_b_ae_members"] = [repeat_interface_b for _ in range(5)]
response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
assert response.status_code == 422
assert response.json() == {
"detail": [
Karel van Klink
committed
{
"loc": ["body", "side_a_ae_members"],
"msg": "Items must be unique",
"type": "value_error",
},
{
"loc": ["body", "side_b_ae_members"],
"msg": "Items must be unique",
"type": "value_error",
},
{
"loc": ["body", "__root__"],
"msg": "Side A members should be at least 5 (iptrunk_minimum_links)",
"type": "value_error",
},
Karel van Klink
committed
],
}
@patch("gso.api.v1.imports._start_process")
Karel van Klink
committed
def test_import_iptrunk_fails_on_side_a_member_count_mismatch(
Karel van Klink
committed
mock_start_process,
test_client,
mock_routers,
iptrunk_data,
):
mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
Karel van Klink
committed
iptrunk_data["side_a_ae_members"].remove(iptrunk_data["side_a_ae_members"][0])
response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
assert response.status_code == 422
assert response.json() == {
"detail": [
{
"loc": ["body", "__root__"],
"msg": "Side A members should be at least 5 (iptrunk_minimum_links)",
"type": "value_error",
Karel van Klink
committed
},
],
}
@patch("gso.api.v1.imports._start_process")
Karel van Klink
committed
def test_import_iptrunk_fails_on_side_a_and_b_members_mismatch(
Karel van Klink
committed
mock_start_process,
test_client,
iptrunk_data,
mock_routers,
):
mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
Karel van Klink
committed
iptrunk_data["side_b_ae_members"].remove(iptrunk_data["side_b_ae_members"][0])
response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
assert response.status_code == 422
assert response.json() == {
Karel van Klink
committed
"detail": [
{
"loc": ["body", "__root__"],
"msg": "Mismatch between Side A and B members",
"type": "value_error",
},
],
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
def test_import_super_pop_switch_endpoint(test_client, site_data, super_pop_switch_data):
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
assert response.status_code == 201
assert SubscriptionTable.query.count() == 1
response = test_client.post(SUPER_POP_SWITCH_IMPORT_API_URL, json=super_pop_switch_data)
assert response.status_code == 201
assert SubscriptionTable.query.count() == 2
def test_import_super_pop_switch_endpoint_with_invalid_data(test_client, site_data, super_pop_switch_data):
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
assert response.status_code == 201
assert SubscriptionTable.query.count() == 1
# invalid data, missing hostname and invalid mgmt_ipv4_address
super_pop_switch_data.pop("hostname")
super_pop_switch_data["super_pop_switch_mgmt_ipv4_address"] = "invalid"
response = test_client.post(SUPER_POP_SWITCH_IMPORT_API_URL, json=super_pop_switch_data)
assert response.status_code == 422
assert SubscriptionTable.query.count() == 1
response = response.json()
assert response["detail"][0]["loc"] == ["body", "hostname"]
assert response["detail"][0]["msg"] == "field required"
assert response["detail"][1]["loc"] == ["body", "super_pop_switch_mgmt_ipv4_address"]
assert response["detail"][1]["msg"] == "value is not a valid IPv4 address"
def test_import_office_router_endpoint(test_client, site_data, office_router_data):
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
assert response.status_code == 201
assert SubscriptionTable.query.count() == 1
response = test_client.post(OFFICE_ROUTER_IMPORT_API_URL, json=office_router_data)
assert response.status_code == 201
assert SubscriptionTable.query.count() == 2
def test_import_office_router_endpoint_with_invalid_data(test_client, site_data, office_router_data):
response = test_client.post(SITE_IMPORT_ENDPOINT, json=site_data)
assert response.status_code == 201
assert SubscriptionTable.query.count() == 1
# invalid data, missing FQDN and invalid lo_ipv6_address
office_router_data.pop("office_router_fqdn")
office_router_data["office_router_lo_ipv6_address"] = "invalid"
response = test_client.post(OFFICE_ROUTER_IMPORT_API_URL, json=office_router_data)
assert response.status_code == 422
assert SubscriptionTable.query.count() == 1
response = response.json()
assert response["detail"][0]["loc"] == ["body", "office_router_fqdn"]
assert response["detail"][0]["msg"] == "field required"
assert response["detail"][1]["loc"] == ["body", "office_router_lo_ipv6_address"]
assert response["detail"][1]["msg"] == "value is not a valid IPv6 address"