initial import of unit test and mocks for the docker api

This commit is contained in:
Deni Bertovic 2013-09-25 23:50:46 +02:00
parent 8047fb4cb4
commit 80e11964f1
2 changed files with 608 additions and 0 deletions

231
tests/fake_api.py Normal file
View File

@ -0,0 +1,231 @@
import json
CURRENT_VERSION = 'v1.4'
FAKE_CONTAINER_ID = '3cc2351ab11b'
FAKE_IMAGE_ID = 'e9aa60c60128'
FAKE_INSPECT_DATA = {
"ID": "3cc2351ab11bca2e319f49b547834f550eb0c0505a636dc4d24c5b5e03845927",
"Created": "2013-09-25T14:01:18.867354259+02:00",
"Path": "/bin/sh",
"Args": [
"-c",
"mkdir -p /tmp/test"
],
"Config": {
"Hostname": FAKE_CONTAINER_ID,
"Domainname": "",
"User": "",
"Memory": 0,
"MemorySwap": 0,
"CpuShares": 0,
"AttachStdin": False,
"AttachStdout": False,
"AttachStderr": False,
"PortSpecs": [
"8080"
],
"Tty": False,
"OpenStdin": False,
"StdinOnce": False,
"Env": [
"HOME=/",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": None,
"Dns": None,
"Image": "b9517f6e2d833745eb5f893ea901abe5ea8247fab8e569e1d3280881ab84284b",
"Volumes": None,
"VolumesFrom": "",
"WorkingDir": "",
"Entrypoint": None,
"NetworkDisabled": False,
"Privileged": False
},
"State": {
"Running": False,
"Pid": 0,
"ExitCode": 0,
"StartedAt": "2013-09-25T14:01:18.869545111+02:00",
"Ghost": False
},
"Image": "9330a90e5753f16df757d865700365263946bd7e6b6439e44622e5952bb5033e",
"NetworkSettings": {
"IPAddress": "",
"IPPrefixLen": 0,
"Gateway": "",
"Bridge": "",
"PortMapping": None
},
"SysInitPath": "/opt/docker/docker",
"ResolvConfPath": "/etc/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/800680f2e4ccca2e319f49b547834f550eb0c0505a636dc4d24c5b5e03845927/hostname",
"HostsPath": "/var/lib/docker/containers/800680f2e4ccca2e319f49b547834f550eb0c0505a636dc4d24c5b5e03845927/hosts",
"Volumes": {},
"VolumesRW": {}
}
### Each method is prefixed with HTTP method (get, post...)
### for clarity and readability
def get_fake_version():
status_code = 200
response = json.dumps({'GoVersion': '1', 'Version': '1.1.1'})
return status_code, response
def get_fake_info():
status_code = 200
response = json.dumps({'Containers': 1, 'Images': 1, 'Debug': ''})
return status_code, response
def get_fake_search():
status_code = 200
response = json.dumps([{'Name': 'busybox', 'Description': 'Fake Description'}])
return status_code, response
def get_fake_images():
status_code = 200
response = json.dumps([
{'Id': FAKE_IMAGE_ID, 'Created': '2 days ago', 'Repository': 'busybox', 'Tag': 'latest'}
])
return status_code, response
def get_fake_containers():
status_code = 200
response = json.dumps([
{'Id': FAKE_CONTAINER_ID,
'Image': 'busybox:latest',
'Created': '2 days ago',
'Command': 'true',
'Status': 'fake status'}
])
return status_code, response
def post_fake_start_container():
status_code = 200
response = json.dumps({'Id': FAKE_CONTAINER_ID})
return status_code, response
def post_fake_create_container():
status_code = 200
response = json.dumps({'Id': FAKE_CONTAINER_ID})
return status_code, response
def get_fake_inspect_container():
status_code = 200
response = json.dumps({
'Id': FAKE_CONTAINER_ID,
'Config': {'Privileged': True},
'ID': FAKE_CONTAINER_ID,
'Image': 'busybox:latest',
"State": {
"Running": True,
"Pid": 0,
"ExitCode": 0,
"StartedAt": "2013-09-25T14:01:18.869545111+02:00",
"Ghost": False
},
})
return status_code, response
def get_fake_wait():
status_code = 200
response = json.dumps({'StatusCode': 0})
return status_code, response
def get_fake_logs():
status_code = 200
response = 'Flowering Nights (Sakuya Iyazoi)'
return status_code, response
def get_fake_diff():
status_code = 200
response = json.dumps([{'Path': '/test', 'Kind': 1}])
return status_code, response
def post_fake_stop_container():
status_code = 200
response = json.dumps({'Id': FAKE_CONTAINER_ID})
return status_code, response
def post_fake_kill_container():
status_code = 200
response = json.dumps({'Id': FAKE_CONTAINER_ID})
return status_code, response
def post_fake_restart_container():
status_code = 200
response = json.dumps({'Id': FAKE_CONTAINER_ID})
return status_code, response
def delete_fake_remove_container():
status_code = 200
response = json.dumps({'Id': FAKE_CONTAINER_ID})
return status_code, response
def post_fake_image_create():
status_code = 200
response = json.dumps({'Id': FAKE_IMAGE_ID})
return status_code, response
def delete_fake_remove_image():
status_code = 200
response = json.dumps({'Id': FAKE_IMAGE_ID})
return status_code, response
def post_fake_commit():
status_code = 200
response = json.dumps({'Id': FAKE_CONTAINER_ID})
return status_code, response
def post_fake_build_container():
status_code = 200
response = json.dumps({'Id': FAKE_CONTAINER_ID})
return status_code, response
## maps real api url to fake response callback
fake_responses = {
'unix://var/run/docker.sock/{0}/version'.format(CURRENT_VERSION): get_fake_version,
'unix://var/run/docker.sock/{0}/info'.format(CURRENT_VERSION): get_fake_info,
'unix://var/run/docker.sock/{0}/images/search'.format(CURRENT_VERSION): get_fake_search,
'unix://var/run/docker.sock/{0}/images/json'.format(CURRENT_VERSION): get_fake_images,
'unix://var/run/docker.sock/{0}/containers/ps'.format(CURRENT_VERSION): get_fake_containers,
'unix://var/run/docker.sock/{0}/containers/3cc2351ab11b/start'.format(CURRENT_VERSION): post_fake_start_container,
'unix://var/run/docker.sock/{0}/containers/3cc2351ab11b/json'.format(CURRENT_VERSION): get_fake_inspect_container,
'unix://var/run/docker.sock/{0}/containers/3cc2351ab11b/wait'.format(CURRENT_VERSION): get_fake_wait,
'unix://var/run/docker.sock/{0}/containers/3cc2351ab11b/attach'.format(CURRENT_VERSION): get_fake_logs,
'unix://var/run/docker.sock/{0}/containers/3cc2351ab11b/changes'.format(CURRENT_VERSION): get_fake_diff,
'unix://var/run/docker.sock/{0}/containers/3cc2351ab11b/stop'.format(CURRENT_VERSION): post_fake_stop_container,
'unix://var/run/docker.sock/{0}/containers/3cc2351ab11b/kill'.format(CURRENT_VERSION): post_fake_kill_container,
'unix://var/run/docker.sock/{0}/containers/3cc2351ab11b/restart'.format(CURRENT_VERSION): post_fake_restart_container,
'unix://var/run/docker.sock/{0}/containers/3cc2351ab11b'.format(CURRENT_VERSION): delete_fake_remove_container,
'unix://var/run/docker.sock/{0}/images/create'.format(CURRENT_VERSION): post_fake_image_create,
'unix://var/run/docker.sock/{0}/images/e9aa60c60128'.format(CURRENT_VERSION): delete_fake_remove_image,
'unix://var/run/docker.sock/{0}/commit'.format(CURRENT_VERSION): post_fake_commit,
'unix://var/run/docker.sock/{0}/containers/create'.format(CURRENT_VERSION): post_fake_create_container,
'unix://var/run/docker.sock/{0}/build'.format(CURRENT_VERSION): post_fake_build_container
}

377
tests/test.py Normal file
View File

@ -0,0 +1,377 @@
# Copyright 2013 dotCloud inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import base64
import os
from StringIO import StringIO
import tempfile
import unittest
import docker
import six
import requests
from requests import structures
import datetime
import json
from fake_api import fake_responses, FAKE_CONTAINER_ID, FAKE_IMAGE_ID
# FIXME: missing tests for
# export; history; import_image; insert; port; push; tag
def response(status_code=200, content='', headers=None, reason=None, elapsed=0,
request=None):
res = requests.Response()
res.status_code = status_code
if isinstance(content, dict):
content = json.dumps(content)
res._content = content
res.headers = structures.CaseInsensitiveDict(headers or {})
res.reason = reason
res.elapsed = datetime.timedelta(elapsed)
return res
def fake_get(self, url, **kwargs):
status_code, content = fake_responses[url]()
return response(status_code=status_code, content=content)
def fake_post(self, url, data=None, **kwargs):
status_code, content = fake_responses[url]()
return response(status_code=status_code, content=content)
def fake_put(self, url, data=None, **kwargs):
status_code, content = fake_responses[url]()
return response(status_code=status_code, content=content)
def fake_delete(self, url, data=None, **kwargs):
status_code, content = fake_responses[url]()
return response(status_code=status_code, content=content)
docker.Client.get = fake_get
docker.Client.post = fake_post
docker.Client.put = fake_put
docker.Client.delete = fake_delete
class BaseTestCase(unittest.TestCase):
def setUp(self):
self.client = docker.Client()
#########################
## INFORMATION TESTS ##
#########################
class TestVersion(BaseTestCase):
def runTest(self):
try:
self.client.version()
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestInfo(BaseTestCase):
def runTest(self):
try:
self.client.info()
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestSearch(BaseTestCase):
def runTest(self):
try:
self.client.search('busybox')
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
# ###################
# ## LISTING TESTS ##
# ###################
class TestImages(BaseTestCase):
def runTest(self):
try:
self.client.images(all=True)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestImageIds(BaseTestCase):
def runTest(self):
try:
self.client.images(quiet=True)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestListContainers(BaseTestCase):
def runTest(self):
try:
self.client.containers(all=True)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
#####################
## CONTAINER TESTS ##
#####################
class TestCreateContainer(BaseTestCase):
def runTest(self):
try:
self.client.create_container('busybox', 'true')
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestCreateContainerWithBinds(BaseTestCase):
def runTest(self):
mount_dest = '/mnt'
mount_origin = '/tmp'
try:
self.client.create_container('busybox',
['ls', mount_dest], volumes={mount_dest: {}})
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestCreateContainerPrivileged(BaseTestCase):
def runTest(self):
try:
self.client.create_container('busybox', 'true', privileged=True)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestStartContainer(BaseTestCase):
def runTest(self):
try:
self.client.start(FAKE_CONTAINER_ID)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestStartContainerWithBinds(BaseTestCase):
def runTest(self):
try:
mount_dest = '/mnt'
mount_origin = '/tmp'
self.client.start(FAKE_CONTAINER_ID, binds={mount_origin: mount_dest})
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestStartContainerWithDictInsteadOfId(BaseTestCase):
def runTest(self):
try:
self.client.start({'Id': FAKE_CONTAINER_ID})
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestWait(BaseTestCase):
def runTest(self):
try:
self.client.wait(FAKE_CONTAINER_ID)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestWaitWithDictInsteadOfId(BaseTestCase):
def runTest(self):
try:
self.client.wait({'Id': FAKE_CONTAINER_ID})
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestLogs(BaseTestCase):
def runTest(self):
try:
self.client.logs(FAKE_CONTAINER_ID)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestLogsWithDictInsteadOfId(BaseTestCase):
def runTest(self):
try:
self.client.logs({'Id': FAKE_CONTAINER_ID})
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestDiff(BaseTestCase):
def runTest(self):
try:
self.client.diff(FAKE_CONTAINER_ID)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestDiffWithDictInsteadOfId(BaseTestCase):
def runTest(self):
try:
self.client.diff({'Id': FAKE_CONTAINER_ID})
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestStop(BaseTestCase):
def runTest(self):
try:
self.client.stop(FAKE_CONTAINER_ID, timeout=2)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestStopWithDictInsteadOfId(BaseTestCase):
def runTest(self):
try:
self.client.stop({'Id': FAKE_CONTAINER_ID}, timeout=2)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestKill(BaseTestCase):
def runTest(self):
try:
self.client.kill(FAKE_CONTAINER_ID)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestKillWithDictInsteadOfId(BaseTestCase):
def runTest(self):
try:
self.client.kill({'Id': FAKE_CONTAINER_ID})
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestRestart(BaseTestCase):
def runTest(self):
try:
self.client.restart(FAKE_CONTAINER_ID, timeout=2)
except Exception as e:
self.fail('Command should not raise exception : ' + str(e))
class TestRestartWithDictInsteadOfId(BaseTestCase):
def runTest(self):
try:
self.client.restart({'Id': FAKE_CONTAINER_ID}, timeout=2)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestRemoveContainer(BaseTestCase):
def runTest(self):
try:
self.client.remove_container(FAKE_CONTAINER_ID)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestRemoveContainerWithDictInsteadOfId(BaseTestCase):
def runTest(self):
try:
self.client.remove_container({'Id': FAKE_CONTAINER_ID})
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
# ##################
# ## IMAGES TESTS ##
# ##################
class TestPull(BaseTestCase):
def runTest(self):
try:
self.client.pull('joffrey/test001')
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestCommit(BaseTestCase):
def runTest(self):
try:
self.client.commit(FAKE_CONTAINER_ID)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
class TestRemoveImage(BaseTestCase):
def runTest(self):
try:
self.client.remove_image(FAKE_IMAGE_ID)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
# #################
# # BUILDER TESTS #
# #################
class TestBuild(BaseTestCase):
def runTest(self):
script = StringIO('\n'.join([
'FROM busybox',
'MAINTAINER docker-py',
'RUN mkdir -p /tmp/test',
'EXPOSE 8080',
'ADD https://dl.dropboxusercontent.com/u/20637798/silence.tar.gz /tmp/silence.tar.gz'
]))
try:
self.client.build(fileobj=script)
except Exception as e:
self.fail('Command should not raise exception: ' + str(e))
# #######################
# ## PY SPECIFIC TESTS ##
# #######################
class TestLoadConfig(BaseTestCase):
def runTest(self):
folder = tempfile.mkdtemp()
f = open(os.path.join(folder, '.dockercfg'), 'w')
auth_ = base64.b64encode('sakuya:izayoi')
f.write('auth = {0}\n'.format(auth_))
f.write('email = sakuya@scarlet.net')
f.close()
cfg = docker.auth.load_config(folder)
self.assertNotEqual(cfg['Configs'][docker.auth.INDEX_URL], None)
cfg = cfg['Configs'][docker.auth.INDEX_URL]
self.assertEqual(cfg['Username'], 'sakuya')
self.assertEqual(cfg['Password'], 'izayoi')
self.assertEqual(cfg['Email'], 'sakuya@scarlet.net')
self.assertEqual(cfg.get('Auth'), None)
if __name__ == '__main__':
unittest.main()