1
- import shlex
2
- import subprocess
3
- import time
4
1
import uuid
5
2
6
3
import pytest
@@ -50,93 +47,77 @@ def xml_file(datapath):
50
47
return datapath ("io" , "data" , "xml" , "books.xml" )
51
48
52
49
53
- @pytest .fixture
54
- def s3_base (worker_id , monkeypatch ):
55
- """
56
- Fixture for mocking S3 interaction.
50
+ @pytest .fixture (scope = "session" )
51
+ def aws_credentials (monkeysession ):
52
+ """Mocked AWS Credentials for moto."""
53
+ monkeysession .setenv ("AWS_ACCESS_KEY_ID" , "testing" )
54
+ monkeysession .setenv ("AWS_SECRET_ACCESS_KEY" , "testing" )
55
+ monkeysession .setenv ("AWS_SECURITY_TOKEN" , "testing" )
56
+ monkeysession .setenv ("AWS_SESSION_AWS_SESSION_TOKEN" , "testing" )
57
+ monkeysession .setenv ("AWS_DEFAULT_REGION" , "us-east-1" )
57
58
58
- Sets up moto server in separate process locally
59
- Return url for motoserver/moto CI service
60
- """
61
- pytest .importorskip ("s3fs" )
62
- pytest .importorskip ("boto3" )
63
-
64
- # temporary workaround as moto fails for botocore >= 1.11 otherwise,
65
- # see https://github.com/spulec/moto/issues/1924 & 1952
66
- monkeypatch .setenv ("AWS_ACCESS_KEY_ID" , "foobar_key" )
67
- monkeypatch .setenv ("AWS_SECRET_ACCESS_KEY" , "foobar_secret" )
68
- if is_ci_environment ():
69
- if is_platform_arm () or is_platform_mac () or is_platform_windows ():
70
- # NOT RUN on Windows/macOS, only Ubuntu
71
- # - subprocess in CI can cause timeouts
72
- # - GitHub Actions do not support
73
- # container services for the above OSs
74
- pytest .skip (
75
- "S3 tests do not have a corresponding service on "
76
- "Windows or macOS platforms"
77
- )
78
- else :
79
- # set in .github/workflows/unit-tests.yml
80
- yield "http://localhost:5000"
59
+
60
+ @pytest .fixture (scope = "session" )
61
+ def moto_server (aws_credentials ):
62
+ # use service container for Linux on GitHub Actions
63
+ if is_ci_environment () and not (
64
+ is_platform_mac () or is_platform_arm () or is_platform_windows ()
65
+ ):
66
+ yield "http://localhost:5000"
81
67
else :
82
- requests = pytest .importorskip ("requests" )
83
- pytest .importorskip ("moto" )
84
- pytest .importorskip ("flask" ) # server mode needs flask too
85
-
86
- # Launching moto in server mode, i.e., as a separate process
87
- # with an S3 endpoint on localhost
88
-
89
- worker_id = "5" if worker_id == "master" else worker_id .lstrip ("gw" )
90
- endpoint_port = f"555{ worker_id } "
91
- endpoint_uri = f"http://127.0.0.1:{ endpoint_port } /"
92
-
93
- # pipe to null to avoid logging in terminal
94
- with subprocess .Popen (
95
- shlex .split (f"moto_server s3 -p { endpoint_port } " ),
96
- stdout = subprocess .DEVNULL ,
97
- stderr = subprocess .DEVNULL ,
98
- ) as proc :
99
- timeout = 5
100
- while timeout > 0 :
101
- try :
102
- # OK to go once server is accepting connections
103
- r = requests .get (endpoint_uri )
104
- if r .ok :
105
- break
106
- except Exception :
107
- pass
108
- timeout -= 0.1
109
- time .sleep (0.1 )
110
- yield endpoint_uri
111
-
112
- proc .terminate ()
68
+ moto_server = pytest .importorskip ("moto.server" )
69
+ server = moto_server .ThreadedMotoServer (port = 0 )
70
+ server .start ()
71
+ host , port = server .get_host_and_port ()
72
+ yield f"http://{ host } :{ port } "
73
+ server .stop ()
113
74
114
75
115
76
@pytest .fixture
116
- def s3so (s3_base ):
117
- return {"client_kwargs" : {"endpoint_url" : s3_base }}
77
+ def moto_s3_resource (moto_server ):
78
+ boto3 = pytest .importorskip ("boto3" )
79
+ s3 = boto3 .resource ("s3" , endpoint_url = moto_server )
80
+ return s3
118
81
119
82
120
- @pytest .fixture
121
- def s3_resource (s3_base ):
122
- import boto3
83
+ @pytest .fixture (scope = "session" )
84
+ def s3so (moto_server ):
85
+ return {
86
+ "client_kwargs" : {
87
+ "endpoint_url" : moto_server ,
88
+ }
89
+ }
123
90
124
- s3 = boto3 .resource ("s3" , endpoint_url = s3_base )
125
- return s3
91
+
92
+ @pytest .fixture
93
+ def s3_bucket_public (moto_s3_resource ):
94
+ """
95
+ Create a public S3 bucket using moto.
96
+ """
97
+ bucket_name = f"pandas-test-{ uuid .uuid4 ()} "
98
+ bucket = moto_s3_resource .Bucket (bucket_name )
99
+ bucket .create (ACL = "public-read" )
100
+ yield bucket
101
+ bucket .objects .delete ()
102
+ bucket .delete ()
126
103
127
104
128
105
@pytest .fixture
129
- def s3_public_bucket (s3_resource ):
130
- bucket = s3_resource .Bucket (f"pandas-test-{ uuid .uuid4 ()} " )
131
- bucket .create ()
106
+ def s3_bucket_private (moto_s3_resource ):
107
+ """
108
+ Create a private S3 bucket using moto.
109
+ """
110
+ bucket_name = f"cant_get_it-{ uuid .uuid4 ()} "
111
+ bucket = moto_s3_resource .Bucket (bucket_name )
112
+ bucket .create (ACL = "private" )
132
113
yield bucket
133
114
bucket .objects .delete ()
134
115
bucket .delete ()
135
116
136
117
137
118
@pytest .fixture
138
- def s3_public_bucket_with_data (
139
- s3_public_bucket , tips_file , jsonl_file , feather_file , xml_file
119
+ def s3_bucket_public_with_data (
120
+ s3_bucket_public , tips_file , jsonl_file , feather_file , xml_file
140
121
):
141
122
"""
142
123
The following datasets
@@ -158,22 +139,13 @@ def s3_public_bucket_with_data(
158
139
]
159
140
for s3_key , file_name in test_s3_files :
160
141
with open (file_name , "rb" ) as f :
161
- s3_public_bucket .put_object (Key = s3_key , Body = f )
162
- return s3_public_bucket
163
-
164
-
165
- @pytest .fixture
166
- def s3_private_bucket (s3_resource ):
167
- bucket = s3_resource .Bucket (f"cant_get_it-{ uuid .uuid4 ()} " )
168
- bucket .create (ACL = "private" )
169
- yield bucket
170
- bucket .objects .delete ()
171
- bucket .delete ()
142
+ s3_bucket_public .put_object (Key = s3_key , Body = f )
143
+ return s3_bucket_public
172
144
173
145
174
146
@pytest .fixture
175
- def s3_private_bucket_with_data (
176
- s3_private_bucket , tips_file , jsonl_file , feather_file , xml_file
147
+ def s3_bucket_private_with_data (
148
+ s3_bucket_private , tips_file , jsonl_file , feather_file , xml_file
177
149
):
178
150
"""
179
151
The following datasets
@@ -195,8 +167,8 @@ def s3_private_bucket_with_data(
195
167
]
196
168
for s3_key , file_name in test_s3_files :
197
169
with open (file_name , "rb" ) as f :
198
- s3_private_bucket .put_object (Key = s3_key , Body = f )
199
- return s3_private_bucket
170
+ s3_bucket_private .put_object (Key = s3_key , Body = f )
171
+ return s3_bucket_private
200
172
201
173
202
174
_compression_formats_params = [
0 commit comments