@@ -443,6 +443,74 @@ def mock_wait(self, server_id, target_state, timeout=300):
443443 assert result == 1
444444
445445
446+ def test_delete_with_volume_not_found_404 (
447+ scaleway_runner , fake_scaleway_group , caplog , monkeypatch
448+ ):
449+ """Test instance deletion when volume returns 404 error."""
450+ backend = fake_scaleway_group .backend
451+ scaleway_runner .instance_id = "test-server-id"
452+ scaleway_runner .save ()
453+
454+ # Mock server with volumes
455+ mock_volume = MagicMock ()
456+ mock_volume .id = "test-volume-id"
457+ mock_server = MagicMock ()
458+ mock_server .id = "test-server-id"
459+ mock_server .state = ServerState .RUNNING
460+ mock_server .volumes = {"0" : mock_volume }
461+
462+ mock_client = backend .client
463+ mock_client .get_server .return_value = MagicMock (server = mock_server )
464+ mock_client .delete_volume .side_effect = Exception ("Error 404: Volume not found" )
465+
466+ # Restore wait_for_server_state mock
467+ def mock_wait (self , server_id , target_state , timeout = 300 ):
468+ return mock_server
469+
470+ monkeypatch .setattr (ScalewayBackend , "wait_for_server_state" , mock_wait )
471+
472+ result = backend .delete (scaleway_runner )
473+
474+ # Verify info log for not_found volume (not warning)
475+ assert "not found - may have been auto-deleted" in caplog .text
476+ assert "Failed to delete volume" not in caplog .text
477+ assert result == 1
478+
479+
480+ def test_delete_with_volume_not_found_string (
481+ scaleway_runner , fake_scaleway_group , caplog , monkeypatch
482+ ):
483+ """Test instance deletion when volume returns 'not_found' in error message."""
484+ backend = fake_scaleway_group .backend
485+ scaleway_runner .instance_id = "test-server-id"
486+ scaleway_runner .save ()
487+
488+ # Mock server with volumes
489+ mock_volume = MagicMock ()
490+ mock_volume .id = "test-volume-id"
491+ mock_server = MagicMock ()
492+ mock_server .id = "test-server-id"
493+ mock_server .state = ServerState .RUNNING
494+ mock_server .volumes = {"0" : mock_volume }
495+
496+ mock_client = backend .client
497+ mock_client .get_server .return_value = MagicMock (server = mock_server )
498+ mock_client .delete_volume .side_effect = Exception ("resource_not_found" )
499+
500+ # Restore wait_for_server_state mock
501+ def mock_wait (self , server_id , target_state , timeout = 300 ):
502+ return mock_server
503+
504+ monkeypatch .setattr (ScalewayBackend , "wait_for_server_state" , mock_wait )
505+
506+ result = backend .delete (scaleway_runner )
507+
508+ # Verify info log for not_found volume (not warning)
509+ assert "not found - may have been auto-deleted" in caplog .text
510+ assert "Failed to delete volume" not in caplog .text
511+ assert result == 1
512+
513+
446514def test_delete_stopped_server (scaleway_runner , fake_scaleway_group ):
447515 """Test deletion of already stopped server."""
448516 backend = fake_scaleway_group .backend
@@ -606,3 +674,171 @@ def test_list(scaleway_runner, scaleway_group):
606674 scaleway_group .backend .delete (runner )
607675 with pytest .raises (NotFoundError ):
608676 scaleway_group .backend .get (runner .instance_id )
677+
678+
679+ def test_create_with_default_sbs_volume (
680+ scaleway_runner , fake_scaleway_group , monkeypatch , caplog
681+ ):
682+ """Test instance creation with default sbs_volume configuration."""
683+ # Mock image with root_volume
684+ mock_image = MagicMock ()
685+ mock_image .id = "test-image-id"
686+ mock_root_volume = MagicMock ()
687+ mock_root_volume .id = "snapshot-id"
688+ mock_image .root_volume = mock_root_volume
689+
690+ # Patch get_image at class level
691+ def mock_get_image (self , image_name ):
692+ return mock_image
693+
694+ monkeypatch .setattr (ScalewayBackend , "get_image" , mock_get_image )
695+
696+ backend = fake_scaleway_group .backend
697+ backend .create (scaleway_runner )
698+
699+ # Verify volumes parameter was passed to _create_server
700+ mock_client = backend .client
701+ create_call = mock_client ._create_server .call_args
702+ volumes = create_call .kwargs .get ("volumes" )
703+
704+ assert volumes is not None
705+ assert "0" in volumes
706+ assert volumes ["0" ].volume_type == "sbs_volume"
707+ assert volumes ["0" ].size == 20_000_000_000 # 20GB default
708+ assert volumes ["0" ].base_snapshot == "snapshot-id"
709+
710+ # Verify log message
711+ assert "Creating sbs_volume boot volume: 20GB" in caplog .text
712+ assert "from snapshot snapshot-id" in caplog .text
713+
714+
715+ def test_create_with_l_ssd_volume (
716+ scaleway_runner , fake_scaleway_group , monkeypatch , caplog
717+ ):
718+ """Test instance creation with l_ssd volume type."""
719+ # Mock image
720+ mock_image = MagicMock ()
721+ mock_image .id = "test-image-id"
722+
723+ # Patch get_image at class level
724+ def mock_get_image (self , image_name ):
725+ return mock_image
726+
727+ monkeypatch .setattr (ScalewayBackend , "get_image" , mock_get_image )
728+
729+ # Configure l_ssd
730+ fake_scaleway_group .backend .instance_config .volume_type = "l_ssd"
731+ fake_scaleway_group .backend .instance_config .volume_size_gb = 80
732+
733+ backend = fake_scaleway_group .backend
734+ backend .create (scaleway_runner )
735+
736+ # Verify volumes parameter
737+ mock_client = backend .client
738+ create_call = mock_client ._create_server .call_args
739+ volumes = create_call .kwargs .get ("volumes" )
740+
741+ assert volumes is not None
742+ assert "0" in volumes
743+ assert volumes ["0" ].volume_type == "l_ssd"
744+ assert volumes ["0" ].size == 80_000_000_000 # 80GB
745+ # For l_ssd, no base_snapshot should be set
746+ assert (
747+ not hasattr (volumes ["0" ], "base_snapshot" ) or volumes ["0" ].base_snapshot is None
748+ )
749+
750+ # Verify log message
751+ assert "Creating l_ssd boot volume: 80GB" in caplog .text
752+
753+
754+ def test_create_with_custom_volume_size (
755+ scaleway_runner , fake_scaleway_group , monkeypatch
756+ ):
757+ """Test instance creation with custom volume size."""
758+ mock_image = MagicMock ()
759+ mock_image .id = "test-image-id"
760+ mock_root_volume = MagicMock ()
761+ mock_root_volume .id = "snapshot-id"
762+ mock_image .root_volume = mock_root_volume
763+
764+ # Patch get_image at class level
765+ def mock_get_image (self , image_name ):
766+ return mock_image
767+
768+ monkeypatch .setattr (ScalewayBackend , "get_image" , mock_get_image )
769+
770+ # Set custom size
771+ fake_scaleway_group .backend .instance_config .volume_size_gb = 100
772+ backend = fake_scaleway_group .backend
773+
774+ backend .create (scaleway_runner )
775+
776+ mock_client = backend .client
777+ create_call = mock_client ._create_server .call_args
778+ volumes = create_call .kwargs .get ("volumes" )
779+
780+ assert volumes ["0" ].size == 100_000_000_000 # 100GB
781+
782+
783+ def test_create_with_no_root_volume_fallback (
784+ scaleway_runner , fake_scaleway_group , monkeypatch , caplog
785+ ):
786+ """Test fallback when image has no root_volume."""
787+ mock_image = MagicMock ()
788+ mock_image .id = "test-image-id"
789+ mock_image .root_volume = None # No root volume
790+
791+ # Patch get_image at class level
792+ def mock_get_image (self , image_name ):
793+ return mock_image
794+
795+ monkeypatch .setattr (ScalewayBackend , "get_image" , mock_get_image )
796+
797+ backend = fake_scaleway_group .backend
798+ backend .create (scaleway_runner )
799+
800+ # Verify warning was logged
801+ assert "has no root_volume, using default volume from image" in caplog .text
802+
803+ # Verify volumes=None was passed
804+ mock_client = backend .client
805+ create_call = mock_client ._create_server .call_args
806+ volumes = create_call .kwargs .get ("volumes" )
807+ assert volumes is None
808+
809+
810+ def test_create_with_user_provided_volumes (
811+ scaleway_runner , fake_scaleway_group , monkeypatch
812+ ):
813+ """Test instance creation with user-provided volumes configuration."""
814+ from scaleway .instance .v1 import VolumeServerTemplate
815+
816+ # Mock image
817+ mock_image = MagicMock ()
818+ mock_image .id = "test-image-id"
819+
820+ # Patch get_image at class level
821+ def mock_get_image (self , image_name ):
822+ return mock_image
823+
824+ monkeypatch .setattr (ScalewayBackend , "get_image" , mock_get_image )
825+
826+ # Set user-provided volumes
827+ custom_volumes = {
828+ "0" : VolumeServerTemplate (
829+ volume_type = "sbs_volume" ,
830+ size = 50_000_000_000 ,
831+ base_snapshot = "custom-snapshot-id" ,
832+ )
833+ }
834+ fake_scaleway_group .backend .instance_config .volumes = custom_volumes
835+
836+ backend = fake_scaleway_group .backend
837+ backend .create (scaleway_runner )
838+
839+ # Verify user-provided volumes were used
840+ mock_client = backend .client
841+ create_call = mock_client ._create_server .call_args
842+ volumes = create_call .kwargs .get ("volumes" )
843+
844+ assert volumes == custom_volumes
0 commit comments