Skip to content

Commit 810df8c

Browse files
authored
test_library_get_key_path check (#2648)
#### Reference Issues/PRs <!--Example: Fixes #1234. See also #3456.--> #### What does this implement or fix? Start running test with conda once again: 50 runs: https://github.com/man-group/ArcticDB/actions/runs/17730467752 Creating bucket now retries on ClientError 400 also and not only to EndpointConnectionError ``` except (botocore.exceptions.EndpointConnectionError, botocore.exceptions.ClientError) as e: ..... ``` This should fix also: https://github.com/man-group/ArcticDB/actions/runs/17843532292/job/50738667004 Validation link for Build and Test: https://github.com/man-group/ArcticDB/actions/runs/17849282592 The fix does not seems to work ... We continue to to get ClientError: https://github.com/man-group/ArcticDB/actions/runs/17856250740/job/50775866306?pr=2648. The code is trying to run Moto (seen from 'OSError(98, 'Address already in use')'). It manages to do that at port 20579. Then we try to create the bucket 15 times ... But for some reason we always get ``` botocore.exceptions.ClientError: An error occurred (400) when calling the CreateBucket operation: Bad Request ``` ``` ........ OSError(98, 'Address already in use') OSError(98, 'Address already in use') DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): localhost:20579 DEBUG:urllib3.connectionpool:http://localhost:20579 "GET / HTTP/1.1" 400 None DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): localhost:20579 DEBUG:urllib3.connectionpool:http://localhost:20579 "PUT /test_s3_bucket_1758284502_1 HTTP/1.1" 400 0 WARNING:S3 Storage Fixture:S3 create bucket failed. Retry 1/15 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://127.0.0.1:20579/ * Running on http://10.1.1.114:20579/ Press CTRL+C to quit DEBUG:urllib3.connectionpool:http://localhost:20579 "PUT /test_s3_bucket_1758284502_1 HTTP/1.1" 400 0 WARNING:S3 Storage Fixture:S3 create bucket failed. Retry 1/15 DEBUG:urllib3.connectionpool:http://localhost:20579 "PUT /test_s3_bucket_1758284502_1 HTTP/1.1" 400 0 WARNING:S3 Storage Fixture:S3 create bucket failed. Retry 1/15 ............ ``` Ok. Trying to make bucket name use - instead of _ ... This seems to be one important recommendation that is not true with our code Coverage after the change: https://github.com/man-group/ArcticDB/actions/runs/17937971277 https://github.com/man-group/ArcticDB/actions/runs/17937631291/job/51006702552?pr=2648 The error still exist. Made new modifications to print out the actual error message. It seems like we are trying to comnect to Azurite that is running on the same port - that means that a Moto S3 gets free port but in mean time Azurite is spawned there. Solution - introduce get_buckets_check operation that will be always executed upon start of Moto S3. If that operation is not successfull a new attempt will be triggered to obtain another free port with different seed this time. Additional validation avail here: https://github.com/man-group/ArcticDB/actions/runs/17978603290 A new version where server identifies itself as Moto AWS S3 or Moto GCP is created. Additional validation run: https://github.com/man-group/ArcticDB/actions/runs/18095773997 Real Storage Test: https://github.com/man-group/ArcticDB/actions/runs/18095823526 #### Any other comments? #### Checklist <details> <summary> Checklist for code changes... </summary> - [ ] Have you updated the relevant docstrings, documentation and copyright notice? - [ ] Is this contribution tested against [all ArcticDB's features](../docs/mkdocs/docs/technical/contributing.md)? - [ ] Do all exceptions introduced raise appropriate [error messages](https://docs.arcticdb.io/error_messages/)? - [ ] Are API changes highlighted in the PR description? - [ ] Is the PR labelled as enhancement or bug so it appears in autogenerated release notes? </details> <!-- Thanks for contributing a Pull Request to ArcticDB! Please ensure you have taken a look at: - ArcticDB's Code of Conduct: https://github.com/man-group/ArcticDB/blob/master/CODE_OF_CONDUCT.md - ArcticDB's Contribution Licensing: https://github.com/man-group/ArcticDB/blob/master/docs/mkdocs/docs/technical/contributing.md#contribution-licensing --> --------- Co-authored-by: Georgi Rusev <Georgi Rusev>
1 parent 79e1e1d commit 810df8c

File tree

4 files changed

+73
-10
lines changed

4 files changed

+73
-10
lines changed

python/arcticdb/storage_fixtures/azure.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import stat
1414
import tempfile
1515
import uuid
16+
import requests
1617
from typing import TYPE_CHECKING, Optional, Union
1718
from tempfile import mkdtemp
1819

@@ -214,8 +215,25 @@ def _safe_enter(self):
214215
process_start_cmd=args,
215216
cwd=self.working_dir,
216217
)
218+
if not self.ssl_test_support:
219+
# Do not verify when ssl test support because of need of proper certs
220+
assert self.is_azurite(self.endpoint_root), f"Azurite not started at: {self.endpoint_root}"
217221
return self
218222

223+
def is_azurite(self, url: str, timeout: int = 60):
224+
try:
225+
response = requests.get(url, timeout=timeout)
226+
headers = response.headers
227+
228+
# Check for Azurite-specific headers
229+
server_header = headers.get("Server", "").lower()
230+
has_azurite_headers = "x-ms-request-id" in str(headers) and "azurite" in server_header
231+
232+
return has_azurite_headers
233+
234+
except requests.RequestException:
235+
return False
236+
219237
def __exit__(self, exc_type, exc_value, traceback):
220238
with handle_cleanup_exception(self, "process", consequence="Subsequent file deletion may also fail. "):
221239
GracefulProcessUtils.terminate(self._p)

python/arcticdb/storage_fixtures/mongo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class ManagedMongoDBServer(StorageFixtureFactory):
117117

118118
def __init__(self, data_dir: Optional[str] = None, port=0, executable="mongod"):
119119
self._data_dir = data_dir or tempfile.mkdtemp("ManagedMongoDBServer")
120-
self._port = port or get_ephemeral_port(5)
120+
self._port = port or get_ephemeral_port(7)
121121
self._executable = executable
122122
self._client = None
123123

python/arcticdb/storage_fixtures/s3.py

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import re
1414
import sys
1515
import platform
16+
import pprint
1617
from tempfile import mkdtemp
1718
from urllib.parse import urlparse
1819
import boto3
@@ -688,13 +689,20 @@ def __call__(self, environ, start_response):
688689
else:
689690
self._reqs_till_rate_limit -= 1
690691

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+
691697
return super().__call__(environ, start_response)
692698

693699

694700
class GcpHostDispatcherApplication(HostDispatcherApplication):
695701
"""GCP's S3 implementation does not have batch delete."""
696702

697703
def __call__(self, environ, start_response):
704+
path_info: bytes = environ.get("PATH_INFO", "")
705+
698706
if environ["REQUEST_METHOD"] == "POST" and environ["QUERY_STRING"] == "delete":
699707
response_body = (
700708
b'<?xml version="1.0" encoding="UTF-8"?>'
@@ -708,6 +716,12 @@ def __call__(self, environ, start_response):
708716
"501 Not Implemented", [("Content-Type", "text/xml"), ("Content-Length", str(len(response_body)))]
709717
)
710718
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+
711725
return super().__call__(environ, start_response)
712726

713727

@@ -731,6 +745,20 @@ def run_gcp_server(port, key_file, cert_file):
731745
)
732746

733747

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+
734762
def create_bucket(s3_client, bucket_name, max_retries=15):
735763
for i in range(max_retries):
736764
try:
@@ -741,6 +769,9 @@ def create_bucket(s3_client, bucket_name, max_retries=15):
741769
raise
742770
logger.warning(f"S3 create bucket failed. Retry {1}/{max_retries}")
743771
time.sleep(1)
772+
except Exception as e:
773+
logger.error(f"create_bucket - Error: {e.response['Error']['Message']}")
774+
pprint.pprint(e.response)
744775

745776

746777
class MotoS3StorageFixtureFactory(BaseS3StorageFixtureFactory):
@@ -791,10 +822,19 @@ def bucket_name(self, bucket_type="s3"):
791822
# We need the unique_id because we have tests that are creating the factory directly
792823
# and not using the fixtures
793824
# 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}"
795826

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)
798838
self.endpoint = f"{self.http_protocol}://{self.host}:{port}"
799839
self.working_dir = mkdtemp(suffix="MotoS3StorageFixtureFactory")
800840
self._iam_endpoint = f"{self.http_protocol}://localhost:{port}"
@@ -826,17 +866,22 @@ def _start_server(self):
826866
# 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
827867
# Due to this, we need to wait for the server to come up for a longer time
828868
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"
829870

830871
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
832873
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}")
834878
break
835879
except AssertionError as e: # Thrown by wait_for_server_to_come_up
836880
sys.stderr.write(repr(e))
837881
GracefulProcessUtils.terminate(self._p)
882+
except Exception as e:
883+
logger.error(f"Error during startup of Moto S3. Trying again. Error: {e}")
838884

839-
self._s3_admin = self._boto(service="s3", key=self.default_key)
840885
return self
841886

842887
def __exit__(self, exc_type, exc_value, traceback):
@@ -928,8 +973,8 @@ def create_fixture(self) -> NfsS3Bucket:
928973

929974

930975
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)
933978
self.endpoint = f"{self.http_protocol}://{self.host}:{port}"
934979
self.working_dir = mkdtemp(suffix="MotoGcpS3StorageFixtureFactory")
935980
self._iam_endpoint = f"{self.http_protocol}://localhost:{port}"
@@ -961,6 +1006,7 @@ def _start_server(self):
9611006
# 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
9621007
# Due to this, we need to wait for the server to come up for a longer time
9631008
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"
9641010

9651011
def create_fixture(self) -> GcpS3Bucket:
9661012
bucket = self.bucket_name("gcp")

python/tests/integration/arcticdb/test_s3.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,6 @@ def test_wrapped_s3_storage(lib_name, wrapped_s3_storage_bucket):
196196
lib.write("s", data=create_df())
197197

198198

199-
@SKIP_CONDA_MARK # issue with fixture init will be fixed in https://github.com/man-group/ArcticDB/issues/2640
200199
def test_library_get_key_path(lib_name, s3_and_nfs_storage_bucket, test_prefix):
201200
lib = s3_and_nfs_storage_bucket.create_version_store_factory(lib_name)()
202201
lib.write("s", data=create_df())

0 commit comments

Comments
 (0)