@@ -644,5 +644,234 @@ def __init__(self, status_code):
644644 self .status_code = status_code
645645
646646
647+ class TestWebappDeployWithSrcUrl (unittest .TestCase ):
648+ """Tests for webapp deploy with --src-url sync/async behavior"""
649+
650+ @mock .patch ('azure.cli.command_modules.appservice.custom._poll_deployment_runtime_status' )
651+ @mock .patch ('azure.cli.command_modules.appservice.custom._build_deploymentstatus_url' )
652+ @mock .patch ('azure.cli.command_modules.appservice.custom.send_raw_request' )
653+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_url' )
654+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_onedeploy_request_body' )
655+ @mock .patch ('azure.cli.command_modules.appservice.custom._build_onedeploy_url' )
656+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_onedeploy_status_url' )
657+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_ondeploy_headers' )
658+ def test_src_url_sync_deployment_default (self , headers_mock , status_url_mock , build_url_mock_onedeploy ,
659+ body_mock , get_url_mock , send_raw_mock , build_url_mock , poll_mock ):
660+ """Test that --src-url defaults to sync deployment (polls for completion)"""
661+ from azure .cli .command_modules .appservice .custom import _make_onedeploy_request
662+
663+ # Mock helper functions
664+ body_mock .return_value = ('{"type": "zip"}' , None )
665+ build_url_mock_onedeploy .return_value = 'https://management.azure.com/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/sites/myapp/extensions/onedeploy'
666+ status_url_mock .return_value = 'https://myapp.scm.azurewebsites.net/api/deployments/latest'
667+ headers_mock .return_value = {'Content-Type' : 'application/json' }
668+
669+ # Mock the ARM response with deployment ID
670+ class MockResponse :
671+ status_code = 200
672+ headers = {'content-type' : 'application/json' }
673+ text = '{"id": "/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/sites/myapp/extensions/onedeploy/123456"}'
674+
675+ def json (self ):
676+ return {
677+ 'id' : '/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/sites/myapp/extensions/onedeploy/123456' ,
678+ 'properties' : {'provisioningState' : 'InProgress' }
679+ }
680+
681+ send_raw_mock .return_value = MockResponse ()
682+ build_url_mock .return_value = 'https://management.azure.com/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/sites/myapp/deploymentStatus/123456'
683+ poll_mock .return_value = {'status' : 'RuntimeSuccessful' }
684+ get_url_mock .return_value = 'https://myapp.azurewebsites.net'
685+
686+ # Create params object
687+ class Params :
688+ src_url = 'https://example.com/myapp.zip'
689+ src_path = None
690+ is_async_deployment = None # Default should be sync
691+ cmd = _get_test_cmd ()
692+ resource_group_name = 'test-rg'
693+ webapp_name = 'test-app'
694+ slot = None
695+ timeout = None
696+ is_linux_webapp = False
697+ is_functionapp = False
698+ enable_kudu_warmup = False
699+
700+ params = Params ()
701+
702+ # Execute
703+ result = _make_onedeploy_request (params )
704+
705+ # Assert polling was called
706+ poll_mock .assert_called_once ()
707+ # Verify deployment ID was extracted correctly
708+ build_url_mock .assert_called_with (params .cmd , 'test-rg' , 'test-app' , None , '123456' )
709+
710+ @mock .patch ('azure.cli.command_modules.appservice.custom._poll_deployment_runtime_status' )
711+ @mock .patch ('azure.cli.command_modules.appservice.custom._build_deploymentstatus_url' )
712+ @mock .patch ('azure.cli.command_modules.appservice.custom.send_raw_request' )
713+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_url' )
714+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_onedeploy_request_body' )
715+ @mock .patch ('azure.cli.command_modules.appservice.custom._build_onedeploy_url' )
716+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_onedeploy_status_url' )
717+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_ondeploy_headers' )
718+ def test_src_url_sync_deployment_explicit_false (self , headers_mock , status_url_mock , build_url_mock_onedeploy ,
719+ body_mock , get_url_mock , send_raw_mock , build_url_mock , poll_mock ):
720+ """Test that --src-url with --async false triggers polling"""
721+ from azure .cli .command_modules .appservice .custom import _make_onedeploy_request
722+
723+ # Mock helper functions
724+ body_mock .return_value = ('{"type": "zip"}' , None )
725+ build_url_mock_onedeploy .return_value = 'https://management.azure.com/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/sites/myapp/extensions/onedeploy'
726+ status_url_mock .return_value = 'https://myapp.scm.azurewebsites.net/api/deployments/latest'
727+ headers_mock .return_value = {'Content-Type' : 'application/json' }
728+
729+ # Mock the ARM response with deployment ID in properties
730+ class MockResponse :
731+ status_code = 200
732+ headers = {'content-type' : 'application/json' }
733+ text = '{"properties": {"deploymentId": "dep-789"}}'
734+
735+ def json (self ):
736+ return {
737+ 'properties' : {'deploymentId' : 'dep-789' , 'provisioningState' : 'InProgress' }
738+ }
739+
740+ send_raw_mock .return_value = MockResponse ()
741+ build_url_mock .return_value = 'https://management.azure.com/.../deploymentStatus/dep-789'
742+ poll_mock .return_value = {'status' : 'RuntimeSuccessful' }
743+ get_url_mock .return_value = 'https://myapp.azurewebsites.net'
744+
745+ # Create params object with explicit async=false
746+ class Params :
747+ src_url = 'https://example.com/myapp.zip'
748+ src_path = None
749+ is_async_deployment = False # Explicitly set to False
750+ cmd = _get_test_cmd ()
751+ resource_group_name = 'test-rg'
752+ webapp_name = 'test-app'
753+ slot = None
754+ timeout = None
755+ is_linux_webapp = False
756+ is_functionapp = False
757+ enable_kudu_warmup = False
758+
759+ params = Params ()
760+
761+ # Execute
762+ result = _make_onedeploy_request (params )
763+
764+ # Assert polling was called
765+ poll_mock .assert_called_once ()
766+ build_url_mock .assert_called_with (params .cmd , 'test-rg' , 'test-app' , None , 'dep-789' )
767+
768+ @mock .patch ('azure.cli.command_modules.appservice.custom.send_raw_request' )
769+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_url' )
770+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_onedeploy_request_body' )
771+ @mock .patch ('azure.cli.command_modules.appservice.custom._build_onedeploy_url' )
772+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_onedeploy_status_url' )
773+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_ondeploy_headers' )
774+ def test_src_url_async_deployment (self , headers_mock , status_url_mock , build_url_mock_onedeploy ,
775+ body_mock , get_url_mock , send_raw_mock ):
776+ """Test that --src-url with --async true returns immediately without polling"""
777+ from azure .cli .command_modules .appservice .custom import _make_onedeploy_request
778+
779+ # Mock helper functions
780+ body_mock .return_value = ('{"type": "zip"}' , None )
781+ build_url_mock_onedeploy .return_value = 'https://management.azure.com/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/sites/myapp/extensions/onedeploy'
782+ status_url_mock .return_value = 'https://myapp.scm.azurewebsites.net/api/deployments/latest'
783+ headers_mock .return_value = {'Content-Type' : 'application/json' }
784+
785+ # Mock the ARM response
786+ class MockResponse :
787+ status_code = 200
788+ headers = {'content-type' : 'application/json' }
789+ text = '{"id": "/subscriptions/sub/.../123456"}'
790+
791+ def json (self ):
792+ return {
793+ 'id' : '/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/sites/myapp/extensions/onedeploy/123456' ,
794+ 'properties' : {'provisioningState' : 'InProgress' }
795+ }
796+
797+ send_raw_mock .return_value = MockResponse ()
798+ get_url_mock .return_value = 'https://myapp.azurewebsites.net'
799+
800+ # Create params object with async=true
801+ class Params :
802+ src_url = 'https://example.com/myapp.zip'
803+ src_path = None
804+ is_async_deployment = True # Async mode
805+ cmd = _get_test_cmd ()
806+ resource_group_name = 'test-rg'
807+ webapp_name = 'test-app'
808+ slot = None
809+ timeout = None
810+ is_linux_webapp = False
811+ is_functionapp = False
812+ enable_kudu_warmup = False
813+
814+ params = Params ()
815+
816+ # Execute
817+ result = _make_onedeploy_request (params )
818+
819+ # Assert result is immediate response (provisioningState returned)
820+ self .assertEqual (result .get ('provisioningState' ), 'InProgress' )
821+
822+ @mock .patch ('azure.cli.command_modules.appservice.custom.send_raw_request' )
823+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_url' )
824+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_onedeploy_request_body' )
825+ @mock .patch ('azure.cli.command_modules.appservice.custom._build_onedeploy_url' )
826+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_onedeploy_status_url' )
827+ @mock .patch ('azure.cli.command_modules.appservice.custom._get_ondeploy_headers' )
828+ def test_src_url_no_deployment_id (self , headers_mock , status_url_mock , build_url_mock_onedeploy ,
829+ body_mock , get_url_mock , send_raw_mock ):
830+ """Test that --src-url falls back gracefully when no deployment ID is found"""
831+ from azure .cli .command_modules .appservice .custom import _make_onedeploy_request
832+
833+ # Mock helper functions
834+ body_mock .return_value = ('{"type": "zip"}' , None )
835+ build_url_mock_onedeploy .return_value = 'https://management.azure.com/subscriptions/sub/resourceGroups/rg/providers/Microsoft.Web/sites/myapp/extensions/onedeploy'
836+ status_url_mock .return_value = 'https://myapp.scm.azurewebsites.net/api/deployments/latest'
837+ headers_mock .return_value = {'Content-Type' : 'application/json' }
838+
839+ # Mock the ARM response without deployment ID
840+ class MockResponse :
841+ status_code = 200
842+ headers = {'content-type' : 'application/json' }
843+ text = '{}'
844+
845+ def json (self ):
846+ return {
847+ 'properties' : {'provisioningState' : 'Succeeded' }
848+ }
849+
850+ send_raw_mock .return_value = MockResponse ()
851+ get_url_mock .return_value = 'https://myapp.azurewebsites.net'
852+
853+ # Create params object
854+ class Params :
855+ src_url = 'https://example.com/myapp.zip'
856+ src_path = None
857+ is_async_deployment = None # Default
858+ cmd = _get_test_cmd ()
859+ resource_group_name = 'test-rg'
860+ webapp_name = 'test-app'
861+ slot = None
862+ timeout = None
863+ is_linux_webapp = False
864+ is_functionapp = False
865+ enable_kudu_warmup = False
866+
867+ params = Params ()
868+
869+ # Execute
870+ result = _make_onedeploy_request (params )
871+
872+ # Assert result is immediate response (no polling)
873+ self .assertEqual (result .get ('provisioningState' ), 'Succeeded' )
874+
875+
647876if __name__ == '__main__' :
648877 unittest .main ()
0 commit comments