Add display name field #331
4 changed files with 151 additions and 128 deletions
|
|
@ -18,6 +18,7 @@ from servala.core.models.service import (
|
||||||
Service,
|
Service,
|
||||||
ServiceCategory,
|
ServiceCategory,
|
||||||
ServiceDefinition,
|
ServiceDefinition,
|
||||||
|
ServiceInstance,
|
||||||
ServiceOffering,
|
ServiceOffering,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -75,7 +76,7 @@ def user():
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_service_category():
|
def service_category():
|
||||||
return ServiceCategory.objects.create(
|
return ServiceCategory.objects.create(
|
||||||
name="Databases",
|
name="Databases",
|
||||||
description="Database services",
|
description="Database services",
|
||||||
|
|
@ -83,18 +84,18 @@ def test_service_category():
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_service(test_service_category):
|
def service(service_category):
|
||||||
return Service.objects.create(
|
return Service.objects.create(
|
||||||
name="Redis",
|
name="Redis",
|
||||||
slug="redis",
|
slug="redis",
|
||||||
category=test_service_category,
|
category=service_category,
|
||||||
description="Redis database service",
|
description="Redis database service",
|
||||||
osb_service_id="test-service-123",
|
osb_service_id="test-service-123",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_cloud_provider():
|
def cloud_provider():
|
||||||
return CloudProvider.objects.create(
|
return CloudProvider.objects.create(
|
||||||
name="Exoscale",
|
name="Exoscale",
|
||||||
description="Exoscale cloud provider",
|
description="Exoscale cloud provider",
|
||||||
|
|
@ -102,10 +103,10 @@ def test_cloud_provider():
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_service_offering(test_service, test_cloud_provider):
|
def service_offering(service, cloud_provider):
|
||||||
return ServiceOffering.objects.create(
|
return ServiceOffering.objects.create(
|
||||||
service=test_service,
|
service=service,
|
||||||
provider=test_cloud_provider,
|
provider=cloud_provider,
|
||||||
description="Redis on Exoscale",
|
description="Redis on Exoscale",
|
||||||
osb_plan_id="test-plan-123",
|
osb_plan_id="test-plan-123",
|
||||||
)
|
)
|
||||||
|
|
@ -148,11 +149,11 @@ def mock_odoo_failure(mocker):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_control_plane(test_cloud_provider):
|
def control_plane(cloud_provider):
|
||||||
return ControlPlane.objects.create(
|
return ControlPlane.objects.create(
|
||||||
name="Geneva (CH-GVA-2)",
|
name="Geneva (CH-GVA-2)",
|
||||||
description="Geneva control plane",
|
description="Geneva control plane",
|
||||||
cloud_provider=test_cloud_provider,
|
cloud_provider=cloud_provider,
|
||||||
api_credentials={
|
api_credentials={
|
||||||
"server": "https://k8s.example.com",
|
"server": "https://k8s.example.com",
|
||||||
"token": "test-token",
|
"token": "test-token",
|
||||||
|
|
@ -162,10 +163,10 @@ def test_control_plane(test_cloud_provider):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_service_definition(test_service):
|
def service_definition(service):
|
||||||
return ServiceDefinition.objects.create(
|
return ServiceDefinition.objects.create(
|
||||||
name="Redis Standard",
|
name="Redis Standard",
|
||||||
service=test_service,
|
service=service,
|
||||||
api_definition={
|
api_definition={
|
||||||
"group": "vshn.appcat.vshn.io",
|
"group": "vshn.appcat.vshn.io",
|
||||||
"version": "v1",
|
"version": "v1",
|
||||||
|
|
@ -175,13 +176,11 @@ def test_service_definition(test_service):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_control_plane_crd(
|
def control_plane_crd(service_offering, control_plane, service_definition):
|
||||||
test_service_offering, test_control_plane, test_service_definition
|
|
||||||
):
|
|
||||||
return ControlPlaneCRD.objects.create(
|
return ControlPlaneCRD.objects.create(
|
||||||
service_offering=test_service_offering,
|
service_offering=service_offering,
|
||||||
control_plane=test_control_plane,
|
control_plane=control_plane,
|
||||||
service_definition=test_service_definition,
|
service_definition=service_definition,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -199,10 +198,10 @@ def compute_plan():
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def compute_plan_assignment(compute_plan, test_control_plane_crd):
|
def compute_plan_assignment(compute_plan, control_plane_crd):
|
||||||
return ComputePlanAssignment.objects.create(
|
return ComputePlanAssignment.objects.create(
|
||||||
compute_plan=compute_plan,
|
compute_plan=compute_plan,
|
||||||
control_plane_crd=test_control_plane_crd,
|
control_plane_crd=control_plane_crd,
|
||||||
sla="besteffort",
|
sla="besteffort",
|
||||||
odoo_product_id="test-product-id",
|
odoo_product_id="test-product-id",
|
||||||
odoo_unit_id="test-unit-id",
|
odoo_unit_id="test-unit-id",
|
||||||
|
|
@ -210,3 +209,30 @@ def compute_plan_assignment(compute_plan, test_control_plane_crd):
|
||||||
unit="hour",
|
unit="hour",
|
||||||
is_active=True,
|
is_active=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def service_instance(organization, control_plane_crd):
|
||||||
|
return ServiceInstance.objects.create(
|
||||||
|
name="test-abc12345",
|
||||||
|
display_name="My Test Instance",
|
||||||
|
organization=organization,
|
||||||
|
context=control_plane_crd,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def control_plane_with_storage(cloud_provider):
|
||||||
|
return ControlPlane.objects.create(
|
||||||
|
name="Storage Zone",
|
||||||
|
description="Zone with storage billing",
|
||||||
|
cloud_provider=cloud_provider,
|
||||||
|
api_credentials={
|
||||||
|
"server": "https://k8s.example.com",
|
||||||
|
"token": "test-token",
|
||||||
|
"certificate-authority-data": "test-ca-data",
|
||||||
|
},
|
||||||
|
storage_plan_odoo_product_id="storage-product-123",
|
||||||
|
storage_plan_odoo_unit_id="storage-unit-456",
|
||||||
|
storage_plan_price_per_gib="0.10",
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,14 @@ def valid_osb_payload():
|
||||||
def test_successful_onboarding_new_organization(
|
def test_successful_onboarding_new_organization(
|
||||||
mock_odoo_success,
|
mock_odoo_success,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
valid_osb_payload,
|
valid_osb_payload,
|
||||||
exoscale_origin,
|
exoscale_origin,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
|
|
||||||
response = osb_client.put(
|
response = osb_client.put(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}",
|
f"/api/osb/v2/service_instances/{instance_id}",
|
||||||
|
|
@ -107,15 +107,15 @@ def test_successful_onboarding_new_organization(
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_new_organization_inherits_origin(
|
def test_new_organization_inherits_origin(
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
valid_osb_payload,
|
valid_osb_payload,
|
||||||
exoscale_origin,
|
exoscale_origin,
|
||||||
instance_id,
|
instance_id,
|
||||||
billing_entity,
|
billing_entity,
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
exoscale_origin.billing_entity = billing_entity
|
exoscale_origin.billing_entity = billing_entity
|
||||||
exoscale_origin.save()
|
exoscale_origin.save()
|
||||||
|
|
||||||
|
|
@ -137,8 +137,8 @@ def test_new_organization_inherits_origin(
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_duplicate_organization_returns_existing(
|
def test_duplicate_organization_returns_existing(
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
valid_osb_payload,
|
valid_osb_payload,
|
||||||
exoscale_origin,
|
exoscale_origin,
|
||||||
instance_id,
|
instance_id,
|
||||||
|
|
@ -148,10 +148,10 @@ def test_duplicate_organization_returns_existing(
|
||||||
osb_guid="test-org-guid-123",
|
osb_guid="test-org-guid-123",
|
||||||
origin=exoscale_origin,
|
origin=exoscale_origin,
|
||||||
)
|
)
|
||||||
org.limit_osb_services.add(test_service)
|
org.limit_osb_services.add(service)
|
||||||
|
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
|
|
||||||
response = osb_client.put(
|
response = osb_client.put(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}",
|
f"/api/osb/v2/service_instances/{instance_id}",
|
||||||
|
|
@ -169,13 +169,13 @@ def test_duplicate_organization_returns_existing(
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_unauthenticated_osb_api_request_fails(
|
def test_unauthenticated_osb_api_request_fails(
|
||||||
client,
|
client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
valid_osb_payload,
|
valid_osb_payload,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
|
|
||||||
response = client.put(
|
response = client.put(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}",
|
f"/api/osb/v2/service_instances/{instance_id}",
|
||||||
|
|
@ -205,15 +205,15 @@ def test_unauthenticated_osb_api_request_fails(
|
||||||
)
|
)
|
||||||
def test_missing_required_fields_error(
|
def test_missing_required_fields_error(
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
valid_osb_payload,
|
valid_osb_payload,
|
||||||
field_to_remove,
|
field_to_remove,
|
||||||
expected_error,
|
expected_error,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
|
|
||||||
if isinstance(field_to_remove, tuple):
|
if isinstance(field_to_remove, tuple):
|
||||||
if field_to_remove[0] == "context":
|
if field_to_remove[0] == "context":
|
||||||
|
|
@ -251,10 +251,8 @@ def test_invalid_service_id_error(osb_client, valid_osb_payload, instance_id):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_invalid_plan_id_error(
|
def test_invalid_plan_id_error(osb_client, service, valid_osb_payload, instance_id):
|
||||||
osb_client, test_service, valid_osb_payload, instance_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
):
|
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
|
||||||
valid_osb_payload["plan_id"] = 99999
|
valid_osb_payload["plan_id"] = 99999
|
||||||
|
|
||||||
response = osb_client.put(
|
response = osb_client.put(
|
||||||
|
|
@ -266,17 +264,17 @@ def test_invalid_plan_id_error(
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
response_data = json.loads(response.content)
|
response_data = json.loads(response.content)
|
||||||
assert (
|
assert (
|
||||||
f"Unknown plan_id: 99999 for service_id: {test_service.osb_service_id}"
|
f"Unknown plan_id: 99999 for service_id: {service.osb_service_id}"
|
||||||
in response_data["error"]
|
in response_data["error"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_empty_users_array_error(
|
def test_empty_users_array_error(
|
||||||
osb_client, test_service, test_service_offering, valid_osb_payload, instance_id
|
osb_client, service, service_offering, valid_osb_payload, instance_id
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
valid_osb_payload["parameters"]["users"] = []
|
valid_osb_payload["parameters"]["users"] = []
|
||||||
|
|
||||||
response = osb_client.put(
|
response = osb_client.put(
|
||||||
|
|
@ -292,10 +290,10 @@ def test_empty_users_array_error(
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_multiple_users_error(
|
def test_multiple_users_error(
|
||||||
osb_client, test_service, test_service_offering, valid_osb_payload, instance_id
|
osb_client, service, service_offering, valid_osb_payload, instance_id
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
valid_osb_payload["parameters"]["users"] = [
|
valid_osb_payload["parameters"]["users"] = [
|
||||||
{"email": "user1@example.com", "full_name": "User One"},
|
{"email": "user1@example.com", "full_name": "User One"},
|
||||||
{"email": "user2@example.com", "full_name": "User Two"},
|
{"email": "user2@example.com", "full_name": "User Two"},
|
||||||
|
|
@ -314,10 +312,10 @@ def test_multiple_users_error(
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_empty_email_address_error(
|
def test_empty_email_address_error(
|
||||||
osb_client, test_service, test_service_offering, valid_osb_payload, instance_id
|
osb_client, service, service_offering, valid_osb_payload, instance_id
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
valid_osb_payload["parameters"]["users"] = [
|
valid_osb_payload["parameters"]["users"] = [
|
||||||
{"email": "", "full_name": "User With No Email"},
|
{"email": "", "full_name": "User With No Email"},
|
||||||
]
|
]
|
||||||
|
|
@ -350,14 +348,14 @@ def test_invalid_json_error(osb_client, instance_id):
|
||||||
def test_user_creation_with_name_parsing(
|
def test_user_creation_with_name_parsing(
|
||||||
mock_odoo_success,
|
mock_odoo_success,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
valid_osb_payload,
|
valid_osb_payload,
|
||||||
exoscale_origin,
|
exoscale_origin,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
valid_osb_payload["parameters"]["users"][0]["full_name"] = "John Doe Smith"
|
valid_osb_payload["parameters"]["users"][0]["full_name"] = "John Doe Smith"
|
||||||
|
|
||||||
response = osb_client.put(
|
response = osb_client.put(
|
||||||
|
|
@ -376,14 +374,14 @@ def test_user_creation_with_name_parsing(
|
||||||
def test_email_normalization(
|
def test_email_normalization(
|
||||||
mock_odoo_success,
|
mock_odoo_success,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
valid_osb_payload,
|
valid_osb_payload,
|
||||||
exoscale_origin,
|
exoscale_origin,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
valid_osb_payload["parameters"]["users"][0]["email"] = " TEST@EXAMPLE.COM "
|
valid_osb_payload["parameters"]["users"][0]["email"] = " TEST@EXAMPLE.COM "
|
||||||
|
|
||||||
response = osb_client.put(
|
response = osb_client.put(
|
||||||
|
|
@ -401,14 +399,14 @@ def test_email_normalization(
|
||||||
def test_odoo_integration_failure_handling(
|
def test_odoo_integration_failure_handling(
|
||||||
mock_odoo_failure,
|
mock_odoo_failure,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
valid_osb_payload,
|
valid_osb_payload,
|
||||||
exoscale_origin,
|
exoscale_origin,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
valid_osb_payload["service_id"] = test_service.osb_service_id
|
valid_osb_payload["service_id"] = service.osb_service_id
|
||||||
valid_osb_payload["plan_id"] = test_service_offering.osb_plan_id
|
valid_osb_payload["plan_id"] = service_offering.osb_plan_id
|
||||||
|
|
||||||
response = osb_client.put(
|
response = osb_client.put(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}",
|
f"/api/osb/v2/service_instances/{instance_id}",
|
||||||
|
|
@ -425,14 +423,14 @@ def test_odoo_integration_failure_handling(
|
||||||
def test_organization_creation_with_context_only(
|
def test_organization_creation_with_context_only(
|
||||||
mock_odoo_success,
|
mock_odoo_success,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
exoscale_origin,
|
exoscale_origin,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
payload = {
|
payload = {
|
||||||
"service_id": test_service.osb_service_id,
|
"service_id": service.osb_service_id,
|
||||||
"plan_id": test_service_offering.osb_plan_id,
|
"plan_id": service_offering.osb_plan_id,
|
||||||
"context": {
|
"context": {
|
||||||
"organization_guid": "fallback-org-guid",
|
"organization_guid": "fallback-org-guid",
|
||||||
"organization_name": "Fallback Organization",
|
"organization_name": "Fallback Organization",
|
||||||
|
|
@ -462,13 +460,13 @@ def test_organization_creation_with_context_only(
|
||||||
def test_delete_offboarding_success(
|
def test_delete_offboarding_success(
|
||||||
mock_odoo_success,
|
mock_odoo_success,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
response = osb_client.delete(
|
response = osb_client.delete(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}"
|
f"/api/osb/v2/service_instances/{instance_id}"
|
||||||
f"?service_id={test_service.osb_service_id}&plan_id={test_service_offering.osb_plan_id}"
|
f"?service_id={service.osb_service_id}&plan_id={service_offering.osb_plan_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
@ -476,9 +474,9 @@ def test_delete_offboarding_success(
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_delete_missing_service_id(osb_client, test_service_offering, instance_id):
|
def test_delete_missing_service_id(osb_client, service_offering, instance_id):
|
||||||
response = osb_client.delete(
|
response = osb_client.delete(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}?plan_id={test_service_offering.osb_plan_id}"
|
f"/api/osb/v2/service_instances/{instance_id}?plan_id={service_offering.osb_plan_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
@ -487,9 +485,9 @@ def test_delete_missing_service_id(osb_client, test_service_offering, instance_i
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_delete_missing_plan_id(osb_client, test_service, instance_id):
|
def test_delete_missing_plan_id(osb_client, service, instance_id):
|
||||||
response = osb_client.delete(
|
response = osb_client.delete(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}?service_id={test_service.osb_service_id}"
|
f"/api/osb/v2/service_instances/{instance_id}?service_id={service.osb_service_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
@ -509,16 +507,16 @@ def test_delete_invalid_service_id(osb_client, instance_id):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_delete_invalid_plan_id(osb_client, test_service, instance_id):
|
def test_delete_invalid_plan_id(osb_client, service, instance_id):
|
||||||
response = osb_client.delete(
|
response = osb_client.delete(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}"
|
f"/api/osb/v2/service_instances/{instance_id}"
|
||||||
f"?service_id={test_service.osb_service_id}&plan_id=invalid"
|
f"?service_id={service.osb_service_id}&plan_id=invalid"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
response_data = json.loads(response.content)
|
response_data = json.loads(response.content)
|
||||||
assert (
|
assert (
|
||||||
f"Unknown plan_id: invalid for service_id: {test_service.osb_service_id}"
|
f"Unknown plan_id: invalid for service_id: {service.osb_service_id}"
|
||||||
in response_data["error"]
|
in response_data["error"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -527,13 +525,13 @@ def test_delete_invalid_plan_id(osb_client, test_service, instance_id):
|
||||||
def test_patch_suspension_success(
|
def test_patch_suspension_success(
|
||||||
mock_odoo_success,
|
mock_odoo_success,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
payload = {
|
payload = {
|
||||||
"service_id": test_service.osb_service_id,
|
"service_id": service.osb_service_id,
|
||||||
"plan_id": test_service_offering.osb_plan_id,
|
"plan_id": service_offering.osb_plan_id,
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
|
|
@ -556,9 +554,9 @@ def test_patch_suspension_success(
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_patch_missing_service_id(osb_client, test_service_offering, instance_id):
|
def test_patch_missing_service_id(osb_client, service_offering, instance_id):
|
||||||
payload = {
|
payload = {
|
||||||
"plan_id": test_service_offering.osb_plan_id,
|
"plan_id": service_offering.osb_plan_id,
|
||||||
"parameters": {"users": []},
|
"parameters": {"users": []},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -574,9 +572,9 @@ def test_patch_missing_service_id(osb_client, test_service_offering, instance_id
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_patch_missing_plan_id(osb_client, test_service, instance_id):
|
def test_patch_missing_plan_id(osb_client, service, instance_id):
|
||||||
payload = {
|
payload = {
|
||||||
"service_id": test_service.osb_service_id,
|
"service_id": service.osb_service_id,
|
||||||
"parameters": {"users": []},
|
"parameters": {"users": []},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -609,8 +607,8 @@ def test_delete_creates_ticket_with_admin_links(
|
||||||
mocker,
|
mocker,
|
||||||
mock_odoo_success,
|
mock_odoo_success,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
instance_id,
|
instance_id,
|
||||||
):
|
):
|
||||||
# Mock the create_helpdesk_ticket function
|
# Mock the create_helpdesk_ticket function
|
||||||
|
|
@ -618,7 +616,7 @@ def test_delete_creates_ticket_with_admin_links(
|
||||||
|
|
||||||
response = osb_client.delete(
|
response = osb_client.delete(
|
||||||
f"/api/osb/v2/service_instances/{instance_id}"
|
f"/api/osb/v2/service_instances/{instance_id}"
|
||||||
f"?service_id={test_service.osb_service_id}&plan_id={test_service_offering.osb_plan_id}"
|
f"?service_id={service.osb_service_id}&plan_id={service_offering.osb_plan_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
@ -629,10 +627,10 @@ def test_delete_creates_ticket_with_admin_links(
|
||||||
|
|
||||||
# Check that the description contains an admin URL
|
# Check that the description contains an admin URL
|
||||||
assert "admin/core/serviceoffering" in call_kwargs["description"]
|
assert "admin/core/serviceoffering" in call_kwargs["description"]
|
||||||
assert f"/{test_service_offering.pk}/" in call_kwargs["description"]
|
assert f"/{service_offering.pk}/" in call_kwargs["description"]
|
||||||
assert (
|
assert (
|
||||||
call_kwargs["title"]
|
call_kwargs["title"]
|
||||||
== f"Exoscale OSB Offboard - {test_service.name} - {instance_id}"
|
== f"Exoscale OSB Offboard - {service.name} - {instance_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -641,8 +639,8 @@ def test_patch_creates_ticket_with_user_admin_links(
|
||||||
mocker,
|
mocker,
|
||||||
mock_odoo_success,
|
mock_odoo_success,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
instance_id,
|
instance_id,
|
||||||
org_owner,
|
org_owner,
|
||||||
):
|
):
|
||||||
|
|
@ -650,8 +648,8 @@ def test_patch_creates_ticket_with_user_admin_links(
|
||||||
mock_create_ticket = mocker.patch("servala.api.views.create_helpdesk_ticket")
|
mock_create_ticket = mocker.patch("servala.api.views.create_helpdesk_ticket")
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
"service_id": test_service.osb_service_id,
|
"service_id": service.osb_service_id,
|
||||||
"plan_id": test_service_offering.osb_plan_id,
|
"plan_id": service_offering.osb_plan_id,
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"users": [
|
"users": [
|
||||||
{
|
{
|
||||||
|
|
@ -680,8 +678,7 @@ def test_patch_creates_ticket_with_user_admin_links(
|
||||||
assert "admin/core/user" in call_kwargs["description"]
|
assert "admin/core/user" in call_kwargs["description"]
|
||||||
assert f"/{org_owner.pk}/" in call_kwargs["description"]
|
assert f"/{org_owner.pk}/" in call_kwargs["description"]
|
||||||
assert (
|
assert (
|
||||||
call_kwargs["title"]
|
call_kwargs["title"] == f"Exoscale OSB Suspend - {service.name} - {instance_id}"
|
||||||
== f"Exoscale OSB Suspend - {test_service.name} - {instance_id}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -690,8 +687,8 @@ def test_ticket_includes_organization_and_instance_when_found(
|
||||||
mocker,
|
mocker,
|
||||||
mock_odoo_success,
|
mock_odoo_success,
|
||||||
osb_client,
|
osb_client,
|
||||||
test_service,
|
service,
|
||||||
test_service_offering,
|
service_offering,
|
||||||
organization,
|
organization,
|
||||||
):
|
):
|
||||||
# Mock the create_helpdesk_ticket function
|
# Mock the create_helpdesk_ticket function
|
||||||
|
|
@ -699,12 +696,12 @@ def test_ticket_includes_organization_and_instance_when_found(
|
||||||
|
|
||||||
service_definition = ServiceDefinition.objects.create(
|
service_definition = ServiceDefinition.objects.create(
|
||||||
name="Test Definition",
|
name="Test Definition",
|
||||||
service=test_service,
|
service=service,
|
||||||
api_definition={"group": "test.example.com", "version": "v1", "kind": "Test"},
|
api_definition={"group": "test.example.com", "version": "v1", "kind": "Test"},
|
||||||
)
|
)
|
||||||
control_plane = ControlPlane.objects.create(
|
control_plane = ControlPlane.objects.create(
|
||||||
name="Test Control Plane",
|
name="Test Control Plane",
|
||||||
cloud_provider=test_service_offering.provider,
|
cloud_provider=service_offering.provider,
|
||||||
api_credentials={
|
api_credentials={
|
||||||
"certificate-authority-data": "test",
|
"certificate-authority-data": "test",
|
||||||
"server": "https://test",
|
"server": "https://test",
|
||||||
|
|
@ -712,7 +709,7 @@ def test_ticket_includes_organization_and_instance_when_found(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
crd = ControlPlaneCRD.objects.create(
|
crd = ControlPlaneCRD.objects.create(
|
||||||
service_offering=test_service_offering,
|
service_offering=service_offering,
|
||||||
control_plane=control_plane,
|
control_plane=control_plane,
|
||||||
service_definition=service_definition,
|
service_definition=service_definition,
|
||||||
)
|
)
|
||||||
|
|
@ -727,7 +724,7 @@ def test_ticket_includes_organization_and_instance_when_found(
|
||||||
|
|
||||||
response = osb_client.delete(
|
response = osb_client.delete(
|
||||||
f"/api/osb/v2/service_instances/{instance_name}"
|
f"/api/osb/v2/service_instances/{instance_name}"
|
||||||
f"?service_id={test_service.osb_service_id}&plan_id={test_service_offering.osb_plan_id}"
|
f"?service_id={service.osb_service_id}&plan_id={service_offering.osb_plan_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ class TestReencryptFieldsCommand:
|
||||||
assert "Starting re-encryption" in output
|
assert "Starting re-encryption" in output
|
||||||
assert "Re-encrypted 0 ControlPlane objects" in output
|
assert "Re-encrypted 0 ControlPlane objects" in output
|
||||||
|
|
||||||
def test_reencrypt_fields_with_control_plane(self, test_control_plane):
|
def test_reencrypt_fields_with_control_plane(self, control_plane):
|
||||||
out = StringIO()
|
out = StringIO()
|
||||||
call_command("reencrypt_fields", stdout=out)
|
call_command("reencrypt_fields", stdout=out)
|
||||||
|
|
||||||
|
|
@ -147,11 +147,11 @@ class TestSyncBillingMetadataCommand:
|
||||||
|
|
||||||
assert "No control planes found with the specified IDs" in out.getvalue()
|
assert "No control planes found with the specified IDs" in out.getvalue()
|
||||||
|
|
||||||
def test_sync_billing_metadata_dry_run_with_control_plane(self, test_control_plane):
|
def test_sync_billing_metadata_dry_run_with_control_plane(self, control_plane):
|
||||||
out = StringIO()
|
out = StringIO()
|
||||||
call_command("sync_billing_metadata", "--dry-run", stdout=out)
|
call_command("sync_billing_metadata", "--dry-run", stdout=out)
|
||||||
|
|
||||||
output = out.getvalue()
|
output = out.getvalue()
|
||||||
assert "DRY RUN" in output
|
assert "DRY RUN" in output
|
||||||
assert "Syncing billing metadata on 1 control plane(s)" in output
|
assert "Syncing billing metadata on 1 control plane(s)" in output
|
||||||
assert test_control_plane.name in output
|
assert control_plane.name in output
|
||||||
|
|
|
||||||
|
|
@ -59,76 +59,76 @@ def test_organization_linked_in_sidebar(
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_service_detail_redirects_with_single_offering(
|
def test_service_detail_redirects_with_single_offering(
|
||||||
client, org_owner, organization, test_service, test_service_offering
|
client, org_owner, organization, service, service_offering
|
||||||
):
|
):
|
||||||
client.force_login(org_owner)
|
client.force_login(org_owner)
|
||||||
url = f"/org/{organization.slug}/services/{test_service.slug}/"
|
url = f"/org/{organization.slug}/services/{service.slug}/"
|
||||||
response = client.get(url)
|
response = client.get(url)
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
expected_url = f"/org/{organization.slug}/services/{test_service.slug}/offering/{test_service_offering.pk}/"
|
expected_url = f"/org/{organization.slug}/services/{service.slug}/offering/{service_offering.pk}/"
|
||||||
assert response.url == expected_url
|
assert response.url == expected_url
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_service_detail_shows_multiple_offerings(
|
def test_service_detail_shows_multiple_offerings(
|
||||||
client, org_owner, organization, test_service, test_service_offering
|
client, org_owner, organization, service, service_offering
|
||||||
):
|
):
|
||||||
second_provider = CloudProvider.objects.create(
|
second_provider = CloudProvider.objects.create(
|
||||||
name="AWS", description="Amazon Web Services"
|
name="AWS", description="Amazon Web Services"
|
||||||
)
|
)
|
||||||
second_offering = ServiceOffering.objects.create(
|
second_offering = ServiceOffering.objects.create(
|
||||||
service=test_service,
|
service=service,
|
||||||
provider=second_provider,
|
provider=second_provider,
|
||||||
description="Redis on AWS",
|
description="Redis on AWS",
|
||||||
osb_plan_id="test-plan-456",
|
osb_plan_id="test-plan-456",
|
||||||
)
|
)
|
||||||
|
|
||||||
client.force_login(org_owner)
|
client.force_login(org_owner)
|
||||||
url = f"/org/{organization.slug}/services/{test_service.slug}/"
|
url = f"/org/{organization.slug}/services/{service.slug}/"
|
||||||
response = client.get(url)
|
response = client.get(url)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
content = response.content.decode()
|
content = response.content.decode()
|
||||||
|
|
||||||
assert test_service_offering.provider.name in content
|
assert service_offering.provider.name in content
|
||||||
assert second_offering.provider.name in content
|
assert second_offering.provider.name in content
|
||||||
assert "Create Instance" in content
|
assert "Create Instance" in content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_service_detail_respects_cloud_provider_restrictions(
|
def test_service_detail_respects_cloud_provider_restrictions(
|
||||||
client, org_owner, organization, test_service, test_service_offering
|
client, org_owner, organization, service, service_offering
|
||||||
):
|
):
|
||||||
second_provider = CloudProvider.objects.create(
|
second_provider = CloudProvider.objects.create(
|
||||||
name="AWS", description="Amazon Web Services"
|
name="AWS", description="Amazon Web Services"
|
||||||
)
|
)
|
||||||
ServiceOffering.objects.create(
|
ServiceOffering.objects.create(
|
||||||
service=test_service,
|
service=service,
|
||||||
provider=second_provider,
|
provider=second_provider,
|
||||||
description="Redis on AWS",
|
description="Redis on AWS",
|
||||||
osb_plan_id="test-plan-456",
|
osb_plan_id="test-plan-456",
|
||||||
)
|
)
|
||||||
organization.origin.limit_cloudproviders.add(test_service_offering.provider)
|
organization.origin.limit_cloudproviders.add(service_offering.provider)
|
||||||
|
|
||||||
client.force_login(org_owner)
|
client.force_login(org_owner)
|
||||||
url = f"/org/{organization.slug}/services/{test_service.slug}/"
|
url = f"/org/{organization.slug}/services/{service.slug}/"
|
||||||
response = client.get(url)
|
response = client.get(url)
|
||||||
|
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
expected_url = f"/org/{organization.slug}/services/{test_service.slug}/offering/{test_service_offering.pk}/"
|
expected_url = f"/org/{organization.slug}/services/{service.slug}/offering/{service_offering.pk}/"
|
||||||
assert response.url == expected_url
|
assert response.url == expected_url
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_service_detail_no_redirect_with_restricted_multiple_offerings(
|
def test_service_detail_no_redirect_with_restricted_multiple_offerings(
|
||||||
client, org_owner, organization, test_service, test_service_offering
|
client, org_owner, organization, service, service_offering
|
||||||
):
|
):
|
||||||
second_provider = CloudProvider.objects.create(
|
second_provider = CloudProvider.objects.create(
|
||||||
name="AWS", description="Amazon Web Services"
|
name="AWS", description="Amazon Web Services"
|
||||||
)
|
)
|
||||||
second_offering = ServiceOffering.objects.create(
|
second_offering = ServiceOffering.objects.create(
|
||||||
service=test_service,
|
service=service,
|
||||||
provider=second_provider,
|
provider=second_provider,
|
||||||
description="Redis on AWS",
|
description="Redis on AWS",
|
||||||
osb_plan_id="test-plan-456",
|
osb_plan_id="test-plan-456",
|
||||||
|
|
@ -137,35 +137,35 @@ def test_service_detail_no_redirect_with_restricted_multiple_offerings(
|
||||||
name="Azure", description="Microsoft Azure"
|
name="Azure", description="Microsoft Azure"
|
||||||
)
|
)
|
||||||
third_offering = ServiceOffering.objects.create(
|
third_offering = ServiceOffering.objects.create(
|
||||||
service=test_service,
|
service=service,
|
||||||
provider=third_provider,
|
provider=third_provider,
|
||||||
description="Redis on Azure",
|
description="Redis on Azure",
|
||||||
osb_plan_id="test-plan-789",
|
osb_plan_id="test-plan-789",
|
||||||
)
|
)
|
||||||
organization.origin.limit_cloudproviders.add(
|
organization.origin.limit_cloudproviders.add(
|
||||||
test_service_offering.provider, second_provider
|
service_offering.provider, second_provider
|
||||||
)
|
)
|
||||||
|
|
||||||
client.force_login(org_owner)
|
client.force_login(org_owner)
|
||||||
url = f"/org/{organization.slug}/services/{test_service.slug}/"
|
url = f"/org/{organization.slug}/services/{service.slug}/"
|
||||||
response = client.get(url)
|
response = client.get(url)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
content = response.content.decode()
|
content = response.content.decode()
|
||||||
assert test_service_offering.provider.name in content
|
assert service_offering.provider.name in content
|
||||||
assert second_offering.provider.name in content
|
assert second_offering.provider.name in content
|
||||||
assert third_offering.provider.name not in content
|
assert third_offering.provider.name not in content
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_service_instance_update_spec_pushes_display_name_annotation(
|
def test_service_instance_update_spec_pushes_display_name_annotation(
|
||||||
organization, test_control_plane_crd, org_owner
|
organization, control_plane_crd, org_owner
|
||||||
):
|
):
|
||||||
instance = ServiceInstance.objects.create(
|
instance = ServiceInstance.objects.create(
|
||||||
name="test-instance",
|
name="test-instance",
|
||||||
display_name="Original Name",
|
display_name="Original Name",
|
||||||
organization=organization,
|
organization=organization,
|
||||||
context=test_control_plane_crd,
|
context=control_plane_crd,
|
||||||
)
|
)
|
||||||
mock_api = MagicMock()
|
mock_api = MagicMock()
|
||||||
with (
|
with (
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue