Add display name field #331

Merged
tobru merged 18 commits from 290-display-name into main 2025-12-11 15:33:00 +00:00
4 changed files with 151 additions and 128 deletions
Showing only changes of commit 457bbaadc2 - Show all commits

View file

@ -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",
)

View file

@ -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

View file

@ -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

View file

@ -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 (