Example #1
0
async def connect_juju(ctrl_name=None,
                       model_name=None,
                       endpoint=None,
                       username=None,
                       password=None,
                       cacert=None):
    controller = Controller(max_frame_size=MAX_FRAME_SIZE)  # noqa

    if endpoint:
        await controller.connect(endpoint=endpoint,
                                 username=username,
                                 password=password,
                                 cacert=cacert)
    else:
        await controller.connect(ctrl_name)

    if endpoint:
        model = Model(max_frame_size=MAX_FRAME_SIZE)
        await model.connect(uuid=model_name,
                            endpoint=endpoint,
                            username=username,
                            password=password,
                            cacert=cacert)
    elif model_name:
        model = await controller.get_model(model_name)
    else:
        model = Model(max_frame_size=MAX_FRAME_SIZE)  # noqa
        await model.connect()

    # HACK low unsettable timeout in the model
    model.charmstore._cs = CharmStore(timeout=60)

    return controller, model
Example #2
0
import collections
import gfm
import os
import re

from jujubundlelib import references
from theblues.charmstore import CharmStore
from theblues.errors import EntityNotFound, ServerError
from theblues.terms import Terms


cs = CharmStore()
terms = Terms("https://api.jujucharms.com/terms/")

SEARCH_LIMIT = 400


def search_entities(
    query,
    entity_type=None,
    tags=None,
    sort=None,
    series=None,
    owner=None,
    promulgated_only=None,
):
    includes = [
        "charm-metadata",
        "bundle-metadata",
        "owner",
        "bundle-unit-count",
Example #3
0
from flask import Blueprint, render_template, abort, current_app
from theblues.charmstore import CharmStore
from pprint import pformat

jaasstore = Blueprint('jaasstore',
                      __name__,
                      template_folder='/templates',
                      static_folder='/static')

cs = CharmStore("https://api.jujucharms.com/v5")


@jaasstore.route('/store')
def store():
    return render_template('store/store.html')


@jaasstore.route('/<entity_name>')
def details(entity_name):
    try:
        entity = cs.entity(entity_name)
        entity_formatted = pformat(entity, 1, 120)
    except Exception:
        return abort(404, "Entity not found {}".format(entity_name))

    return render_template('store/details.html', entity=entity_formatted)
Example #4
0
import collections
import os
import re
import markdown

from mdx_gfm import GithubFlavoredMarkdownExtension
from jujubundlelib import references
from theblues.charmstore import CharmStore
from theblues.errors import EntityNotFound, ServerError
from theblues.terms import Terms

cs = CharmStore(timeout=5)
terms = Terms("https://api.jujucharms.com/terms/")

SEARCH_LIMIT = 400

markdown = markdown.Markdown(extensions=[GithubFlavoredMarkdownExtension()])


def search_entities(
    query,
    entity_type=None,
    tags=None,
    sort=None,
    series=None,
    owner=None,
    promulgated_only=None,
):
    includes = [
        "charm-metadata",
        "bundle-metadata",
Example #5
0
 def setUp(self):
     self.cs = CharmStore('http://example.com')
Example #6
0
class TestCharmStore(TestCase):

    def entities_response(self, url, request):
        self.assertEqual(
            url.geturl(), 'http://example.com/meta/' +
            'any?include=id&id=wordpress&id=mysql')
        return {
            'status_code': 200,
            'content': b'{"wordpress":"wordpress","mysql":"mysql"}'}

    def setUp(self):
        self.cs = CharmStore('http://example.com')

    def test_init(self):
        self.assertEqual(self.cs.url, 'http://example.com')

    def test_entity(self):
        with HTTMock(entity_200):
            data = self.cs.charm(SAMPLE_CHARM)
        self.assertEqual({'Meta': {'charm-metadata': {'exists': True}}}, data)

    def test_entity_full_id(self):
        with HTTMock(entity_200):
            data = self.cs.charm(SAMPLE_CHARM_ID)
        self.assertEqual({'Meta': {'charm-metadata': {'exists': True}}}, data)

    def test_entity_reference(self):
        with HTTMock(entity_200):
            data = self.cs.charm(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual({'Meta': {'charm-metadata': {'exists': True}}}, data)

    def test_entities(self):
        with HTTMock(self.entities_response):
            response = self.cs.entities(['wordpress', 'mysql'])
        self.assertEqual(
            {u'wordpress': u'wordpress', u'mysql': u'mysql'}, response)

    def test_entities_reference(self):
        with HTTMock(self.entities_response):
            response = self.cs.entities(
                [references.Reference.from_string('wordpress'),
                 references.Reference.from_string('mysql')])
        self.assertEqual(
            {u'wordpress': u'wordpress', u'mysql': u'mysql'}, response)

    def test_entities_error(self):
        with HTTMock(entity_404):
            with self.assertRaises(EntityNotFound) as cm:
                self.cs.entities(['not-found'])
            self.assertEqual(
                'http://example.com/meta/any?include=id&id=not-found',
                cm.exception.args[0]
            )

    def test_charm_error(self):
        with HTTMock(entity_404):
            with self.assertRaises(EntityNotFound):
                self.cs.charm(SAMPLE_CHARM)

    def test_charm_error_id(self):
        with HTTMock(entity_404):
            with self.assertRaises(EntityNotFound):
                self.cs.charm(SAMPLE_CHARM_ID)

    def test_charm_error_407(self):
        with HTTMock(entity_407):
            with self.assertRaises(EntityNotFound):
                self.cs.charm(SAMPLE_CHARM)

    def test_config(self):
        with HTTMock(config_200):
            data = self.cs.config(SAMPLE_CHARM)
        self.assertEqual({'exists': True}, data)

    def test_config_reference(self):
        with HTTMock(config_200):
            data = self.cs.config(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual({'exists': True}, data)

    def test_config_error(self):
        with HTTMock(config_404):
            with self.assertRaises(EntityNotFound):
                self.cs.config(SAMPLE_CHARM)

    def test_archive_url(self):
        with HTTMock(manifest_200):
            data = self.cs.archive_url(SAMPLE_CHARM)
        self.assertEqual(u'http://example.com/precise/mysql-1/archive', data)

    def test_archive_url_reference(self):
        with HTTMock(manifest_200):
            data = self.cs.archive_url(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual(u'http://example.com/precise/mysql-1/archive', data)

    def test_file_good(self):
        with HTTMock(manifest_200):
            data = self.cs.files(SAMPLE_CHARM)
        self.assertEqual({
            u'icon.svg':
            u'http://example.com/precise/mysql-1/archive/icon.svg',
            u'README.md':
            u'http://example.com/precise/mysql-1/archive/README.md'
            },
            data)

    def test_file_good_reference(self):
        with HTTMock(manifest_200):
            data = self.cs.files(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual({
            u'icon.svg':
            u'http://example.com/precise/mysql-1/archive/icon.svg',
            u'README.md':
            u'http://example.com/precise/mysql-1/archive/README.md'
            },
            data)

    def test_file_error(self):
        with HTTMock(manifest_404):
            with self.assertRaises(EntityNotFound):
                self.cs.files(SAMPLE_CHARM)

    def test_file_one_file(self):
        with HTTMock(manifest_200):
            data = self.cs.files(SAMPLE_CHARM, filename='README.md')
        self.assertEqual(
            u'http://example.com/precise/mysql-1/archive/README.md',
            data)

    def test_file_one_file_reference(self):
        with HTTMock(manifest_200):
            data = self.cs.files(
                references.Reference.from_string(SAMPLE_CHARM),
                filename='README.md')
        self.assertEqual(
            u'http://example.com/precise/mysql-1/archive/README.md',
            data)

    def test_file_one_file_error(self):
        with HTTMock(manifest_200):
            with self.assertRaises(EntityNotFound):
                self.cs.files(SAMPLE_CHARM, filename='does.not.exist.md')

    def test_file_read_file(self):
        with HTTMock(manifest_200):
            with HTTMock(file_200):
                data = self.cs.files(
                    SAMPLE_CHARM, filename='README.md', read_file=True)
        self.assertEqual('This is a file.', data)

    def test_file_read_file_reference(self):
        with HTTMock(manifest_200):
            with HTTMock(file_200):
                data = self.cs.files(
                    references.Reference.from_string(SAMPLE_CHARM),
                    filename='README.md',
                    read_file=True)
        self.assertEqual('This is a file.', data)

    def test_file_read_file_error(self):
        with HTTMock(manifest_200):
            with HTTMock(file_404):
                with self.assertRaises(EntityNotFound):
                    self.cs.files(
                        SAMPLE_CHARM, filename='readme.md', read_file=True)

    def test_entityId(self):
        with HTTMock(id_200):
            charm_id = self.cs.entityId('bar')
            self.assertEqual('foo/bar', charm_id)

    def test_entityId_reference(self):
        with HTTMock(id_200):
            charm_id = self.cs.entityId(
                references.Reference.from_string('bar'))
            self.assertEqual('foo/bar', charm_id)

    def test_ids_no_charm(self):
        with HTTMock(id_404):
            with self.assertRaises(EntityNotFound):
                self.cs.entityId('baz')

    def test_search(self):
        with HTTMock(search_200):
            results = self.cs.search('foo')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list(self):
        with HTTMock(list_200):
            results = self.cs.list()
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_escaped(self):
        with HTTMock(search_200_escaped):
            results = self.cs.search('&foo')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_400(self):
        with patch('theblues.charmstore.logging.error') as log_mocked:
            with HTTMock(search_400):
                with self.assertRaises(ServerError) as cm:
                    self.cs.search('foo')
        self.assertEqual(400, cm.exception.args[0])
        log_mocked.assert_called_with(
            'Error during request: http://example.com/search?text=foo '
            'status code:(400) message: '
            '{"Message": "invalid parameter: user", "Code": "bad request"}')

    def test_list_400(self):
        with patch('theblues.charmstore.logging.error') as log_mocked:
            with HTTMock(search_400):
                with self.assertRaises(ServerError) as cm:
                    self.cs.list()
        self.assertEqual(400, cm.exception.args[0])
        log_mocked.assert_called_with(
            'Error during request: http://example.com/list '
            'status code:(400) message: '
            '{"Message": "invalid parameter: user", "Code": "bad request"}')

    def test_search_limit(self):
        with HTTMock(search_limit_200):
            results = self.cs.search('foo', limit=1)
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_autocomplete(self):
        with HTTMock(search_autocomplete_200):
            results = self.cs.search(
                'foo', autocomplete=True)
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_includes(self):
        with HTTMock(search_includes_200):
            results = self.cs.search(
                'foo', includes=['archive-size', 'charm-metadata'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list_includes(self):
        with HTTMock(list_includes_200):
            results = self.cs.list(includes=['archive-size', 'charm-metadata'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_type(self):
        with HTTMock(search_type_200):
            results = self.cs.search('foo', doc_type='bundle')
            self.assertEqual([{'Id': 'cs:bundle/mediawiki-single-7'}], results)

    def test_list_type(self):
        with HTTMock(list_type_200):
            results = self.cs.list(doc_type='bundle')
            self.assertEqual([{'Id': 'cs:bundle/mediawiki-single-7'}], results)

    def test_search_tags(self):
        with HTTMock(search_tags_200):
            results = self.cs.search('foo', tags='databases')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_multiple_tags(self):
        with HTTMock(search_multiple_tags_200):
            results = self.cs.search('foo', tags=['databases', 'applications'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_series(self):
        with HTTMock(search_series_200):
            results = self.cs.search('foo', series='precise')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list_series(self):
        with HTTMock(list_series_200):
            results = self.cs.list(series='precise')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_multiple_series(self):
        with HTTMock(search_multiple_series_200):
            results = self.cs.search('foo', series=['trusty', 'precise'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_owner(self):
        with HTTMock(search_owner_200):
            results = self.cs.search('', owner='hatch')
            self.assertEqual([{"Id": "cs:foo/bar-0"}], results)

    def test_list_owner(self):
        with HTTMock(search_owner_200):
            results = self.cs.list(owner='hatch')
            self.assertEqual([{"Id": "cs:foo/bar-0"}], results)

    def test_charm_icon_url(self):
        entity_id = 'mongodb'
        url = self.cs.charm_icon_url(entity_id)
        self.assertEqual('http://example.com/mongodb/icon.svg', url)

    def test_charm_icon_url_reference(self):
        entity_id = 'mongodb'
        url = self.cs.charm_icon_url(
            references.Reference.from_string(entity_id))
        self.assertEqual('http://example.com/mongodb/icon.svg', url)

    def test_charm_icon_ok(self):
        entity_id = 'precise/mysql-1'
        with HTTMock(icon_200):
            icon = self.cs.charm_icon(entity_id)
        self.assertEqual('icon', icon)

    def test_charm_icon_ok_reference(self):
        entity_id = 'precise/mysql-1'
        with HTTMock(icon_200):
            icon = self.cs.charm_icon(
                references.Reference.from_string(entity_id))
        self.assertEqual('icon', icon)

    def test_charm_icon_bad(self):
        entity_id = 'precise/mysql-1'
        with HTTMock(icon_404):
            with self.assertRaises(EntityNotFound):
                self.cs.charm_icon(entity_id)

    def test_bundle_visualization_url(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.bundle_visualization_url(entity_id)
        self.assertEqual('http://example.com/mongodb-cluster/diagram.svg', url)

    def test_bundle_visualization_url_reference(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.bundle_visualization_url(
            references.Reference.from_string(entity_id))
        self.assertEqual('http://example.com/mongodb-cluster/diagram.svg', url)

    def test_bundle_visualization_ok(self):
        entity_id = 'mongodb-cluster'
        with HTTMock(diagram_200):
            diagram = self.cs.bundle_visualization(entity_id)
        self.assertEqual('diagram', diagram)

    def test_bundle_visualization_bad(self):
        entity_id = 'mongodb-cluster'
        with HTTMock(diagram_404):
            with self.assertRaises(EntityNotFound):
                self.cs.bundle_visualization(entity_id)

    def test_bundle_visualization_reference(self):
        entity_id = 'mongodb-cluster'
        with HTTMock(diagram_200):
            diagram = self.cs.bundle_visualization(
                references.Reference.from_string(entity_id))
        self.assertEqual('diagram', diagram)

    def test_entity_readme_url(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.entity_readme_url(entity_id)
        self.assertEqual('http://example.com/mongodb-cluster/readme', url)

    def test_entity_readme_url_reference(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.entity_readme_url(
            references.Reference.from_string(entity_id))
        self.assertEqual('http://example.com/mongodb-cluster/readme', url)

    def test_readme_not_found(self):
        # A 404 not found error is returned when the readme cannot be found.
        with HTTMock(readme_404):
            with self.assertRaises(EntityNotFound):
                self.cs.entity_readme_content('precise/mysql-1')

    def test_readme_content(self):
        with HTTMock(readme_200):
            content = self.cs.entity_readme_content('precise/mysql-1')
            self.assertEqual('This is the readme', content)

    def test_readme_content_reference(self):
        with HTTMock(readme_200):
            content = self.cs.entity_readme_content(
                references.Reference.from_string('precise/mysql-1'))
            self.assertEqual('This is the readme', content)

    def test_debug(self):
        with HTTMock(debug_200):
            debug_data = self.cs.debug()
            self.assertEqual('all clear', debug_data['status'])

    def test_timeout(self):
        with HTTMock(search_timeout):
            with self.assertRaises(ServerError) as cm:
                self.cs.search('foo')
        message = cm.exception.args[0]
        self.assertTrue('Request timed out' in message)

    def test_resource_url(self):
        entity_id = 'mongodb'
        url = self.cs.resource_url(entity_id, "myresource", "22")
        self.assertEqual('http://example.com/mongodb/resource/myresource/22',
                         url)
Example #7
0
 def setUp(self):
     self.cs = CharmStore('http://example.com')
Example #8
0
class TestCharmStore(TestCase):

    def entities_response(self, url, request):
        self.assertEqual(
            url.geturl(), 'http://example.com/meta/' +
            'any?include=id&id=wordpress&id=mysql')
        return {
            'status_code': 200,
            'content': b'{"wordpress":"wordpress","mysql":"mysql"}'}

    def setUp(self):
        self.cs = CharmStore('http://example.com')

    def test_init(self):
        self.assertEqual(self.cs.url, 'http://example.com')

    def test_entity(self):
        with HTTMock(entity_200):
            data = self.cs.charm(SAMPLE_CHARM)
        self.assertEqual({'Meta': {'charm-metadata': {'exists': True}}}, data)

    def test_entity_full_id(self):
        with HTTMock(entity_200):
            data = self.cs.charm(SAMPLE_CHARM_ID)
        self.assertEqual({'Meta': {'charm-metadata': {'exists': True}}}, data)

    def test_entity_reference(self):
        with HTTMock(entity_200):
            data = self.cs.charm(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual({'Meta': {'charm-metadata': {'exists': True}}}, data)

    def test_entities(self):
        with HTTMock(self.entities_response):
            response = self.cs.entities(['wordpress', 'mysql'])
        self.assertEqual(
            {u'wordpress': u'wordpress', u'mysql': u'mysql'}, response)

    def test_entities_reference(self):
        with HTTMock(self.entities_response):
            response = self.cs.entities(
                [references.Reference.from_string('wordpress'),
                 references.Reference.from_string('mysql')])
        self.assertEqual(
            {u'wordpress': u'wordpress', u'mysql': u'mysql'}, response)

    def test_entities_error(self):
        with HTTMock(entity_404):
            with self.assertRaises(EntityNotFound) as cm:
                self.cs.entities(['not-found'])
            self.assertEqual(
                'http://example.com/meta/any?include=id&id=not-found',
                cm.exception.args[0]
            )

    def test_charm_error(self):
        with HTTMock(entity_404):
            with self.assertRaises(EntityNotFound):
                self.cs.charm(SAMPLE_CHARM)

    def test_charm_error_id(self):
        with HTTMock(entity_404):
            with self.assertRaises(EntityNotFound):
                self.cs.charm(SAMPLE_CHARM_ID)

    def test_charm_error_407(self):
        with HTTMock(entity_407):
            with self.assertRaises(EntityNotFound):
                self.cs.charm(SAMPLE_CHARM)

    def test_config(self):
        with HTTMock(config_200):
            data = self.cs.config(SAMPLE_CHARM)
        self.assertEqual({'exists': True}, data)

    def test_config_reference(self):
        with HTTMock(config_200):
            data = self.cs.config(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual({'exists': True}, data)

    def test_config_error(self):
        with HTTMock(config_404):
            with self.assertRaises(EntityNotFound):
                self.cs.config(SAMPLE_CHARM)

    def test_archive_url(self):
        with HTTMock(manifest_200):
            data = self.cs.archive_url(SAMPLE_CHARM)
        self.assertEqual(u'http://example.com/precise/mysql-1/archive', data)

    def test_archive_url_reference(self):
        with HTTMock(manifest_200):
            data = self.cs.archive_url(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual(u'http://example.com/precise/mysql-1/archive', data)

    def test_file_good(self):
        with HTTMock(manifest_200):
            data = self.cs.files(SAMPLE_CHARM)
        self.assertEqual({
            u'icon.svg':
            u'http://example.com/precise/mysql-1/archive/icon.svg',
            u'README.md':
            u'http://example.com/precise/mysql-1/archive/README.md'
            },
            data)

    def test_file_good_reference(self):
        with HTTMock(manifest_200):
            data = self.cs.files(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual({
            u'icon.svg':
            u'http://example.com/precise/mysql-1/archive/icon.svg',
            u'README.md':
            u'http://example.com/precise/mysql-1/archive/README.md'
            },
            data)

    def test_file_error(self):
        with HTTMock(manifest_404):
            with self.assertRaises(EntityNotFound):
                self.cs.files(SAMPLE_CHARM)

    def test_file_one_file(self):
        with HTTMock(manifest_200):
            data = self.cs.files(SAMPLE_CHARM, filename='README.md')
        self.assertEqual(
            u'http://example.com/precise/mysql-1/archive/README.md',
            data)

    def test_file_one_file_reference(self):
        with HTTMock(manifest_200):
            data = self.cs.files(
                references.Reference.from_string(SAMPLE_CHARM),
                filename='README.md')
        self.assertEqual(
            u'http://example.com/precise/mysql-1/archive/README.md',
            data)

    def test_file_one_file_error(self):
        with HTTMock(manifest_200):
            with self.assertRaises(EntityNotFound):
                self.cs.files(SAMPLE_CHARM, filename='does.not.exist.md')

    def test_file_read_file(self):
        with HTTMock(manifest_200):
            with HTTMock(file_200):
                data = self.cs.files(
                    SAMPLE_CHARM, filename='README.md', read_file=True)
        self.assertEqual('This is a file.', data)

    def test_file_read_file_reference(self):
        with HTTMock(manifest_200):
            with HTTMock(file_200):
                data = self.cs.files(
                    references.Reference.from_string(SAMPLE_CHARM),
                    filename='README.md',
                    read_file=True)
        self.assertEqual('This is a file.', data)

    def test_file_read_file_error(self):
        with HTTMock(manifest_200):
            with HTTMock(file_404):
                with self.assertRaises(EntityNotFound):
                    self.cs.files(
                        SAMPLE_CHARM, filename='readme.md', read_file=True)

    def test_entityId(self):
        with HTTMock(id_200):
            charm_id = self.cs.entityId('bar')
            self.assertEqual('foo/bar', charm_id)

    def test_entityId_reference(self):
        with HTTMock(id_200):
            charm_id = self.cs.entityId(
                references.Reference.from_string('bar'))
            self.assertEqual('foo/bar', charm_id)

    def test_ids_no_charm(self):
        with HTTMock(id_404):
            with self.assertRaises(EntityNotFound):
                self.cs.entityId('baz')

    def test_search(self):
        with HTTMock(search_200):
            results = self.cs.search('foo')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list(self):
        with HTTMock(list_200):
            results = self.cs.list()
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_escaped(self):
        with HTTMock(search_200_escaped):
            results = self.cs.search('&foo')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_400(self):
        with patch('theblues.charmstore.logging.error') as log_mocked:
            with HTTMock(search_400):
                with self.assertRaises(ServerError) as cm:
                    self.cs.search('foo')
        self.assertEqual(400, cm.exception.args[0])
        log_mocked.assert_called_with(
            'Error during request: http://example.com/search?text=foo '
            'status code:(400) message: '
            '{"Message": "invalid parameter: user", "Code": "bad request"}')

    def test_list_400(self):
        with patch('theblues.charmstore.logging.error') as log_mocked:
            with HTTMock(search_400):
                with self.assertRaises(ServerError) as cm:
                    self.cs.list()
        self.assertEqual(400, cm.exception.args[0])
        log_mocked.assert_called_with(
            'Error during request: http://example.com/list '
            'status code:(400) message: '
            '{"Message": "invalid parameter: user", "Code": "bad request"}')

    def test_search_limit(self):
        with HTTMock(search_limit_200):
            results = self.cs.search('foo', limit=1)
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_autocomplete(self):
        with HTTMock(search_autocomplete_200):
            results = self.cs.search(
                'foo', autocomplete=True)
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_includes(self):
        with HTTMock(search_includes_200):
            results = self.cs.search(
                'foo', includes=['archive-size', 'charm-metadata'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list_includes(self):
        with HTTMock(list_includes_200):
            results = self.cs.list(includes=['archive-size', 'charm-metadata'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_type(self):
        with HTTMock(search_type_200):
            results = self.cs.search('foo', doc_type='bundle')
            self.assertEqual([{'Id': 'cs:bundle/mediawiki-single-7'}], results)

    def test_list_type(self):
        with HTTMock(list_type_200):
            results = self.cs.list(doc_type='bundle')
            self.assertEqual([{'Id': 'cs:bundle/mediawiki-single-7'}], results)

    def test_search_tags(self):
        with HTTMock(search_tags_200):
            results = self.cs.search('foo', tags='databases')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_multiple_tags(self):
        with HTTMock(search_multiple_tags_200):
            results = self.cs.search('foo', tags=['databases', 'applications'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_series(self):
        with HTTMock(search_series_200):
            results = self.cs.search('foo', series='precise')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list_series(self):
        with HTTMock(list_series_200):
            results = self.cs.list(series='precise')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_multiple_series(self):
        with HTTMock(search_multiple_series_200):
            results = self.cs.search('foo', series=['trusty', 'precise'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_owner(self):
        with HTTMock(search_owner_200):
            results = self.cs.search('', owner='hatch')
            self.assertEqual([{"Id": "cs:foo/bar-0"}], results)

    def test_list_owner(self):
        with HTTMock(search_owner_200):
            results = self.cs.list(owner='hatch')
            self.assertEqual([{"Id": "cs:foo/bar-0"}], results)

    def test_charm_icon_url(self):
        entity_id = 'mongodb'
        url = self.cs.charm_icon_url(entity_id)
        self.assertEqual('http://example.com/mongodb/icon.svg', url)

    def test_charm_icon_url_reference(self):
        entity_id = 'mongodb'
        url = self.cs.charm_icon_url(
            references.Reference.from_string(entity_id))
        self.assertEqual('http://example.com/mongodb/icon.svg', url)

    def test_charm_icon_ok(self):
        entity_id = 'precise/mysql-1'
        with HTTMock(icon_200):
            icon = self.cs.charm_icon(entity_id)
        self.assertEqual('icon', icon)

    def test_charm_icon_ok_reference(self):
        entity_id = 'precise/mysql-1'
        with HTTMock(icon_200):
            icon = self.cs.charm_icon(
                references.Reference.from_string(entity_id))
        self.assertEqual('icon', icon)

    def test_charm_icon_bad(self):
        entity_id = 'precise/mysql-1'
        with HTTMock(icon_404):
            with self.assertRaises(EntityNotFound):
                self.cs.charm_icon(entity_id)

    def test_bundle_visualization_url(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.bundle_visualization_url(entity_id)
        self.assertEqual('http://example.com/mongodb-cluster/diagram.svg', url)

    def test_bundle_visualization_url_reference(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.bundle_visualization_url(
            references.Reference.from_string(entity_id))
        self.assertEqual('http://example.com/mongodb-cluster/diagram.svg', url)

    def test_bundle_visualization_ok(self):
        entity_id = 'mongodb-cluster'
        with HTTMock(diagram_200):
            diagram = self.cs.bundle_visualization(entity_id)
        self.assertEqual('diagram', diagram)

    def test_bundle_visualization_bad(self):
        entity_id = 'mongodb-cluster'
        with HTTMock(diagram_404):
            with self.assertRaises(EntityNotFound):
                self.cs.bundle_visualization(entity_id)

    def test_bundle_visualization_reference(self):
        entity_id = 'mongodb-cluster'
        with HTTMock(diagram_200):
            diagram = self.cs.bundle_visualization(
                references.Reference.from_string(entity_id))
        self.assertEqual('diagram', diagram)

    def test_entity_readme_url(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.entity_readme_url(entity_id)
        self.assertEqual('http://example.com/mongodb-cluster/readme', url)

    def test_entity_readme_url_reference(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.entity_readme_url(
            references.Reference.from_string(entity_id))
        self.assertEqual('http://example.com/mongodb-cluster/readme', url)

    def test_readme_not_found(self):
        # A 404 not found error is returned when the readme cannot be found.
        with HTTMock(readme_404):
            with self.assertRaises(EntityNotFound):
                self.cs.entity_readme_content('precise/mysql-1')

    def test_readme_content(self):
        with HTTMock(readme_200):
            content = self.cs.entity_readme_content('precise/mysql-1')
            self.assertEqual('This is the readme', content)

    def test_readme_content_reference(self):
        with HTTMock(readme_200):
            content = self.cs.entity_readme_content(
                references.Reference.from_string('precise/mysql-1'))
            self.assertEqual('This is the readme', content)

    def test_debug(self):
        with HTTMock(debug_200):
            debug_data = self.cs.debug()
            self.assertEqual('all clear', debug_data['status'])

    def test_fetch_macaroon_successful(self):
        with HTTMock(fetch_macaroon_200):
            results = self.cs.fetch_macaroon()
            self.assertEqual('{"mymacaroon": "something"}', results)

    def test_fetch_macaroon_not_found(self):
        with HTTMock(fetch_macaroon_404):
            with self.assertRaises(EntityNotFound) as cm:
                self.cs.fetch_macaroon()
        self.assertEqual(cm.exception.args, ('http://example.com/macaroon',))

    def test_search_with_macaroon(self):
        with HTTMock(search_200_with_macaroon):
            self.cs.macaroons = "[macaroon1, macaroon2]"
            results = self.cs.search('foo')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list_with_macaroon(self):
        with HTTMock(search_200_with_macaroon):
            self.cs.macaroons = "[macaroon1, macaroon2]"
            results = self.cs.list()
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_timeout(self):
        with HTTMock(search_timeout):
            with self.assertRaises(ServerError) as cm:
                self.cs.search('foo')
        message = cm.exception.args[0]
        self.assertTrue('Request timed out' in message)

    def test_resource_url(self):
        entity_id = 'mongodb'
        url = self.cs.resource_url(entity_id, "myresource", "22")
        self.assertEqual('http://example.com/mongodb/resource/myresource/22',
                         url)
Example #9
0
# Copyright (c) 2015 Canonical Ltd.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

""" Charm utilities

Simple wrapper around theblues charmstore client

Api for the charmstore:
https://github.com/juju/charmstore/blob/v4/docs/API.md
"""
from theblues.charmstore import CharmStore

cs = CharmStore('https://api.jujucharms.com/v4')
Example #10
0
class TestCharmStore(TestCase):
    def entities_response(self, url, request):
        self.assertEqual(
            url.geturl(), 'http://example.com/meta/' +
            'any?include=id&id=wordpress&id=mysql')
        return {
            'status_code': 200,
            'content': b'{"wordpress":"wordpress","mysql":"mysql"}'
        }

    def setUp(self):
        self.cs = CharmStore('http://example.com')

    def test_init(self):
        self.assertEqual(self.cs.url, 'http://example.com')

    def test_entity(self):
        tests = [{
            'about':
            'default includes',
            'want_query':
            ('include=bundle-machine-count&include=bundle-metadata&'
             'include=bundle-unit-count&include=charm-actions&'
             'include=charm-config&include=charm-metadata&'
             'include=common-info&include=extra-info&include=owner&'
             'include=published&include=resources&'
             'include=supported-series&include=terms&include=stats'),
        }, {
            'about': 'custom includes',
            'kwargs': {
                'includes': ['foo', 'bar']
            },
            'want_query': 'include=foo&include=bar&include=stats',
        }, {
            'about': 'custom includes and no stats',
            'kwargs': {
                'includes': ['foo'],
                'include_stats': False
            },
            'want_query': 'include=foo',
        }, {
            'about': 'custom includes and get files',
            'kwargs': {
                'includes': [],
                'get_files': True
            },
            'want_query': 'include=manifest&include=stats',
        }, {
            'about':
            'default includes, no stats, with files',
            'kwargs': {
                'get_files': True,
                'include_stats': False
            },
            'want_query':
            ('include=bundle-machine-count&include=bundle-metadata&'
             'include=bundle-unit-count&include=charm-actions&'
             'include=charm-config&include=charm-metadata&'
             'include=common-info&include=extra-info&include=owner&'
             'include=published&include=resources&'
             'include=supported-series&include=terms&include=manifest'),
        }]
        for test in tests:
            # TODO(frankban): use subtests here when switching to Python 3.
            logging.debug(test['about'])
            self.check_entity(test.get('kwargs', {}),
                              test.get('want_query', ''))

    def check_entity(self, kwargs, want_query):
        @urlmatch(path=ID_PATH)
        def handler(url, request):
            self.assertEqual(request.method, 'GET')
            self.assertEqual(url.path, '/precise/mysql-1/meta/any')
            self.assertEqual(url.query, want_query)
            return {'status_code': 200, 'content': {'result': 'foo'}}

        with HTTMock(handler):
            data = self.cs.entity(SAMPLE_CHARM_ID, **kwargs)
        self.assertEqual(data, {'result': 'foo'})

    def test_charm(self):
        with HTTMock(entity_200):
            data = self.cs.charm(SAMPLE_CHARM)
        self.assertEqual({'Meta': {'charm-metadata': {'exists': True}}}, data)

    def test_charm_full_id(self):
        with HTTMock(entity_200):
            data = self.cs.charm(SAMPLE_CHARM_ID)
        self.assertEqual({'Meta': {'charm-metadata': {'exists': True}}}, data)

    def test_charm_reference(self):
        with HTTMock(entity_200):
            data = self.cs.charm(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual({'Meta': {'charm-metadata': {'exists': True}}}, data)

    def test_entities(self):
        with HTTMock(self.entities_response):
            response = self.cs.entities(['wordpress', 'mysql'])
        self.assertEqual({
            u'wordpress': u'wordpress',
            u'mysql': u'mysql'
        }, response)

    def test_entities_reference(self):
        with HTTMock(self.entities_response):
            response = self.cs.entities([
                references.Reference.from_string('wordpress'),
                references.Reference.from_string('mysql')
            ])
        self.assertEqual({
            u'wordpress': u'wordpress',
            u'mysql': u'mysql'
        }, response)

    def test_entities_error(self):
        with HTTMock(entity_404):
            with self.assertRaises(EntityNotFound) as cm:
                self.cs.entities(['not-found'])
            self.assertEqual(
                'http://example.com/meta/any?include=id&id=not-found',
                cm.exception.args[0])

    def test_charm_error(self):
        with HTTMock(entity_404):
            with self.assertRaises(EntityNotFound):
                self.cs.charm(SAMPLE_CHARM)

    def test_charm_error_id(self):
        with HTTMock(entity_404):
            with self.assertRaises(EntityNotFound):
                self.cs.charm(SAMPLE_CHARM_ID)

    def test_charm_error_407(self):
        with HTTMock(entity_407):
            with self.assertRaises(EntityNotFound):
                self.cs.charm(SAMPLE_CHARM)

    def test_config(self):
        with HTTMock(config_200):
            data = self.cs.config(SAMPLE_CHARM)
        self.assertEqual({'exists': True}, data)

    def test_config_reference(self):
        with HTTMock(config_200):
            data = self.cs.config(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual({'exists': True}, data)

    def test_config_error(self):
        with HTTMock(config_404):
            with self.assertRaises(EntityNotFound):
                self.cs.config(SAMPLE_CHARM)

    def test_archive_url(self):
        with HTTMock(manifest_200):
            data = self.cs.archive_url(SAMPLE_CHARM)
        self.assertEqual(u'http://example.com/precise/mysql-1/archive', data)

    def test_archive_url_reference(self):
        with HTTMock(manifest_200):
            data = self.cs.archive_url(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual(u'http://example.com/precise/mysql-1/archive', data)

    def test_file_good(self):
        with HTTMock(manifest_200):
            data = self.cs.files(SAMPLE_CHARM)
        self.assertEqual(
            {
                u'icon.svg':
                u'http://example.com/precise/mysql-1/archive/icon.svg',
                u'README.md':
                u'http://example.com/precise/mysql-1/archive/README.md'
            }, data)

    def test_file_good_reference(self):
        with HTTMock(manifest_200):
            data = self.cs.files(
                references.Reference.from_string(SAMPLE_CHARM))
        self.assertEqual(
            {
                u'icon.svg':
                u'http://example.com/precise/mysql-1/archive/icon.svg',
                u'README.md':
                u'http://example.com/precise/mysql-1/archive/README.md'
            }, data)

    def test_file_error(self):
        with HTTMock(manifest_404):
            with self.assertRaises(EntityNotFound):
                self.cs.files(SAMPLE_CHARM)

    def test_file_one_file(self):
        with HTTMock(manifest_200):
            data = self.cs.files(SAMPLE_CHARM, filename='README.md')
        self.assertEqual(
            u'http://example.com/precise/mysql-1/archive/README.md', data)

    def test_file_one_file_reference(self):
        with HTTMock(manifest_200):
            data = self.cs.files(
                references.Reference.from_string(SAMPLE_CHARM),
                filename='README.md')
        self.assertEqual(
            u'http://example.com/precise/mysql-1/archive/README.md', data)

    def test_file_one_file_error(self):
        with HTTMock(manifest_200):
            with self.assertRaises(EntityNotFound):
                self.cs.files(SAMPLE_CHARM, filename='does.not.exist.md')

    def test_file_read_file(self):
        with HTTMock(manifest_200):
            with HTTMock(file_200):
                data = self.cs.files(SAMPLE_CHARM,
                                     filename='README.md',
                                     read_file=True)
        self.assertEqual('This is a file.', data)

    def test_file_read_file_reference(self):
        with HTTMock(manifest_200):
            with HTTMock(file_200):
                data = self.cs.files(
                    references.Reference.from_string(SAMPLE_CHARM),
                    filename='README.md',
                    read_file=True)
        self.assertEqual('This is a file.', data)

    def test_file_read_file_error(self):
        with HTTMock(manifest_200):
            with HTTMock(file_404):
                with self.assertRaises(EntityNotFound):
                    self.cs.files(SAMPLE_CHARM,
                                  filename='readme.md',
                                  read_file=True)

    def test_entityId(self):
        with HTTMock(id_200):
            charm_id = self.cs.entityId('bar')
            self.assertEqual('foo/bar', charm_id)

    def test_entityId_reference(self):
        with HTTMock(id_200):
            charm_id = self.cs.entityId(
                references.Reference.from_string('bar'))
            self.assertEqual('foo/bar', charm_id)

    def test_ids_no_charm(self):
        with HTTMock(id_404):
            with self.assertRaises(EntityNotFound):
                self.cs.entityId('baz')

    def test_search(self):
        with HTTMock(search_200):
            results = self.cs.search('foo')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list(self):
        with HTTMock(list_200):
            results = self.cs.list()
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_escaped(self):
        with HTTMock(search_200_escaped):
            results = self.cs.search('&foo')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_400(self):
        with patch('theblues.charmstore.logging.error') as log_mocked:
            with HTTMock(search_400):
                with self.assertRaises(ServerError) as cm:
                    self.cs.search('foo')
        self.assertEqual(400, cm.exception.args[0])
        log_mocked.assert_called_with(
            'Error during request: http://example.com/search?text=foo '
            'status code:(400) message: '
            '{"Message": "invalid parameter: user", "Code": "bad request"}')

    def test_list_400(self):
        with patch('theblues.charmstore.logging.error') as log_mocked:
            with HTTMock(search_400):
                with self.assertRaises(ServerError) as cm:
                    self.cs.list()
        self.assertEqual(400, cm.exception.args[0])
        log_mocked.assert_called_with(
            'Error during request: http://example.com/list '
            'status code:(400) message: '
            '{"Message": "invalid parameter: user", "Code": "bad request"}')

    def test_search_limit(self):
        with HTTMock(search_limit_200):
            results = self.cs.search('foo', limit=1)
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_autocomplete(self):
        with HTTMock(search_autocomplete_200):
            results = self.cs.search('foo', autocomplete=True)
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_includes(self):
        with HTTMock(search_includes_200):
            results = self.cs.search(
                'foo', includes=['archive-size', 'charm-metadata'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list_includes(self):
        with HTTMock(list_includes_200):
            results = self.cs.list(includes=['archive-size', 'charm-metadata'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_type(self):
        with HTTMock(search_type_200):
            results = self.cs.search('foo', doc_type='bundle')
            self.assertEqual([{'Id': 'cs:bundle/mediawiki-single-7'}], results)

    def test_list_type(self):
        with HTTMock(list_type_200):
            results = self.cs.list(doc_type='bundle')
            self.assertEqual([{'Id': 'cs:bundle/mediawiki-single-7'}], results)

    def test_search_tags(self):
        with HTTMock(search_tags_200):
            results = self.cs.search('foo', tags='databases')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_multiple_tags(self):
        with HTTMock(search_multiple_tags_200):
            results = self.cs.search('foo', tags=['databases', 'applications'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_series(self):
        with HTTMock(search_series_200):
            results = self.cs.search('foo', series='precise')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_list_series(self):
        with HTTMock(list_series_200):
            results = self.cs.list(series='precise')
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_multiple_series(self):
        with HTTMock(search_multiple_series_200):
            results = self.cs.search('foo', series=['trusty', 'precise'])
            self.assertEqual([{'Id': 'cs:foo/bar-0'}], results)

    def test_search_owner(self):
        with HTTMock(search_owner_200):
            results = self.cs.search('', owner='hatch')
            self.assertEqual([{"Id": "cs:foo/bar-0"}], results)

    def test_list_owner(self):
        with HTTMock(search_owner_200):
            results = self.cs.list(owner='hatch')
            self.assertEqual([{"Id": "cs:foo/bar-0"}], results)

    def test_charm_icon_url(self):
        entity_id = 'mongodb'
        url = self.cs.charm_icon_url(entity_id)
        self.assertEqual('http://example.com/mongodb/icon.svg', url)

    def test_charm_icon_url_reference(self):
        entity_id = 'mongodb'
        url = self.cs.charm_icon_url(
            references.Reference.from_string(entity_id))
        self.assertEqual('http://example.com/mongodb/icon.svg', url)

    def test_charm_icon_ok(self):
        entity_id = 'precise/mysql-1'
        with HTTMock(icon_200):
            icon = self.cs.charm_icon(entity_id)
        self.assertEqual('icon', icon)

    def test_charm_icon_ok_reference(self):
        entity_id = 'precise/mysql-1'
        with HTTMock(icon_200):
            icon = self.cs.charm_icon(
                references.Reference.from_string(entity_id))
        self.assertEqual('icon', icon)

    def test_charm_icon_bad(self):
        entity_id = 'precise/mysql-1'
        with HTTMock(icon_404):
            with self.assertRaises(EntityNotFound):
                self.cs.charm_icon(entity_id)

    def test_bundle_visualization_url(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.bundle_visualization_url(entity_id)
        self.assertEqual('http://example.com/mongodb-cluster/diagram.svg', url)

    def test_bundle_visualization_url_reference(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.bundle_visualization_url(
            references.Reference.from_string(entity_id))
        self.assertEqual('http://example.com/mongodb-cluster/diagram.svg', url)

    def test_bundle_visualization_ok(self):
        entity_id = 'mongodb-cluster'
        with HTTMock(diagram_200):
            diagram = self.cs.bundle_visualization(entity_id)
        self.assertEqual('diagram', diagram)

    def test_bundle_visualization_bad(self):
        entity_id = 'mongodb-cluster'
        with HTTMock(diagram_404):
            with self.assertRaises(EntityNotFound):
                self.cs.bundle_visualization(entity_id)

    def test_bundle_visualization_reference(self):
        entity_id = 'mongodb-cluster'
        with HTTMock(diagram_200):
            diagram = self.cs.bundle_visualization(
                references.Reference.from_string(entity_id))
        self.assertEqual('diagram', diagram)

    def test_entity_readme_url(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.entity_readme_url(entity_id)
        self.assertEqual('http://example.com/mongodb-cluster/readme', url)

    def test_entity_readme_url_reference(self):
        entity_id = 'mongodb-cluster'
        url = self.cs.entity_readme_url(
            references.Reference.from_string(entity_id))
        self.assertEqual('http://example.com/mongodb-cluster/readme', url)

    def test_readme_not_found(self):
        # A 404 not found error is returned when the readme cannot be found.
        with HTTMock(readme_404):
            with self.assertRaises(EntityNotFound):
                self.cs.entity_readme_content('precise/mysql-1')

    def test_readme_content(self):
        with HTTMock(readme_200):
            content = self.cs.entity_readme_content('precise/mysql-1')
            self.assertEqual('This is the readme', content)

    def test_readme_content_reference(self):
        with HTTMock(readme_200):
            content = self.cs.entity_readme_content(
                references.Reference.from_string('precise/mysql-1'))
            self.assertEqual('This is the readme', content)

    def test_debug(self):
        with HTTMock(debug_200):
            debug_data = self.cs.debug()
            self.assertEqual('all clear', debug_data['status'])

    def test_timeout(self):
        with HTTMock(search_timeout):
            with self.assertRaises(ServerError) as cm:
                self.cs.search('foo')
        message = cm.exception.args[0]
        self.assertTrue('Request timed out' in message)

    def test_resource_url(self):
        entity_id = 'mongodb'
        url = self.cs.resource_url(entity_id, "myresource", "22")
        self.assertEqual('http://example.com/mongodb/resource/myresource/22',
                         url)
Example #11
0
 def __init__(self):
     self.cs = CharmStore('https://api.jujucharms.com/v4')
     self.charm_search = None
     self.result = None
Example #12
0
class Query:
    def __init__(self):
        self.cs = CharmStore('https://api.jujucharms.com/v4')
        self.charm_search = None
        self.result = None

    @classmethod
    def is_fuzzy(cls, charm):
        glob_chars = set('~*')
        if any((c in glob_chars) for c in charm):
            return True
        return False

    @classmethod
    def valid_filter(cls, charm):
        fail_glob_chars = set('.?[]')
        if any((c in fail_glob_chars) for c in charm):
            return False
        return True

    def _save_charm_search(self, charm):
        """ Saves the charm search query, sanitizing any wildcards
        """
        charm = charm.translate({ord(i): None for i in '~*'})
        self.charm_search = charm

    def filter_non_name_matches(self, result):
        """ The search query doesnt return just results with charm_search
        in the name, so we filter that out
        """
        self.result = [item for item in result
                       if self.charm_search in item['Id']]

    def search(self, charm, promulgated=True):
        """ Searches for charm

        Eg:
        https://api.jujucharms.com/charmstore/v4/search?text=nova&autocomplete=1&limit=100

        Only blessed ones:
        https://api.jujucharms.com/charmstore/v4/search?text=nova&autocomplete=1&limit=100&owner=
        Arguments:
        charm: name of service
        """
        try:
            self._save_charm_search(charm)
            self.result = self.cs.search(charm,
                                         autocomplete=True,
                                         promulgated_only=promulgated,
                                         limit=25)
        except EntityNotFound as e:
            raise QueryError(e)

    def get(self, charm):
        """ Returns single entry for charm
        """
        try:
            self._save_charm_search(charm)
            self.result = dict(Id=self.cs.entityId(charm))
        except EntityNotFound as e:
            raise QueryError(e)

    def render(self):
        """ Renders charm results

        Example:

        juju search nova

        Trusty
          nova-cloud-controller
          nova-compute

        Precise
          nova-compute

        User contributed
          nova-compute-vmware
        """
        if not self.result:
            raise QueryError(
                "Must search for a charm before attempting to render it.")

        if not isinstance(self.result, list):
            self.result = [self.result]

        series_map = {
            'trusty': [],
            'precise': [],
            'namespaced': [],
        }

        self.filter_non_name_matches(self.result)
        for entity in self.result:
            _id = entity['Id']
            item = _id
            if entity['Id'].startswith('cs:'):
                item = entity['Id'][3:]
            charm = self.cs.entity(item)
            try:
                meta = charm['Meta']['charm-metadata']
            except KeyError:
                # Probably a bundle
                continue
            stat = charm['Meta']['stats']
            dl = stat['ArchiveDownloadCount']
            summary = meta['Summary']

            if Query.is_fuzzy(item):
                series_map['namespaced'].append(
                    (_id, dl, summary)
                )
            elif 'trusty' in item:
                series_map['trusty'].append(
                    (_id, dl, summary)
                )
            elif 'precise' in item:
                series_map['precise'].append(
                    (_id, dl, summary)
                )

        valid_series = None
        for series in sorted(series_map.keys(), reverse=True):
            if len(series_map[series]) == 0:
                continue
            valid_series = series
            print(series.capitalize())
            print("")
            for _id, dl, summary in series_map[series]:
                print(" {}".format(_id))
            print("")

        if valid_series:
            item = series_map[valid_series][0]
            print("Example:")
            print("")
            print(" juju deploy {}".format(item[0]))
            print("")
            print("Get additional information:")
            print("")
            print(" juju info {}".format(item[0]))
            print("")