"""Unit tests for SWF tasks.""" import io import json import math import time from unittest.mock import MagicMock import boto from boto.s3.key import Key from job import tasks import moto import pytest import smart_open def file_fixture(): """Quick fixture to mimick a file on s3.""" connection = boto.connect_s3() bucket = connection.create_bucket('mybucket') key = Key(bucket) key.name = 'file' key.set_contents_from_filename('tests/fixtures/snowflake_unload_sample') return 's3://mybucket/file' @pytest.mark.parametrize(('line_count', 'filename'), [ (0, '0.txt'), (tasks.LINES_PER_FILE + 1, '1.txt'), (tasks.LINES_PER_FILE * 5 + 1, '5.txt')]) def test_smart_open(monkeypatch, line_count, filename): """Test the creation of the filename.""" smart_open_mock = MagicMock() monkeypatch.setattr(smart_open, 'smart_open', smart_open_mock) tasks.smart_open_file('s3://destination/file/', line_count) smart_open_mock.assert_called_with( 's3://destination/file/{}'.format(filename), 'wb') @moto.mock_s3 def test_stream_content(): """Test streaming a gzip file.""" source = file_fixture() total = 0 for line in tasks.stream_content(source): total += 1 assert isinstance(line, str) assert total == 10000 @moto.mock_s3 def test_generate_load_files(monkeypatch): """Test the file can be analysed and reduced.""" spy = MagicMock() file_destination = 's3://destination/' monkeypatch.setattr(tasks, 'LINES_PER_FILE', 10000) def validate_line(line): """Verify the data is here. Args: line (str): the line to write into the file. """ line = json.loads(line) assert 'metric' in line assert 'month' in line assert 'label_id' in line def smart_open_file(destination, total_lines): """Replacement of the smart open. Args: destination (str): the destination for the file. total_lines (int): the current number of lines """ spy() assert destination == file_destination writer = io.StringIO() monkeypatch.setattr(writer, 'write', validate_line) return writer monkeypatch.setattr(tasks, 'smart_open_file', smart_open_file) src_path = file_fixture() tasks.generate_load_files(MagicMock(), src_path, file_destination) # The task reduces so the number of files at the end should contain # less lines than the number of files from the begining. assert spy.call_count != math.ceil(10000 / tasks.LINES_PER_FILE) assert spy.call_count == 1 # folded result fits into a single file @moto.mock_s3 def test_wait_until_empty_s3_path(monkeypatch): """Test waiting until s3 is empty.""" connection = boto.connect_s3() bucket = connection.create_bucket('mybucket') spy = MagicMock() # Create all the keys keys = [] for f in range(4): key = Key(bucket) key.name = 'path/file.{}'.format(f) key.set_contents_from_string('random content') keys.append(key) def sleep(time): """Mock of the sleep method. This replacement is actually going to remove one file at a time until there are no more in the path. Args: time (int): the time for the method to sleep. """ assert isinstance(time, int) key = keys.pop() bucket.delete_key(key.name) spy() monkeypatch.setattr(time, 'sleep', sleep) tasks.wait_until_empty_s3_path(MagicMock(), 's3://mybucket/path/') assert spy.call_count == 4