~justin-fathomdb/nova/justinsb-openstack-api-volumes

« back to all changes in this revision

Viewing changes to nova/tests/api_unittest.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
# Copyright [2010] [Anso Labs, LLC]
 
3
#
 
4
#    Licensed under the Apache License, Version 2.0 (the "License");
 
5
#    you may not use this file except in compliance with the License.
 
6
#    You may obtain a copy of the License at
 
7
#
 
8
#        http://www.apache.org/licenses/LICENSE-2.0
 
9
#
 
10
#    Unless required by applicable law or agreed to in writing, software
 
11
#    distributed under the License is distributed on an "AS IS" BASIS,
 
12
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
#    See the License for the specific language governing permissions and
 
14
#    limitations under the License.
 
15
 
 
16
import httplib
 
17
import random
 
18
import StringIO
 
19
 
 
20
from nova import vendor
 
21
import boto
 
22
from boto.ec2 import regioninfo
 
23
from tornado import httpserver
 
24
from twisted.internet import defer
 
25
 
 
26
from nova import flags
 
27
from nova import test
 
28
from nova.auth import users
 
29
from nova.endpoint import api
 
30
from nova.endpoint import cloud
 
31
 
 
32
 
 
33
FLAGS = flags.FLAGS
 
34
 
 
35
 
 
36
# NOTE(termie): These are a bunch of helper methods and classes to short
 
37
#               circuit boto calls and feed them into our tornado handlers,
 
38
#               it's pretty damn circuitous so apologies if you have to fix
 
39
#               a bug in it
 
40
def boto_to_tornado(method, path, headers, data, host, connection=None):
 
41
    """ translate boto requests into tornado requests
 
42
 
 
43
    connection should be a FakeTornadoHttpConnection instance
 
44
    """
 
45
    headers = httpserver.HTTPHeaders()
 
46
    for k, v in headers.iteritems():
 
47
        headers[k] = v
 
48
 
 
49
    req = httpserver.HTTPRequest(method=method,
 
50
                                 uri=path,
 
51
                                 headers=headers,
 
52
                                 body=data,
 
53
                                 host=host,
 
54
                                 remote_ip='127.0.0.1',
 
55
                                 connection=connection)
 
56
    return req
 
57
 
 
58
 
 
59
def raw_to_httpresponse(s):
 
60
    """ translate a raw tornado http response into an httplib.HTTPResponse """
 
61
    sock = FakeHttplibSocket(s)
 
62
    resp = httplib.HTTPResponse(sock)
 
63
    resp.begin()
 
64
    return resp
 
65
 
 
66
 
 
67
class FakeHttplibSocket(object):
 
68
    """ a fake socket implementation for httplib.HTTPResponse, trivial """
 
69
    def __init__(self, s):
 
70
        self.fp = StringIO.StringIO(s)
 
71
 
 
72
    def makefile(self, mode, other):
 
73
        return self.fp
 
74
 
 
75
 
 
76
class FakeTornadoStream(object):
 
77
    """ a fake stream to satisfy tornado's assumptions, trivial """
 
78
    def set_close_callback(self, f):
 
79
        pass
 
80
 
 
81
 
 
82
class FakeTornadoConnection(object):
 
83
    """ a fake connection object for tornado to pass to its handlers
 
84
 
 
85
    web requests are expected to write to this as they get data and call
 
86
    finish when they are done with the request, we buffer the writes and
 
87
    kick off a callback when it is done so that we can feed the result back
 
88
    into boto.
 
89
    """
 
90
    def __init__(self, d):
 
91
        self.d = d
 
92
        self._buffer = StringIO.StringIO()
 
93
 
 
94
    def write(self, chunk):
 
95
        self._buffer.write(chunk)
 
96
 
 
97
    def finish(self):
 
98
        s = self._buffer.getvalue()
 
99
        self.d.callback(s)
 
100
 
 
101
    xheaders = None
 
102
 
 
103
    @property
 
104
    def stream(self):
 
105
        return FakeTornadoStream()
 
106
 
 
107
 
 
108
class FakeHttplibConnection(object):
 
109
    """ a fake httplib.HTTPConnection for boto to use
 
110
 
 
111
    requests made via this connection actually get translated and routed into
 
112
    our tornado app, we then wait for the response and turn it back into
 
113
    the httplib.HTTPResponse that boto expects.
 
114
    """
 
115
    def __init__(self, app, host, is_secure=False):
 
116
        self.app = app
 
117
        self.host = host
 
118
        self.deferred = defer.Deferred()
 
119
 
 
120
    def request(self, method, path, data, headers):
 
121
        req = boto_to_tornado
 
122
        conn = FakeTornadoConnection(self.deferred)
 
123
        request = boto_to_tornado(connection=conn,
 
124
                                  method=method,
 
125
                                  path=path,
 
126
                                  headers=headers,
 
127
                                  data=data,
 
128
                                  host=self.host)
 
129
        handler = self.app(request)
 
130
        self.deferred.addCallback(raw_to_httpresponse)
 
131
 
 
132
    def getresponse(self):
 
133
        @defer.inlineCallbacks
 
134
        def _waiter():
 
135
            result = yield self.deferred
 
136
            defer.returnValue(result)
 
137
        d = _waiter()
 
138
        # NOTE(termie): defer.returnValue above should ensure that
 
139
        #               this deferred has already been called by the time
 
140
        #               we get here, we are going to cheat and return
 
141
        #               the result of the callback
 
142
        return d.result
 
143
 
 
144
    def close(self):
 
145
        pass
 
146
 
 
147
 
 
148
class ApiEc2TestCase(test.BaseTestCase):
 
149
    def setUp(self):
 
150
        super(ApiEc2TestCase, self).setUp()
 
151
 
 
152
        self.users = users.UserManager.instance()
 
153
        self.cloud = cloud.CloudController()
 
154
 
 
155
        self.host = '127.0.0.1'
 
156
 
 
157
        self.app = api.APIServerApplication(self.users, {'Cloud': self.cloud})
 
158
        self.ec2 = boto.connect_ec2(
 
159
                aws_access_key_id='fake',
 
160
                aws_secret_access_key='fake',
 
161
                is_secure=False,
 
162
                region=regioninfo.RegionInfo(None, 'test', self.host),
 
163
                port=FLAGS.cc_port,
 
164
                path='/services/Cloud')
 
165
 
 
166
        self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
 
167
 
 
168
    def expect_http(self, host=None, is_secure=False):
 
169
        http = FakeHttplibConnection(
 
170
                self.app, '%s:%d' % (self.host, FLAGS.cc_port), False)
 
171
        self.ec2.new_http_connection(host, is_secure).AndReturn(http)
 
172
        return http
 
173
 
 
174
    def test_describe_instances(self):
 
175
        self.expect_http()
 
176
        self.mox.ReplayAll()
 
177
 
 
178
        self.assertEqual(self.ec2.get_all_instances(), [])
 
179
 
 
180
 
 
181
    def test_get_all_key_pairs(self):
 
182
        self.expect_http()
 
183
        self.mox.ReplayAll()
 
184
        keyname = "".join(random.choice("sdiuisudfsdcnpaqwertasd") for x in range(random.randint(4, 8)))
 
185
        self.users.generate_key_pair('fake', keyname)
 
186
 
 
187
        rv = self.ec2.get_all_key_pairs()
 
188
        self.assertTrue(filter(lambda k: k.name == keyname, rv))
 
189