1 | from unittest.mock import patch, Mock |
---|
2 | |
---|
3 | import pytest |
---|
4 | |
---|
5 | from ow.tasks.bulk import process_compressed_files |
---|
6 | |
---|
7 | |
---|
8 | class TestBulkTasks(object): |
---|
9 | |
---|
10 | @pytest.fixture |
---|
11 | def settings(self): |
---|
12 | settings = { |
---|
13 | 'workouts.bulk_tmp_path': '/tmp', |
---|
14 | 'workouts.bulk_loading_lock': '/tmp/queue-processor.lock'} |
---|
15 | return settings |
---|
16 | |
---|
17 | @pytest.fixture |
---|
18 | def root(self): |
---|
19 | root = { |
---|
20 | '_bulk_files': {} |
---|
21 | } |
---|
22 | return root |
---|
23 | |
---|
24 | @pytest.fixture |
---|
25 | def env(self, settings, root): |
---|
26 | env = { |
---|
27 | 'request': Mock(), |
---|
28 | 'root': root, |
---|
29 | 'registry': Mock(settings=settings) |
---|
30 | } |
---|
31 | return env |
---|
32 | |
---|
33 | @patch('fcntl.lockf') |
---|
34 | @patch('ow.tasks.bulk.log') |
---|
35 | def test_process_compressed_files_no_files(self, log, lockf, env): |
---|
36 | workouts_loaded = process_compressed_files(env) |
---|
37 | # the lockf was called, to set the lock on the lock file |
---|
38 | assert lockf.called |
---|
39 | # no warnings shown |
---|
40 | assert not log.warning.called |
---|
41 | # nothing loaded, no transaction committed |
---|
42 | assert not workouts_loaded |
---|
43 | assert not env['request'].tm.commit.called |
---|
44 | |
---|
45 | @patch('fcntl.lockf') |
---|
46 | @patch('ow.tasks.bulk.log') |
---|
47 | def test_process_compressed_files_single_file(self, log, lockf, env): |
---|
48 | bulk_file = Mock(loaded=False) |
---|
49 | env['root']['_bulk_files']['faked-bulk_id'] = bulk_file |
---|
50 | workouts_loaded = process_compressed_files(env) |
---|
51 | # the lockf was called, to set the lock on the lock file |
---|
52 | assert lockf.called |
---|
53 | # no warnings shown |
---|
54 | assert not log.warning.called |
---|
55 | # file loaded, transaction commited |
---|
56 | bulk_file.load.assert_called_once_with( |
---|
57 | env['root'], |
---|
58 | env['registry'].settings['workouts.bulk_tmp_path']) |
---|
59 | assert workouts_loaded |
---|
60 | env['request'].tm.commit.assert_called_once |
---|
61 | |
---|
62 | @patch('fcntl.lockf') |
---|
63 | @patch('ow.tasks.bulk.log') |
---|
64 | def test_process_compressed_files_already_loaded(self, log, lockf, env): |
---|
65 | bulk_file = Mock(loaded=True) |
---|
66 | env['root']['_bulk_files']['faked-bulk_id'] = bulk_file |
---|
67 | workouts_loaded = process_compressed_files(env) |
---|
68 | # the lockf was called, to set the lock on the lock file |
---|
69 | assert lockf.called |
---|
70 | # no warnings shown |
---|
71 | assert not log.warning.called |
---|
72 | # file already loaded, no transaction commited |
---|
73 | assert not bulk_file.load.called |
---|
74 | assert not workouts_loaded |
---|
75 | assert not env['request'].tm.commit.called |
---|
76 | |
---|
77 | @patch('fcntl.lockf') |
---|
78 | @patch('ow.tasks.bulk.log') |
---|
79 | def test_process_compressed_files_multiple_files(self, log, lockf, env): |
---|
80 | bulk_file = Mock(loaded=False) |
---|
81 | loaded_bulk_file = Mock(loaded=True) |
---|
82 | additional_bulk_file = Mock(loaded=False) |
---|
83 | env['root']['_bulk_files']['faked-bulk_id'] = bulk_file |
---|
84 | env['root']['_bulk_files']['loaded-bulk_id'] = loaded_bulk_file |
---|
85 | env['root']['_bulk_files']['additional-bulk_id'] = additional_bulk_file |
---|
86 | workouts_loaded = process_compressed_files(env) |
---|
87 | # the lockf was called, to set the lock on the lock file |
---|
88 | assert lockf.called |
---|
89 | # no warnings shown |
---|
90 | assert not log.warning.called |
---|
91 | # 2 files loaded, transaction commited once |
---|
92 | bulk_file.load.assert_called_once_with( |
---|
93 | env['root'], |
---|
94 | env['registry'].settings['workouts.bulk_tmp_path']) |
---|
95 | assert not loaded_bulk_file.load.called |
---|
96 | additional_bulk_file.load.assert_called_once_with( |
---|
97 | env['root'], |
---|
98 | env['registry'].settings['workouts.bulk_tmp_path']) |
---|
99 | assert workouts_loaded |
---|
100 | env['request'].tm.commit.assert_called_once |
---|
101 | |
---|
102 | @patch('fcntl.lockf') |
---|
103 | @patch('ow.tasks.bulk.log') |
---|
104 | def test_process_compressed_files_lock_ioerror(self, log, lockf, env): |
---|
105 | """ |
---|
106 | A second call to this task, while a first call is still running, |
---|
107 | does not do anything, just log a warning message to the logger |
---|
108 | """ |
---|
109 | # Make lock raise an IOError, mimicing what happens when the lock has |
---|
110 | # been acquired by another process |
---|
111 | e = IOError('could not lock file!') |
---|
112 | lockf.side_effect = e |
---|
113 | |
---|
114 | workouts_loaded = process_compressed_files(env) |
---|
115 | # Exception raised, False returned |
---|
116 | assert workouts_loaded is False |
---|
117 | |
---|
118 | # Calls: fcntl.lock has been called, then the IOError was raised |
---|
119 | # and no more calls to the api have been made |
---|
120 | assert lockf.called |
---|
121 | |
---|
122 | assert not log.info.called |
---|
123 | assert not log.error.called |
---|
124 | # except for the log call, which was a warning |
---|
125 | assert log.warning.called |
---|
126 | log_msg = log.warning.call_args_list[0][0][0] |
---|
127 | assert 'not run the workout bulk load task' in log_msg |
---|
128 | assert 'could not acquire lock' in log_msg |
---|