1
- import shlex
2
- import subprocess
3
- import time
4
1
import uuid
5
2
6
3
import pytest
7
4
8
- from pandas .compat import (
9
- is_ci_environment ,
10
- is_platform_arm ,
11
- is_platform_mac ,
12
- is_platform_windows ,
13
- )
14
5
import pandas .util ._test_decorators as td
15
6
16
7
import pandas .io .common as icom
@@ -50,93 +41,62 @@ def xml_file(datapath):
50
41
return datapath ("io" , "data" , "xml" , "books.xml" )
51
42
52
43
53
- @pytest .fixture
54
- def s3_base (worker_id , monkeypatch ):
55
- """
56
- Fixture for mocking S3 interaction.
44
+ @pytest .fixture (scope = "session" )
45
+ def aws_credentials (monkeysession ):
46
+ """Mocked AWS Credentials for moto."""
47
+ monkeysession .setenv ("AWS_ACCESS_KEY_ID" , "testing" )
48
+ monkeysession .setenv ("AWS_SECRET_ACCESS_KEY" , "testing" )
49
+ monkeysession .setenv ("AWS_SECURITY_TOKEN" , "testing" )
50
+ monkeysession .setenv ("AWS_SESSION_AWS_SESSION_TOKEN" , "testing" )
51
+ monkeysession .setenv ("AWS_DEFAULT_REGION" , "us-east-1" )
57
52
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"
81
- 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 ()
53
+
54
+ @pytest .fixture (scope = "session" )
55
+ def moto_server (aws_credentials ):
56
+ moto_server = pytest .importorskip ("moto.server" )
57
+ server = moto_server .ThreadedMotoServer (port = 0 )
58
+ server .start ()
59
+ host , port = server .get_host_and_port ()
60
+ yield f"http://{ host } :{ port } "
61
+ server .stop ()
113
62
114
63
115
64
@pytest .fixture
116
- def s3so (s3_base ):
117
- return {"client_kwargs" : {"endpoint_url" : s3_base }}
65
+ def moto_s3_resource (moto_server ):
66
+ boto3 = pytest .importorskip ("boto3" )
67
+ s3 = boto3 .resource ("s3" , endpoint_url = moto_server )
68
+ return s3
118
69
119
70
120
71
@pytest .fixture
121
- def s3_resource (s3_base ):
122
- import boto3
123
-
124
- s3 = boto3 .resource ("s3" , endpoint_url = s3_base )
125
- return s3
72
+ def s3_bucket_public (moto_s3_resource ):
73
+ """
74
+ Create a public S3 bucket using moto.
75
+ """
76
+ bucket_name = f"pandas-test-{ uuid .uuid4 ()} "
77
+ bucket = moto_s3_resource .Bucket (bucket_name )
78
+ bucket .create (ACL = "public-read" )
79
+ yield bucket
80
+ bucket .objects .delete ()
81
+ bucket .delete ()
126
82
127
83
128
84
@pytest .fixture
129
- def s3_public_bucket (s3_resource ):
130
- bucket = s3_resource .Bucket (f"pandas-test-{ uuid .uuid4 ()} " )
131
- bucket .create ()
85
+ def s3_bucket_private (moto_s3_resource ):
86
+ """
87
+ Create a private S3 bucket using moto.
88
+ """
89
+ bucket_name = f"cant_get_it-{ uuid .uuid4 ()} "
90
+ bucket = moto_s3_resource .Bucket (bucket_name )
91
+ bucket .create (ACL = "private" )
132
92
yield bucket
133
93
bucket .objects .delete ()
134
94
bucket .delete ()
135
95
136
96
137
97
@pytest .fixture
138
- def s3_public_bucket_with_data (
139
- s3_public_bucket , tips_file , jsonl_file , feather_file , xml_file
98
+ def s3_bucket_public_with_data (
99
+ s3_bucket_public , tips_file , jsonl_file , feather_file , xml_file
140
100
):
141
101
"""
142
102
The following datasets
@@ -158,22 +118,13 @@ def s3_public_bucket_with_data(
158
118
]
159
119
for s3_key , file_name in test_s3_files :
160
120
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 ()
121
+ s3_bucket_public .put_object (Key = s3_key , Body = f )
122
+ return s3_bucket_public
172
123
173
124
174
125
@pytest .fixture
175
- def s3_private_bucket_with_data (
176
- s3_private_bucket , tips_file , jsonl_file , feather_file , xml_file
126
+ def s3_bucket_private_with_data (
127
+ s3_bucket_private , tips_file , jsonl_file , feather_file , xml_file
177
128
):
178
129
"""
179
130
The following datasets
@@ -195,8 +146,8 @@ def s3_private_bucket_with_data(
195
146
]
196
147
for s3_key , file_name in test_s3_files :
197
148
with open (file_name , "rb" ) as f :
198
- s3_private_bucket .put_object (Key = s3_key , Body = f )
199
- return s3_private_bucket
149
+ s3_bucket_private .put_object (Key = s3_key , Body = f )
150
+ return s3_bucket_private
200
151
201
152
202
153
_compression_formats_params = [
0 commit comments