mirror of https://github.com/scrapy/scrapy.git
Use mocking for tests/test_feedexport.py::BatchDeliveriesTest::test_s3_export
This commit is contained in:
parent
56f05fb164
commit
17e135377a
|
|
@ -13,7 +13,6 @@ from logging import getLogger
|
|||
from pathlib import Path
|
||||
from string import ascii_letters, digits
|
||||
from unittest import mock
|
||||
from unittest.mock import call
|
||||
from urllib.parse import urljoin, urlparse, quote
|
||||
from urllib.request import pathname2url
|
||||
|
||||
|
|
@ -42,7 +41,6 @@ from scrapy.extensions.feedexport import (
|
|||
from scrapy.settings import Settings
|
||||
from scrapy.utils.python import to_unicode
|
||||
from scrapy.utils.test import (
|
||||
assert_aws_environ,
|
||||
get_s3_content_and_delete,
|
||||
get_crawler,
|
||||
mock_google_cloud_storage,
|
||||
|
|
@ -286,9 +284,9 @@ class S3FeedStorageTest(unittest.TestCase):
|
|||
self.assertEqual(
|
||||
file.method_calls,
|
||||
[
|
||||
call.seek(0),
|
||||
mock.call.seek(0),
|
||||
# The call to read does not happen with Stubber
|
||||
call.close(),
|
||||
mock.call.close(),
|
||||
]
|
||||
)
|
||||
|
||||
|
|
@ -1518,46 +1516,53 @@ class BatchDeliveriesTest(FeedExportTestBase):
|
|||
|
||||
@defer.inlineCallbacks
|
||||
def test_s3_export(self):
|
||||
"""
|
||||
Test export of items into s3 bucket.
|
||||
S3_TEST_BUCKET_NAME, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY must be specified in tox.ini
|
||||
to perform this test:
|
||||
[testenv]
|
||||
setenv =
|
||||
AWS_SECRET_ACCESS_KEY = ABCD
|
||||
AWS_ACCESS_KEY_ID = EFGH
|
||||
S3_TEST_BUCKET_NAME = IJKL
|
||||
"""
|
||||
try:
|
||||
import boto3
|
||||
except ImportError:
|
||||
raise unittest.SkipTest("S3FeedStorage requires boto3")
|
||||
skip_if_no_boto()
|
||||
|
||||
assert_aws_environ()
|
||||
s3_test_bucket_name = os.environ.get('S3_TEST_BUCKET_NAME')
|
||||
access_key = os.environ.get('AWS_ACCESS_KEY_ID')
|
||||
secret_key = os.environ.get('AWS_SECRET_ACCESS_KEY')
|
||||
if not s3_test_bucket_name:
|
||||
raise unittest.SkipTest("No S3 BUCKET available for testing")
|
||||
|
||||
chars = [random.choice(ascii_letters + digits) for _ in range(15)]
|
||||
filename = ''.join(chars)
|
||||
prefix = f'tmp/{filename}'
|
||||
s3_test_file_uri = f's3://{s3_test_bucket_name}/{prefix}/%(batch_time)s.json'
|
||||
storage = S3FeedStorage(s3_test_bucket_name, access_key, secret_key)
|
||||
settings = Settings({
|
||||
'FEEDS': {
|
||||
s3_test_file_uri: {
|
||||
'format': 'json',
|
||||
},
|
||||
},
|
||||
'FEED_EXPORT_BATCH_ITEM_COUNT': 1,
|
||||
})
|
||||
bucket = 'mybucket'
|
||||
items = [
|
||||
self.MyItem({'foo': 'bar1', 'egg': 'spam1'}),
|
||||
self.MyItem({'foo': 'bar2', 'egg': 'spam2', 'baz': 'quux2'}),
|
||||
self.MyItem({'foo': 'bar3', 'baz': 'quux3'}),
|
||||
]
|
||||
|
||||
class CustomS3FeedStorage(S3FeedStorage):
|
||||
|
||||
stubs = []
|
||||
|
||||
def open(self, *args, **kwargs):
|
||||
from botocore.stub import ANY, Stubber
|
||||
stub = Stubber(self.s3_client)
|
||||
stub.activate()
|
||||
CustomS3FeedStorage.stubs.append(stub)
|
||||
stub.add_response(
|
||||
'put_object',
|
||||
expected_params={
|
||||
'Body': ANY,
|
||||
'Bucket': bucket,
|
||||
'Key': ANY,
|
||||
},
|
||||
service_response={},
|
||||
)
|
||||
return super().open(*args, **kwargs)
|
||||
|
||||
key = 'export.csv'
|
||||
uri = f's3://{bucket}/{key}/%(batch_time)s.json'
|
||||
batch_item_count = 1
|
||||
settings = {
|
||||
'AWS_ACCESS_KEY_ID': 'access_key',
|
||||
'AWS_SECRET_ACCESS_KEY': 'secret_key',
|
||||
'FEED_EXPORT_BATCH_ITEM_COUNT': batch_item_count,
|
||||
'FEED_STORAGES': {
|
||||
's3': CustomS3FeedStorage,
|
||||
},
|
||||
'FEEDS': {
|
||||
uri: {
|
||||
'format': 'json',
|
||||
},
|
||||
},
|
||||
}
|
||||
crawler = get_crawler(settings_dict=settings)
|
||||
storage = S3FeedStorage.from_crawler(crawler, uri)
|
||||
verifyObject(IFeedStorage, storage)
|
||||
|
||||
class TestSpider(scrapy.Spider):
|
||||
|
|
@ -1567,22 +1572,14 @@ class BatchDeliveriesTest(FeedExportTestBase):
|
|||
for item in items:
|
||||
yield item
|
||||
|
||||
s3 = boto3.resource('s3')
|
||||
my_bucket = s3.Bucket(s3_test_bucket_name)
|
||||
batch_size = settings.getint('FEED_EXPORT_BATCH_ITEM_COUNT')
|
||||
|
||||
with MockServer() as s:
|
||||
with MockServer() as server:
|
||||
runner = CrawlerRunner(Settings(settings))
|
||||
TestSpider.start_urls = [s.url('/')]
|
||||
TestSpider.start_urls = [server.url('/')]
|
||||
yield runner.crawl(TestSpider)
|
||||
|
||||
for file_uri in my_bucket.objects.filter(Prefix=prefix):
|
||||
content = get_s3_content_and_delete(s3_test_bucket_name, file_uri.key)
|
||||
if not content and not items:
|
||||
break
|
||||
content = json.loads(content.decode('utf-8'))
|
||||
expected_batch, items = items[:batch_size], items[batch_size:]
|
||||
self.assertEqual(expected_batch, content)
|
||||
self.assertEqual(len(CustomS3FeedStorage.stubs), len(items)+1)
|
||||
for stub in CustomS3FeedStorage.stubs[:-1]:
|
||||
stub.assert_no_pending_responses()
|
||||
|
||||
|
||||
class FeedExportInitTest(unittest.TestCase):
|
||||
|
|
|
|||
Loading…
Reference in New Issue