13
13
import re
14
14
import sys
15
15
import platform
16
+ import pprint
16
17
from tempfile import mkdtemp
17
18
from urllib .parse import urlparse
18
19
import boto3
@@ -688,13 +689,20 @@ def __call__(self, environ, start_response):
688
689
else :
689
690
self ._reqs_till_rate_limit -= 1
690
691
692
+ # Lets add ability to identify type as S3
693
+ if "/whoami" in path_info :
694
+ start_response ("200 OK" , [("Content-Type" , "text/plain" )])
695
+ return [b"Moto AWS S3" ]
696
+
691
697
return super ().__call__ (environ , start_response )
692
698
693
699
694
700
class GcpHostDispatcherApplication (HostDispatcherApplication ):
695
701
"""GCP's S3 implementation does not have batch delete."""
696
702
697
703
def __call__ (self , environ , start_response ):
704
+ path_info : bytes = environ .get ("PATH_INFO" , "" )
705
+
698
706
if environ ["REQUEST_METHOD" ] == "POST" and environ ["QUERY_STRING" ] == "delete" :
699
707
response_body = (
700
708
b'<?xml version="1.0" encoding="UTF-8"?>'
@@ -708,6 +716,12 @@ def __call__(self, environ, start_response):
708
716
"501 Not Implemented" , [("Content-Type" , "text/xml" ), ("Content-Length" , str (len (response_body )))]
709
717
)
710
718
return [response_body ]
719
+
720
+ # Lets add ability to identify type as GCP
721
+ if "/whoami" in path_info :
722
+ start_response ("200 OK" , [("Content-Type" , "text/plain" )])
723
+ return [b"Moto GCP" ]
724
+
711
725
return super ().__call__ (environ , start_response )
712
726
713
727
@@ -731,6 +745,20 @@ def run_gcp_server(port, key_file, cert_file):
731
745
)
732
746
733
747
748
+ def is_server_type (url : str , server_type : str ):
749
+ """Check if a server is of certain type.
750
+
751
+ /whoami url is added to Moto* objects to identify GCP or S3"""
752
+ try :
753
+ response = requests .get (url , verify = False )
754
+ if response .status_code == 200 and server_type in response .text :
755
+ return True
756
+ except Exception as e :
757
+ logger .error (f"Error during server type check: { e } " )
758
+ logger .error (f"Was not of expected type: status code { response .status_code } , text: { response .text } " )
759
+ return False
760
+
761
+
734
762
def create_bucket (s3_client , bucket_name , max_retries = 15 ):
735
763
for i in range (max_retries ):
736
764
try :
@@ -741,6 +769,9 @@ def create_bucket(s3_client, bucket_name, max_retries=15):
741
769
raise
742
770
logger .warning (f"S3 create bucket failed. Retry { 1 } /{ max_retries } " )
743
771
time .sleep (1 )
772
+ except Exception as e :
773
+ logger .error (f"create_bucket - Error: { e .response ['Error' ]['Message' ]} " )
774
+ pprint .pprint (e .response )
744
775
745
776
746
777
class MotoS3StorageFixtureFactory (BaseS3StorageFixtureFactory ):
@@ -791,10 +822,19 @@ def bucket_name(self, bucket_type="s3"):
791
822
# We need the unique_id because we have tests that are creating the factory directly
792
823
# and not using the fixtures
793
824
# so this guarantees a unique bucket name
794
- return f"test_ { bucket_type } _bucket_ { self .unique_id } _ { self ._bucket_id } "
825
+ return f"test- { bucket_type } -bucket- { self .unique_id } - { self ._bucket_id } "
795
826
796
- def _start_server (self ):
797
- port = self .port = get_ephemeral_port (2 )
827
+ def is_server_type (url : str , server_type : str ):
828
+ try :
829
+ response = requests .get (url , verify = False )
830
+ if response .status_code == 200 and server_type in response .text :
831
+ return True
832
+ except Exception :
833
+ pass
834
+ return False
835
+
836
+ def _start_server (self , seed = 2 ):
837
+ port = self .port = get_ephemeral_port (seed )
798
838
self .endpoint = f"{ self .http_protocol } ://{ self .host } :{ port } "
799
839
self .working_dir = mkdtemp (suffix = "MotoS3StorageFixtureFactory" )
800
840
self ._iam_endpoint = f"{ self .http_protocol } ://localhost:{ port } "
@@ -826,17 +866,22 @@ def _start_server(self):
826
866
# There is a problem with the performance of the socket module in the MacOS 15 GH runners - https://github.com/actions/runner-images/issues/12162
827
867
# Due to this, we need to wait for the server to come up for a longer time
828
868
wait_for_server_to_come_up (self .endpoint , "moto" , self ._p , timeout = 240 )
869
+ assert is_server_type (self .endpoint + "/whoami" , "S3" ), "The server has not identified as S3"
829
870
830
871
def _safe_enter (self ):
831
- for _ in range (3 ): # For unknown reason, Moto, when running in pytest-xdist, will randomly fail to start
872
+ for i in range (5 ): # For unknown reason, Moto, when running in pytest-xdist, will randomly fail to start
832
873
try :
833
- self ._start_server ()
874
+ logger .info (f"Attempt to start server - { i } " )
875
+ self ._start_server (2 + i )
876
+ self ._s3_admin = self ._boto (service = "s3" , key = self .default_key )
877
+ logger .info (f"Moto S3 STARTED!!! on port { self .port } " )
834
878
break
835
879
except AssertionError as e : # Thrown by wait_for_server_to_come_up
836
880
sys .stderr .write (repr (e ))
837
881
GracefulProcessUtils .terminate (self ._p )
882
+ except Exception as e :
883
+ logger .error (f"Error during startup of Moto S3. Trying again. Error: { e } " )
838
884
839
- self ._s3_admin = self ._boto (service = "s3" , key = self .default_key )
840
885
return self
841
886
842
887
def __exit__ (self , exc_type , exc_value , traceback ):
@@ -928,8 +973,8 @@ def create_fixture(self) -> NfsS3Bucket:
928
973
929
974
930
975
class MotoGcpS3StorageFixtureFactory (MotoS3StorageFixtureFactory ):
931
- def _start_server (self ):
932
- port = self .port = get_ephemeral_port (3 )
976
+ def _start_server (self , seed = 20 ):
977
+ port = self .port = get_ephemeral_port (seed )
933
978
self .endpoint = f"{ self .http_protocol } ://{ self .host } :{ port } "
934
979
self .working_dir = mkdtemp (suffix = "MotoGcpS3StorageFixtureFactory" )
935
980
self ._iam_endpoint = f"{ self .http_protocol } ://localhost:{ port } "
@@ -961,6 +1006,7 @@ def _start_server(self):
961
1006
# There is a problem with the performance of the socket module in the MacOS 15 GH runners - https://github.com/actions/runner-images/issues/12162
962
1007
# Due to this, we need to wait for the server to come up for a longer time
963
1008
wait_for_server_to_come_up (self .endpoint , "moto" , self ._p , timeout = 240 )
1009
+ assert is_server_type (self .endpoint + "/whoami" , "GCP" ), "The server has not identified as GCP"
964
1010
965
1011
def create_fixture (self ) -> GcpS3Bucket :
966
1012
bucket = self .bucket_name ("gcp" )
0 commit comments