Skip to content

Commit e2ad91b

Browse files
committed
Exec API tests
1 parent 0fd70b4 commit e2ad91b

File tree

4 files changed

+148
-28
lines changed

4 files changed

+148
-28
lines changed

docker/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ def exec_resize(self, exec_id, height=None, width=None):
569569
'w': width
570570
}
571571
res = self._post_json(
572-
self._url('exec/{0}/resize'.format(exec_id)), data
572+
self._url('/exec/{0}/resize'.format(exec_id)), data
573573
)
574574
res.raise_for_status()
575575

tests/fake_api.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
FAKE_CONTAINER_ID = '3cc2351ab11b'
2020
FAKE_IMAGE_ID = 'e9aa60c60128'
21+
FAKE_EXEC_ID = 'd5d177f121dc'
2122
FAKE_IMAGE_NAME = 'test_image'
2223
FAKE_TARBALL_PATH = '/path/to/tarball'
2324
FAKE_REPO_NAME = 'repo'
@@ -247,20 +248,44 @@ def get_fake_export():
247248
return status_code, response
248249

249250

250-
def post_fake_execute():
251+
def post_fake_exec_create():
251252
status_code = 200
252-
response = {'Id': FAKE_CONTAINER_ID}
253+
response = {'Id': FAKE_EXEC_ID}
253254
return status_code, response
254255

255256

256-
def post_fake_execute_start():
257+
def post_fake_exec_start():
257258
status_code = 200
258259
response = (b'\x01\x00\x00\x00\x00\x00\x00\x11bin\nboot\ndev\netc\n'
259260
b'\x01\x00\x00\x00\x00\x00\x00\x12lib\nmnt\nproc\nroot\n'
260261
b'\x01\x00\x00\x00\x00\x00\x00\x0csbin\nusr\nvar\n')
261262
return status_code, response
262263

263264

265+
def post_fake_exec_resize():
266+
status_code = 201
267+
return status_code, ''
268+
269+
270+
def get_fake_exec_inspect():
271+
return 200, {
272+
'OpenStderr': True,
273+
'OpenStdout': True,
274+
'Container': get_fake_inspect_container()[1],
275+
'Running': False,
276+
'ProcessConfig': {
277+
'arguments': ['hello world'],
278+
'tty': False,
279+
'entrypoint': 'echo',
280+
'privileged': False,
281+
'user': ''
282+
},
283+
'ExitCode': 0,
284+
'ID': FAKE_EXEC_ID,
285+
'OpenStdin': False
286+
}
287+
288+
264289
def post_fake_stop_container():
265290
status_code = 200
266291
response = {'Id': FAKE_CONTAINER_ID}
@@ -393,9 +418,14 @@ def get_fake_stats():
393418
'{1}/{0}/containers/3cc2351ab11b/export'.format(CURRENT_VERSION, prefix):
394419
get_fake_export,
395420
'{1}/{0}/containers/3cc2351ab11b/exec'.format(CURRENT_VERSION, prefix):
396-
post_fake_execute,
397-
'{1}/{0}/exec/3cc2351ab11b/start'.format(CURRENT_VERSION, prefix):
398-
post_fake_execute_start,
421+
post_fake_exec_create,
422+
'{1}/{0}/exec/d5d177f121dc/start'.format(CURRENT_VERSION, prefix):
423+
post_fake_exec_start,
424+
'{1}/{0}/exec/d5d177f121dc/json'.format(CURRENT_VERSION, prefix):
425+
get_fake_exec_inspect,
426+
'{1}/{0}/exec/d5d177f121dc/resize'.format(CURRENT_VERSION, prefix):
427+
post_fake_exec_resize,
428+
399429
'{1}/{0}/containers/3cc2351ab11b/stats'.format(CURRENT_VERSION, prefix):
400430
get_fake_stats,
401431
'{1}/{0}/containers/3cc2351ab11b/stop'.format(CURRENT_VERSION, prefix):

tests/integration_test.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,9 +1071,12 @@ def runTest(self):
10711071
self.client.start(id)
10721072
self.tmp_containers.append(id)
10731073

1074-
res = self.client.execute(id, ['echo', 'hello'])
1074+
res = self.client.exec_create(id, ['echo', 'hello'])
1075+
self.assertIn('Id', res)
1076+
1077+
exec_log = self.client.exec_start(res)
10751078
expected = b'hello\n' if six.PY3 else 'hello\n'
1076-
self.assertEqual(res, expected)
1079+
self.assertEqual(exec_log, expected)
10771080

10781081

10791082
@unittest.skipIf(not EXEC_DRIVER_IS_NATIVE, 'Exec driver not native')
@@ -1085,9 +1088,12 @@ def runTest(self):
10851088
self.client.start(id)
10861089
self.tmp_containers.append(id)
10871090

1088-
res = self.client.execute(id, 'echo hello world', stdout=True)
1091+
res = self.client.exec_create(id, 'echo hello world')
1092+
self.assertIn('Id', res)
1093+
1094+
exec_log = self.client.exec_start(res)
10891095
expected = b'hello world\n' if six.PY3 else 'hello world\n'
1090-
self.assertEqual(res, expected)
1096+
self.assertEqual(exec_log, expected)
10911097

10921098

10931099
@unittest.skipIf(not EXEC_DRIVER_IS_NATIVE, 'Exec driver not native')
@@ -1099,14 +1105,33 @@ def runTest(self):
10991105
self.client.start(id)
11001106
self.tmp_containers.append(id)
11011107

1102-
chunks = self.client.execute(id, ['echo', 'hello\nworld'], stream=True)
1108+
exec_id = self.client.exec_create(id, ['echo', 'hello\nworld'])
1109+
self.assertIn('Id', exec_id)
1110+
11031111
res = b'' if six.PY3 else ''
1104-
for chunk in chunks:
1112+
for chunk in self.client.exec_start(exec_id, stream=True):
11051113
res += chunk
11061114
expected = b'hello\nworld\n' if six.PY3 else 'hello\nworld\n'
11071115
self.assertEqual(res, expected)
11081116

11091117

1118+
@unittest.skipIf(not EXEC_DRIVER_IS_NATIVE, 'Exec driver not native')
1119+
class TestExecInspect(BaseTestCase):
1120+
def runTest(self):
1121+
container = self.client.create_container('busybox', 'cat',
1122+
detach=True, stdin_open=True)
1123+
id = container['Id']
1124+
self.client.start(id)
1125+
self.tmp_containers.append(id)
1126+
1127+
exec_id = self.client.exec_create(id, ['mkdir', '/does/not/exist'])
1128+
self.assertIn('Id', exec_id)
1129+
self.client.exec_start(exec_id)
1130+
exec_info = self.client.exec_inspect(exec_id)
1131+
self.assertIn('ExitCode', exec_info)
1132+
self.assertNotEqual(exec_info['ExitCode'], 0)
1133+
1134+
11101135
class TestRunContainerStreaming(BaseTestCase):
11111136
def runTest(self):
11121137
container = self.client.create_container('busybox', '/bin/sh',

tests/test.py

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,31 +1583,96 @@ def test_stop_container_with_dict_instead_of_id(self):
15831583
timeout=(docker.client.DEFAULT_TIMEOUT_SECONDS + timeout)
15841584
)
15851585

1586-
def test_execute_command(self):
1586+
def test_exec_create(self):
15871587
try:
1588-
self.client.execute(fake_api.FAKE_CONTAINER_ID, ['ls', '-1'])
1588+
self.client.exec_create(fake_api.FAKE_CONTAINER_ID, ['ls', '-1'])
15891589
except Exception as e:
15901590
self.fail('Command should not raise exception: {0}'.format(e))
15911591

15921592
args = fake_request.call_args
1593-
self.assertEqual(args[0][0],
1594-
url_prefix + 'exec/3cc2351ab11b/start')
1593+
self.assertEqual(
1594+
args[0][0], url_prefix + 'containers/{0}/exec'.format(
1595+
fake_api.FAKE_CONTAINER_ID
1596+
)
1597+
)
15951598

1596-
self.assertEqual(json.loads(args[1]['data']),
1597-
json.loads('''{
1598-
"Tty": false,
1599-
"AttachStderr": true,
1600-
"Container": "3cc2351ab11b",
1601-
"Cmd": ["ls", "-1"],
1602-
"AttachStdin": false,
1603-
"User": "",
1604-
"Detach": false,
1605-
"Privileged": false,
1606-
"AttachStdout": true}'''))
1599+
self.assertEqual(
1600+
json.loads(args[1]['data']), {
1601+
'Tty': False,
1602+
'AttachStdout': True,
1603+
'Container': fake_api.FAKE_CONTAINER_ID,
1604+
'Detach': False,
1605+
'Cmd': ['ls', '-1'],
1606+
'Privileged': False,
1607+
'AttachStdin': False,
1608+
'AttachStderr': True,
1609+
'User': ''
1610+
}
1611+
)
16071612

16081613
self.assertEqual(args[1]['headers'],
16091614
{'Content-Type': 'application/json'})
16101615

1616+
def test_exec_start(self):
1617+
try:
1618+
self.client.exec_start(fake_api.FAKE_EXEC_ID)
1619+
except Exception as e:
1620+
self.fail('Command should not raise exception: {0}'.format(e))
1621+
1622+
args = fake_request.call_args
1623+
self.assertEqual(
1624+
args[0][0], url_prefix + 'exec/{0}/start'.format(
1625+
fake_api.FAKE_EXEC_ID
1626+
)
1627+
)
1628+
1629+
self.assertEqual(
1630+
json.loads(args[1]['data']), {
1631+
'Tty': False,
1632+
'Detach': False,
1633+
}
1634+
)
1635+
1636+
self.assertEqual(args[1]['headers'],
1637+
{'Content-Type': 'application/json'})
1638+
1639+
def test_exec_inspect(self):
1640+
try:
1641+
self.client.exec_inspect(fake_api.FAKE_EXEC_ID)
1642+
except Exception as e:
1643+
self.fail('Command should not raise exception: {0}'.format(e))
1644+
1645+
args = fake_request.call_args
1646+
self.assertEqual(
1647+
args[0][0], url_prefix + 'exec/{0}/json'.format(
1648+
fake_api.FAKE_EXEC_ID
1649+
)
1650+
)
1651+
1652+
def test_exec_resize(self):
1653+
try:
1654+
self.client.exec_resize(fake_api.FAKE_EXEC_ID, height=20, width=60)
1655+
except Exception as e:
1656+
self.fail('Command should not raise exception: {0}'.format(e))
1657+
1658+
args = fake_request.call_args
1659+
self.assertEqual(
1660+
args[0][0], url_prefix + 'exec/{0}/resize'.format(
1661+
fake_api.FAKE_EXEC_ID
1662+
)
1663+
)
1664+
1665+
self.assertEqual(
1666+
json.loads(args[1]['data']), {
1667+
'h': 20,
1668+
'w': 60,
1669+
}
1670+
)
1671+
1672+
self.assertEqual(
1673+
args[1]['headers'], {'Content-Type': 'application/json'}
1674+
)
1675+
16111676
def test_pause_container(self):
16121677
try:
16131678
self.client.pause(fake_api.FAKE_CONTAINER_ID)

0 commit comments

Comments
 (0)