Further fixes to the Kubernetes config provider, and a new set of proper unit tests
This commit is contained in:
parent
babb7bb803
commit
2ae69dc651
8 changed files with 181 additions and 107 deletions
|
@ -1,60 +1,138 @@
|
|||
import base64
|
||||
import os
|
||||
import json
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
from mock import Mock
|
||||
|
||||
from contextlib import contextmanager
|
||||
from collections import namedtuple
|
||||
from httmock import urlmatch, HTTMock
|
||||
|
||||
from util.config.provider import KubernetesConfigProvider
|
||||
|
||||
from test.fixtures import *
|
||||
def normalize_path(path):
|
||||
return path.replace('/', '_')
|
||||
|
||||
@contextmanager
|
||||
def fake_kubernetes_api(tmpdir_factory, files=None):
|
||||
hostname = 'kubapi'
|
||||
service_account_token_path = str(tmpdir_factory.mktemp("k8s").join("serviceaccount"))
|
||||
auth_header = str(uuid.uuid4())
|
||||
|
||||
with open(service_account_token_path, 'w') as f:
|
||||
f.write(auth_header)
|
||||
|
||||
global secret
|
||||
secret = {
|
||||
'data': {}
|
||||
}
|
||||
|
||||
def write_file(config_dir, filepath, value):
|
||||
normalized_path = normalize_path(filepath)
|
||||
absolute_path = str(config_dir.join(normalized_path))
|
||||
try:
|
||||
os.makedirs(os.path.dirname(absolute_path))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
with open(absolute_path, 'w') as f:
|
||||
f.write(value)
|
||||
|
||||
config_dir = tmpdir_factory.mktemp("config")
|
||||
if files:
|
||||
for filepath, value in files.iteritems():
|
||||
normalized_path = normalize_path(filepath)
|
||||
write_file(config_dir, filepath, value)
|
||||
secret['data'][normalized_path] = base64.b64encode(value)
|
||||
|
||||
@urlmatch(netloc=hostname,
|
||||
path='/api/v1/namespaces/quay-enterprise/secrets/quay-enterprise-config-secret$',
|
||||
method='get')
|
||||
def get_secret(_, __):
|
||||
return {'status_code': 200, 'content': json.dumps(secret)}
|
||||
|
||||
@urlmatch(netloc=hostname,
|
||||
path='/api/v1/namespaces/quay-enterprise/secrets/quay-enterprise-config-secret$',
|
||||
method='put')
|
||||
def put_secret(_, request):
|
||||
updated_secret = json.loads(request.body)
|
||||
for filepath, value in updated_secret['data'].iteritems():
|
||||
if filepath not in secret['data']:
|
||||
# Add
|
||||
write_file(config_dir, filepath, base64.b64decode(value))
|
||||
|
||||
for filepath in secret['data']:
|
||||
if filepath not in updated_secret['data']:
|
||||
# Remove.
|
||||
normalized_path = normalize_path(filepath)
|
||||
os.remove(str(config_dir.join(normalized_path)))
|
||||
|
||||
secret['data'] = updated_secret['data']
|
||||
return {'status_code': 200, 'content': json.dumps(secret)}
|
||||
|
||||
@urlmatch(netloc=hostname, path='/api/v1/namespaces/quay-enterprise$')
|
||||
def get_namespace(_, __):
|
||||
return {'status_code': 200, 'content': json.dumps({})}
|
||||
|
||||
@urlmatch(netloc=hostname)
|
||||
def catch_all(url, _):
|
||||
print url
|
||||
return {'status_code': 404, 'content': '{}'}
|
||||
|
||||
with HTTMock(get_secret, put_secret, get_namespace, catch_all):
|
||||
provider = KubernetesConfigProvider(str(config_dir), 'config.yaml', 'config.py',
|
||||
api_host=hostname,
|
||||
service_account_token_path=service_account_token_path)
|
||||
|
||||
# Validate all the files.
|
||||
for filepath, value in files.iteritems():
|
||||
normalized_path = normalize_path(filepath)
|
||||
assert provider.volume_file_exists(normalized_path)
|
||||
with provider.get_volume_file(normalized_path) as f:
|
||||
assert f.read() == value
|
||||
|
||||
yield provider
|
||||
|
||||
|
||||
class TestKubernetesConfigProvider(KubernetesConfigProvider):
|
||||
def __init__(self):
|
||||
self.config_volume = ''
|
||||
self.yaml_filename = 'yaml_filename'
|
||||
self.py_filename = None
|
||||
def test_basic_config(tmpdir_factory):
|
||||
basic_files = {
|
||||
'config.yaml': 'FOO: bar',
|
||||
}
|
||||
|
||||
self.yaml_path = os.path.join(self.config_volume, self.yaml_filename)
|
||||
|
||||
self._service_token = 'service_token'
|
||||
self._execute_k8s_api = Mock()
|
||||
with fake_kubernetes_api(tmpdir_factory, files=basic_files) as provider:
|
||||
assert provider.config_exists()
|
||||
assert provider.get_config() is not None
|
||||
assert provider.get_config()['FOO'] == 'bar'
|
||||
|
||||
|
||||
@pytest.mark.parametrize('directory,filename,expected', [
|
||||
("directory", "file", "directory_file"),
|
||||
("directory/dir", "file", "directory/dir_file"),
|
||||
("directory/dir/", "file", "directory/dir_file"),
|
||||
("directory", "file/test", "directory_file/test"),
|
||||
@pytest.mark.parametrize('filepath', [
|
||||
'foo',
|
||||
'foo/meh',
|
||||
'foo/bar/baz',
|
||||
])
|
||||
def test_get_volume_path(directory, filename, expected):
|
||||
provider = TestKubernetesConfigProvider()
|
||||
assert expected == provider.get_volume_path(directory, filename)
|
||||
def test_remove_file(filepath, tmpdir_factory):
|
||||
basic_files = {
|
||||
filepath: 'foo',
|
||||
}
|
||||
|
||||
with fake_kubernetes_api(tmpdir_factory, files=basic_files) as provider:
|
||||
normalized_path = normalize_path(filepath)
|
||||
assert provider.volume_file_exists(normalized_path)
|
||||
provider.remove_volume_file(normalized_path)
|
||||
assert not provider.volume_file_exists(normalized_path)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('response,expected', [
|
||||
(Mock(text="{\"data\": {\"license\":\"test\"}}", status_code=200), {"data": {"license":"test"}}),
|
||||
(Mock(text="{\"data\": {\"license\":\"test\"}}", status_code=404), None),
|
||||
])
|
||||
def test_lookup_secret(response, expected):
|
||||
provider = TestKubernetesConfigProvider()
|
||||
provider._execute_k8s_api.return_value = response
|
||||
assert expected == provider._lookup_secret()
|
||||
|
||||
|
||||
@pytest.mark.parametrize('response,key,expected', [
|
||||
(Mock(text="{\"data\": {\"license\":\"test\"}}", status_code=200), "license", True),
|
||||
(Mock(text="{\"data\": {\"license\":\"test\"}}", status_code=200), "config.yaml", False),
|
||||
(Mock(text="", status_code=404), "license", False),
|
||||
])
|
||||
def test_volume_file_exists(response, key, expected):
|
||||
provider = TestKubernetesConfigProvider()
|
||||
provider._execute_k8s_api.return_value = response
|
||||
assert expected == provider.volume_file_exists(key)
|
||||
class TestFlaskFile(object):
|
||||
def save(self, buf):
|
||||
buf.write('hello world!')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('response,expected', [
|
||||
(Mock(text="{\"data\": {\"extra_license\":\"test\"}}", status_code=200), ["license"]),
|
||||
(Mock(text="", status_code=404), []),
|
||||
])
|
||||
def test_list_volume_directory(response, expected):
|
||||
provider = TestKubernetesConfigProvider()
|
||||
provider._execute_k8s_api.return_value = response
|
||||
assert expected == provider.list_volume_directory("extra")
|
||||
def test_save_file(tmpdir_factory):
|
||||
basic_files = {}
|
||||
|
||||
with fake_kubernetes_api(tmpdir_factory, files=basic_files) as provider:
|
||||
assert not provider.volume_file_exists('testfile')
|
||||
flask_file = TestFlaskFile()
|
||||
provider.save_volume_file(flask_file, 'testfile')
|
||||
assert provider.volume_file_exists('testfile')
|
||||
|
|
Reference in a new issue