Skip to content
This repository was archived by the owner on Jan 5, 2019. It is now read-only.

Commit 6bc79b4

Browse files
committed
Merge pull request #8 from frigg/fix-tests
Fix tests and bugs that the tests uncovered
2 parents f912508 + 91c8022 commit 6bc79b4

2 files changed

Lines changed: 102 additions & 55 deletions

File tree

docker/manager.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import datetime
22
import logging
33
import os
4+
import re
45
import subprocess
56
from time import sleep
67

@@ -25,21 +26,31 @@ def _execute(cmd):
2526
result.out = stdout.decode('utf-8').strip() if stdout else ''
2627
result.err = stderr.decode('utf-8').strip() if stderr else ''
2728
result.return_code = process.returncode
28-
result.succeeded = result.return_code == 0
2929
logger.debug('Finished running of: {0}'.format(result.__dict__))
3030
return result
3131

3232

3333
class ProcessResult(object):
34+
return_code = None
35+
out = ''
36+
err = ''
37+
3438
def __init__(self, command):
3539
self.command = command
3640

41+
@property
42+
def succeeded(self):
43+
if self.return_code is None:
44+
return None
45+
return self.return_code == 0
46+
3747

3848
class Docker(object):
39-
def __init__(self, image='ubuntu', timeout=3600):
49+
def __init__(self, image='ubuntu', timeout=3600, combine_outputs=False):
4050
self.container_name = 'dyn-{0}'.format(int(datetime.datetime.now().strftime('%s')) * 1000)
4151
self.timeout = timeout
4252
self.image = image
53+
self.combine_outputs = combine_outputs
4354

4455
def __enter__(self):
4556
return self.start()
@@ -49,10 +60,23 @@ def __exit__(self, exc_type, exc_val, exc_tb):
4960

5061
def run(self, cmd, working_directory=''):
5162
working_directory = self._get_working_directory(working_directory)
52-
return _execute('docker exec -i {container} bash -c "{command}"'.format(
53-
container=self.container_name,
54-
command='cd {0} && {1}'.format(working_directory, cmd)
55-
))
63+
command_string = 'cd {working_directory} && {command}'
64+
if self.combine_outputs:
65+
command_string += ' 2>&1'
66+
result = _execute(
67+
'docker exec -i {container} bash -c \'{command} ; echo "--return-$?--"\''.format(
68+
container=self.container_name,
69+
command=command_string.format(working_directory=working_directory, command=cmd)
70+
)
71+
)
72+
73+
return_code_match = re.search(r'(?:\\n)?--return-(\d+)--$', result.out)
74+
if return_code_match:
75+
result.return_code = int(return_code_match.group(1))
76+
result.out = result.out.replace(return_code_match.group(0), '')
77+
if result.out.endswith('\n'):
78+
result.out = result.out[:len(result.out) - 1]
79+
return result
5680

5781
def read_file(self, path):
5882
path = self._get_working_directory(path)
@@ -147,6 +171,6 @@ def wrapper(*args, **kwargs):
147171

148172
@staticmethod
149173
def _get_working_directory(working_directory):
150-
if not working_directory.startswith('/'):
151-
working_directory = '~/{}'.format(working_directory)
152-
return working_directory
174+
if working_directory.startswith('/') or working_directory.startswith('~/'):
175+
return working_directory
176+
return '~/{}'.format(working_directory)

tests/test_manager.py

Lines changed: 69 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,16 @@
99
import mock
1010

1111

12-
class DockerBasicInteractionTests(unittest.TestCase):
13-
14-
def test_create_files(self):
15-
with Docker() as docker:
16-
docker.run('touch file1')
17-
docker.run('touch file2')
18-
self.assertEqual(docker.list_files(''), ['file1', 'file2'])
19-
20-
def test_create_directories(self):
21-
with Docker() as docker:
22-
docker.run('mkdir dir1')
23-
docker.run('mkdir dir1/test')
24-
docker.run('mkdir dir2')
25-
docker.run('mkdir dir3')
26-
self.assertEqual(
27-
docker.list_directories('', include_trailing_slash=False),
28-
['dir1', 'dir2', 'dir3']
29-
)
30-
31-
def test_create_and_list_files_in_sub_directory(self):
32-
with Docker() as docker:
33-
docker.run('mkdir builds')
34-
docker.run('touch builds/readme.txt')
35-
36-
self.assertEqual(docker.list_files('builds'), ['readme.txt'])
37-
38-
def test_create_file_with_content(self):
39-
with Docker() as docker:
40-
file_name = 'readme.txt'
41-
file_content = 'this is a test file'
42-
43-
self.assertFalse(docker.file_exist(file_name))
44-
docker.create_file(file_name, file_content)
45-
self.assertTrue(docker.file_exist(file_name))
46-
47-
def test_read_file_with_content(self):
48-
with Docker() as docker:
49-
file_name = 'readme.txt'
50-
file_content = 'this is a test file {0}'.format(randint(5000, 5500))
51-
docker.create_file(file_name, file_content)
52-
53-
self.assertEqual(docker.read_file(file_name), file_content)
54-
55-
def test_read_file_that_dont_exist(self):
56-
with Docker() as docker:
57-
self.assertIsNone(docker.read_file('no-file.txt'))
12+
class DockerManagerTests(unittest.TestCase):
13+
"""
14+
This test class should contain tests for the docker manager
15+
that does not invoke docker.
16+
"""
5817

5918
def test__get_working_directory(self):
6019
self.assertEqual(Docker._get_working_directory('directory'), '~/directory')
6120
self.assertEqual(Docker._get_working_directory('/absolute/path'), '/absolute/path')
21+
self.assertEqual(Docker._get_working_directory('~/home/path'), '~/home/path')
6222

6323
@mock.patch('docker.manager.Docker.stop')
6424
@mock.patch('docker.manager.Docker.start')
@@ -79,3 +39,66 @@ def wrapped(docker):
7939
wrapped()
8040
mock_start.assert_called_once_with()
8141
mock_stop.assert_called_once_with()
42+
43+
44+
class DockerInteractionTests(unittest.TestCase):
45+
def setUp(self):
46+
self.docker = Docker()
47+
self.docker.start()
48+
49+
def tearDown(self):
50+
self.docker.stop()
51+
52+
def test_create_files(self):
53+
self.docker.run('touch file1')
54+
self.docker.run('touch file2')
55+
self.assertEqual(self.docker.list_files(''), ['file1', 'file2'])
56+
57+
def test_create_directories(self):
58+
self.docker.run('mkdir dir1')
59+
self.docker.run('mkdir dir1/test')
60+
self.docker.run('mkdir dir2')
61+
self.docker.run('mkdir dir3')
62+
self.assertEqual(
63+
self.docker.list_directories('', include_trailing_slash=False),
64+
['dir1', 'dir2', 'dir3']
65+
)
66+
67+
def test_create_and_list_files_in_sub_directory(self):
68+
self.docker.run('mkdir builds')
69+
self.docker.run('touch builds/readme.txt')
70+
71+
self.assertEqual(self.docker.list_files('builds'), ['readme.txt'])
72+
73+
def test_create_file_with_content(self):
74+
file_name = 'readme.txt'
75+
file_content = 'this is a test file'
76+
77+
self.assertFalse(self.docker.file_exist(file_name))
78+
self.docker.create_file(file_name, file_content)
79+
self.assertTrue(self.docker.file_exist(file_name))
80+
81+
def test_read_file_with_content(self):
82+
file_name = 'readme.txt'
83+
file_content = 'this is a test file {0}'.format(randint(5000, 5500))
84+
self.docker.run('echo \"{0}\" > ~/{1}; cat readme.txt'.format(file_content, file_name))
85+
86+
self.assertEqual(self.docker.read_file(file_name), file_content)
87+
88+
def test_read_file_that_dont_exist(self):
89+
self.assertIsNone(self.docker.read_file('no-file.txt'))
90+
91+
def test_directory_exist(self):
92+
self.assertTrue(self.docker.directory_exist('~/'))
93+
self.assertFalse(self.docker.directory_exist('does-not-exist'))
94+
95+
def test_file_exist(self):
96+
self.docker.run('touch file')
97+
self.assertTrue(self.docker.file_exist('file'))
98+
self.assertFalse(self.docker.file_exist('does-not-exist'))
99+
100+
def test_combine_output(self):
101+
self.docker.combine_outputs = True
102+
result = self.docker.run('ls does-not-exist')
103+
self.assertEqual(result.err, '')
104+
self.assertEqual(result.out, 'ls: cannot access does-not-exist: No such file or directory')

0 commit comments

Comments
 (0)