~jcsackett/charmworld/bac-tag-constraints

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# Copyright 2012, 2013 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

from contextlib import contextmanager
import logging
import os
from StringIO import StringIO
import unittest
from urllib2 import URLError

import mock
from mongoqueue import MongoQueue
from pyramid import testing
from webtest import TestApp

from charmworld import main
from charmworld.models import getconnection
from charmworld.models import getdb
from charmworld.models import getfs
from charmworld.search import ElasticSearchClient
from charmworld.testing.factory import makeSSOResponse
from charmworld.utils import get_ini


INI = get_ini()
MONGO_URL = os.environ.get('TEST_MONGODB')
MONGO_DATABASE = INI.get('mongo.database')
# Update the ini values with the database fired up by the nosemongo plugin.
INI['mongo.url'] = MONGO_URL

REAL_FILE_CHARM_DIR = os.path.join(os.path.split(__file__)[0], 'data')


class MongoTestBase(unittest.TestCase):

    @property
    def connection(self):
        if getattr(self, '_connection', None) is None:
            self._connection = getconnection(INI, safe=True)
        return self._connection

    def setUp(self):
        self.db = getdb(self.connection, MONGO_DATABASE)
        self.fs = getfs(self.db)

    def tearDown(self):
        # Drop the Mongo database.
        self.connection.drop_database(MONGO_DATABASE)

    def get_handler(self, log_name):
        logger = logging.getLogger(log_name)
        handler = logging.handlers.BufferingHandler(20)
        logger.addHandler(handler)

        def cleanup():
            logger.removeHandler(handler)
        self.addCleanup(cleanup)
        return handler


class WebTestBase(MongoTestBase):

    def setUp(self):
        super(WebTestBase, self).setUp()
        app = main({}, **INI)
        self.app = TestApp(app)

    def tearDown(self):
        self.app = None
        super(WebTestBase, self).tearDown()


class ViewTestBase(MongoTestBase):

    def setUp(self):
        super(ViewTestBase, self).setUp()
        self.config = testing.setUp()

    def getRequest(self, params=None, post=None):
        request = testing.DummyRequest(params=params, post=post)
        request.db = self.db
        return request

    def tearDown(self):
        testing.tearDown()
        super(ViewTestBase, self).tearDown()


class RemoteURLBase(MongoTestBase):

    url_prefix = "https://jenkins.qa.ubuntu.com/job/"
    url_debug = False

    def setUp(self):
        super(RemoteURLBase, self).setUp()
        self.url_result_map = {"": ""}

    def lookup_url_result(self, url):
        if self.url_debug:
            print "url", url
        short_url = url[len(self.url_prefix):]
        if short_url in self.url_result_map:
            return StringIO(self.url_result_map[short_url])
        raise URLError(url)

    def invoke(self, func, *args, **kw):
        with mock.patch("urllib2.urlopen") as urlopen:
            urlopen.side_effect = self.lookup_url_result
            return func(*args, **kw)


class JobTestBase(MongoTestBase):

    def patch_ingest_job(self, job, methods):
        # Mocks multiple attr on a job.
        old_methods = []
        for m in methods:
            old_methods.append(getattr(job, m))
            setattr(job, m, mock.Mock())

        def cleanup():
            for i, m in enumerate(methods):
                setattr(job, m, old_methods[i])
        self.addCleanup(cleanup)

    def get_mongo_queues(self, data=None):
        in_queue = MongoQueue(self.db.in_queue, "in-queue")
        out_queue = MongoQueue(self.db.out_queue, "out-queue")

        if data:
            in_queue.put(data)

        def cleanup():
            in_queue.clear()
            out_queue.clear()
        self.addCleanup(cleanup)
        return (in_queue, out_queue)


@contextmanager
def login_request(app, groups=None):
    """Context manager to help functionally test a logged in user account.

    :param app: The application constructed for testing. Usually self.app when
                using WebTestBase.
    :return response: The post-logged in WebTest response object.
    """
    sso_resp = makeSSOResponse(groups=groups)
    resp = app.get(
        '/auth_callback',
        params=sso_resp,
        status=302)
    resp = resp.follow()
    yield resp


def get_bad_mock(exception_type=Exception, *args):
    """Convenience helper to generate a mock that will raise a particular
    exception with necessary messages.
    """
    if not len(args):
        args = ["Exception forced by mock."]
    return mock.Mock(side_effect=exception_type(*args))


@contextmanager
def temp_index_client():
    client = ElasticSearchClient.from_settings(INI, 'temp_index')
    try:
        yield client
    finally:
        client.delete_index()