Merge lp:~tylesmit/neutron/quantum-client-library into lp:neutron/diablo

Proposed by Tyler Smith
Status: Rejected
Rejected by: Salvatore Orlando
Proposed branch: lp:~tylesmit/neutron/quantum-client-library
Merge into: lp:neutron/diablo
Diff against target: 3363 lines (+954/-1169)
6 files modified
quantum/cli.py (+97/-176)
quantum/client.py (+254/-0)
tests/unit/__init__.py (+0/-32)
tests/unit/api.py (+603/-0)
tests/unit/test_api.py (+0/-831)
tests/unit/testlib_api.py (+0/-130)
To merge this branch: bzr merge lp:~tylesmit/neutron/quantum-client-library
Reviewer Review Type Date Requested Status
Sumit Naiksatam Needs Information
Ying Liu community Needs Fixing
Somik Behera netstack-core Needs Fixing
Review via email: mp+68247@code.launchpad.net

Description of the change

A refactoring of the MiniClient into a more stable and robust API Client library. The test_scripts/tests.py, and quantum/cli.py have been rewritten to use the new library.

In addition, there are unit tests included that test the library's functionality.

To post a comment you must log in.
Revision history for this message
Somik Behera (somikbehera) wrote :

Hi Tyler, Good work on Quantum Client lib, this abstraction will be very helpful to enable others to build upon Quantum in a convenient manner. I like your decorators too!

I did have a few comments regarding issues we will need to work to get this branch ready for merge into the Quantum trunk:

1) We should get lp:quantum trunk merged into your development branch and resolve conflicts. I see quite a few merge conflicts in this merge prop that need to be addressed. I would suggest doing a bzr merge lp:quantum into your dev branch and then merge prop again, and launchpad shouldn't show these conflicts.

2) Regarding the use of HTTPS connections. I see that you have made it very convenient for users to use HTTPS, which is good. But the default way of making HTTPS connection in python essentially "trusts" any and all certificates without verifying its authenticity.

We should definitely have the "easy" but not secure HTTPS option for testing and for folks who are on secure management networks, but then they should be using HTTP :) but thats a different story. I think in addition to the HTTPS mechanism you coded up, we should also support true HTTPS authentication were we verifyt he server authenticity with a certificate. Take a look here - http://code.activestate.com/recipes/117004-ssl-client-authentication-over-https/

3) I think once we made these changes and run you unit tests, we will be good.

Good work! We are getting very close.

review: Needs Fixing (netstack-core)
Revision history for this message
Ying Liu (yinliu2) wrote :

Hi Tyler,

Great job!
New client lib and unit tests look good to me.

Just two comments:
1. It seems that quantum code in your local branch is out of date, which is not sync with latest lp:quantum. Therefore, before the merge, you can check out the latest lp:quantum, sync with it and make sure that it works with new client library.
2. For unit tests, probably we can have more negative tests, e.g. delete network which is not existed or delete a network which is in use.

Other than these, the new code look good to me. Good job!

review: Needs Fixing (community)
Revision history for this message
Salvatore Orlando (salvatore-orlando) wrote :

On unit tests:
Tyler probably branched out from lp:~netstack/quantum/quantum-unit-tests, which was still in progress.
This might explain why the list of unit tests is incomplete. The full list of unit tests is in the above mentioned branch, which will be proposed for merge in a few hours. Implemented API unit tests are listed at wiki.openstack.org/QuantumUnitTestStatus.

setting back to WIP until comments are addressed.

23. By Salvatore Orlando

Merging branch lp:~netstack/quantum/quantum-unit-tests

Provides functionality as specified by blueprint https://blueprints.launchpad.net/quantum/+spec/api-spec-unit-tests

24. By Salvatore Orlando

Merging branch lp:~salvatore-orlando/quantum/bug802892
Fixing bug #802892

25. By Salvatore Orlando

Apply fix for bug #797419
merging lp:~salvatore-orlando/quantum/bug797419

26. By Tyler Smith

Merge in the client-library branch

27. By Tyler Smith

Adding some negative unit tests for the client library

Revision history for this message
Sumit Naiksatam (snaiksat) wrote :

Tyler, nice work. A couple of points,

(1) is this library meant to also provide a way to access the extensions exposed by plugins? If so, how?

(2) A nit - the company affiliations/credits in the banner at the top of the new files are not consistent (in places it says Citrix, in some it's OpenStack, and still others the license banner is missing)

review: Needs Information
Revision history for this message
Tyler Smith (tylesmit) wrote :

Hi Sumit, thanks.

(1) The library as it is only has methods for the high-level API operations outlined in the spec (http://wiki.openstack.org/QuantumAPISpec). There is a do_request method that can be used to to send any arbitrary query to Quantum server, but it's much less friendly than the high-level methods. A plugin could sub-class the Client and add its own methods (although I'm not sure how well this would work out long-term). Do you have any suggestions?

(2) The repo has been broken since I've tried merging lp:quantum back into (I'm new to bzr, so it's taking some getting used to). I'm working on getting it straightened out. When I do I'll only be adding 2 files. For quantum/client.py I have kept the Citrix banner because I refactored the MiniClient into it, so I retained the header. For the other file, a unit tests file, I'm finding out now how to properly credit it.

Revision history for this message
dan wendlandt (danwent) wrote :

On Tue, Jul 26, 2011 at 7:38 AM, Tyler Smith <email address hidden> wrote:

> Hi Sumit, thanks.
>
> (1) The library as it is only has methods for the high-level API operations
> outlined in the spec (http://wiki.openstack.org/QuantumAPISpec). There is
> a do_request method that can be used to to send any arbitrary query to
> Quantum server, but it's much less friendly than the high-level methods. A
> plugin could sub-class the Client and add its own methods (although I'm not
> sure how well this would work out long-term). Do you have any suggestions?
>

I think having some kind of generic "do_request" call makes sense.

>
> (2) The repo has been broken since I've tried merging lp:quantum back into
> (I'm new to bzr, so it's taking some getting used to). I'm working on
> getting it straightened out. When I do I'll only be adding 2 files. For
> quantum/client.py I have kept the Citrix banner because I refactored the
> MiniClient into it, so I retained the header. For the other file, a unit
> tests file, I'm finding out now how to properly credit it.
>

yes, bzr kind of sucks if you're used to something else. We can try and
help you out, but many of us are new to bzr as well (soon all openstack
projects will be shifting to github.com).

As for copyright, I think a standard thing to do is: (a) if you copy a
large part of a file, retain the copyrights notices that existed in the
original file and (b) if you make substantial changes to a file, add your
own copyright in addition to those that exist.

> --
>
> https://code.launchpad.net/~tylesmit/quantum/quantum-client-library/+merge/68247
> Your team Netstack Core Developers is subscribed to branch lp:quantum.
>

--
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dan Wendlandt
Nicira Networks, Inc.
www.nicira.com | www.openvswitch.org
Sr. Product Manager
cell: 650-906-2650
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Revision history for this message
Salvatore Orlando (salvatore-orlando) wrote :

> On Tue, Jul 26, 2011 at 7:38 AM, Tyler Smith <email address hidden> wrote:
>
> > Hi Sumit, thanks.
> >
> > (1) The library as it is only has methods for the high-level API operations
> > outlined in the spec (http://wiki.openstack.org/QuantumAPISpec). There is
> > a do_request method that can be used to to send any arbitrary query to
> > Quantum server, but it's much less friendly than the high-level methods. A
> > plugin could sub-class the Client and add its own methods (although I'm not
> > sure how well this would work out long-term). Do you have any suggestions?
> >
>
> I think having some kind of generic "do_request" call makes sense.

I agree client apps can directly use do_request for submitting requests related to api extensions. We can probably try and make do_request a bit more user-friendly if it turns out to complex to us.
In the medium-long term I would however expect plugins to extend the quantum client library; not sure however whether "extended" client libraries should still be regarded as a part of Quantum.

>
>
> >
> > (2) The repo has been broken since I've tried merging lp:quantum back into
> > (I'm new to bzr, so it's taking some getting used to). I'm working on
> > getting it straightened out. When I do I'll only be adding 2 files. For
> > quantum/client.py I have kept the Citrix banner because I refactored the
> > MiniClient into it, so I retained the header. For the other file, a unit
> > tests file, I'm finding out now how to properly credit it.
> >
>
> yes, bzr kind of sucks if you're used to something else. We can try and
> help you out, but many of us are new to bzr as well (soon all openstack
> projects will be shifting to github.com).
>
> As for copyright, I think a standard thing to do is: (a) if you copy a
> large part of a file, retain the copyrights notices that existed in the
> original file and (b) if you make substantial changes to a file, add your
> own copyright in addition to those that exist.
>

I agree with Dan on Copyrights. Thiese are the general guidelines, but we don't have an "official" rule. My personal approach is:
- if you copy the file, keep the original copyright
- if you modify a part of it without altering the purpose of the file itself, add yourself as an author, do not touch copyright
- if you modify it in a way that it does something different wrt what it did before, apply your copyright
- and, of course, if you create it, use your copyright!

>
>
>
> > --
> >
> > https://code.launchpad.net/~tylesmit/quantum/quantum-client-
> library/+merge/68247
> > Your team Netstack Core Developers is subscribed to branch lp:quantum.
> >
>
>
>
> --
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~
> Dan Wendlandt
> Nicira Networks, Inc.
> www.nicira.com | www.openvswitch.org
> Sr. Product Manager
> cell: 650-906-2650
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~

Revision history for this message
Sumit Naiksatam (snaiksat) wrote :

Thanks Tyler for the suggestion on the use of do_request(), we will explore it. In my opinion that would be a good and generic enough way for accessing extensions. Of course, if there is a way to make it easier to use, all the better.

I also agree that private extensions to the client library are always an option, and to Salvatore's point, those library extensions might not (or rather should not) necessarily be a part of Quantum.

In general, given that one of the main reasons for having the client library is to have a uniform/consistent way for potentials clients to access the Quantum API (and not to duplicate efforts), I think the do_request() mechanism (and any effort at enhancing it) will serve the community well.

On the point of credits, I agree with Dan & Salvatore's guidelines, I have personally been following exactly those rules of thumb. In this particular case, Tyler, I was suggesting that you take credit for the work you have put in (even if it means a minor modification to a particular file). :-)

Revision history for this message
Ying Liu (yinliu2) wrote :

Regarding to the client-library extension, we can keep two options open.

By default, "do_request()" can be used. Agree with Sumit, this provides a consistent way to access quantum services through quantum client library.

However, if vendors (or extension providers) like to have more user friendly client, they could provide extended client library, which may not be a part of Quantum.

Best,
Ying

> -----Original Message-----
> From: <email address hidden> [mailto:<email address hidden>] On Behalf Of
> Sumit Naiksatam (snaiksat)
> Sent: Tuesday, July 26, 2011 9:29 AM
> To: <email address hidden>
> Subject: Re: [Merge] lp:~tylesmit/quantum/quantum-client-library
> intolp:quantum
>
> Thanks Tyler for the suggestion on the use of do_request(), we will
> explore it. In my opinion that would be a good and generic enough way
> for accessing extensions. Of course, if there is a way to make it
> easier to use, all the better.
>
> I also agree that private extensions to the client library are always
> an option, and to Salvatore's point, those library extensions might not
> (or rather should not) necessarily be a part of Quantum.
>
> In general, given that one of the main reasons for having the client
> library is to have a uniform/consistent way for potentials clients to
> access the Quantum API (and not to duplicate efforts), I think the
> do_request() mechanism (and any effort at enhancing it) will serve the
> community well.
>
> On the point of credits, I agree with Dan & Salvatore's guidelines, I
> have personally been following exactly those rules of thumb. In this
> particular case, Tyler, I was suggesting that you take credit for the
> work you have put in (even if it means a minor modification to a
> particular file). :-)
> --
> https://code.launchpad.net/~tylesmit/quantum/quantum-client-
> library/+merge/68247
> You are reviewing the proposed merge of lp:~tylesmit/quantum/quantum-
> client-library into lp:quantum.

Revision history for this message
dan wendlandt (danwent) wrote :

On Tue, Jul 26, 2011 at 10:14 AM, Ying Liu <email address hidden> wrote:

> Regarding to the client-library extension, we can keep two options open.
>
> By default, "do_request()" can be used. Agree with Sumit, this provides a
> consistent way to access quantum services through quantum client library.
>
> However, if vendors (or extension providers) like to have more user
> friendly client, they could provide extended client library, which may not
> be a part of Quantum.
>

+1

>
> Best,
> Ying
>
> > -----Original Message-----
> > From: <email address hidden> [mailto:<email address hidden>] On Behalf Of
> > Sumit Naiksatam (snaiksat)
> > Sent: Tuesday, July 26, 2011 9:29 AM
> > To: <email address hidden>
> > Subject: Re: [Merge] lp:~tylesmit/quantum/quantum-client-library
> > intolp:quantum
> >
> > Thanks Tyler for the suggestion on the use of do_request(), we will
> > explore it. In my opinion that would be a good and generic enough way
> > for accessing extensions. Of course, if there is a way to make it
> > easier to use, all the better.
> >
> > I also agree that private extensions to the client library are always
> > an option, and to Salvatore's point, those library extensions might not
> > (or rather should not) necessarily be a part of Quantum.
> >
> > In general, given that one of the main reasons for having the client
> > library is to have a uniform/consistent way for potentials clients to
> > access the Quantum API (and not to duplicate efforts), I think the
> > do_request() mechanism (and any effort at enhancing it) will serve the
> > community well.
> >
> > On the point of credits, I agree with Dan & Salvatore's guidelines, I
> > have personally been following exactly those rules of thumb. In this
> > particular case, Tyler, I was suggesting that you take credit for the
> > work you have put in (even if it means a minor modification to a
> > particular file). :-)
> > --
> > https://code.launchpad.net/~tylesmit/quantum/quantum-client-
> > library/+merge/68247
> > You are reviewing the proposed merge of lp:~tylesmit/quantum/quantum-
> > client-library into lp:quantum.
>
> --
>
> https://code.launchpad.net/~tylesmit/quantum/quantum-client-library/+merge/68247
> Your team Netstack Core Developers is subscribed to branch lp:quantum.
>

--
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dan Wendlandt
Nicira Networks, Inc.
www.nicira.com | www.openvswitch.org
Sr. Product Manager
cell: 650-906-2650
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Revision history for this message
Tyler Smith (tylesmit) wrote :

Due to the issues I ran into (and ended up creating), I uploaded a fixed branch to:

https://code.launchpad.net/~tylesmit/quantum/quantum-client-library-proper

And the merge request:

https://code.launchpad.net/~tylesmit/quantum/quantum-client-library-proper/+merge/69698

Revision history for this message
dan wendlandt (danwent) wrote :

Thanks Tyler,

I just wanted to confirm with you that your new merge prop means that we
should change the status of merge prop 68247 to "Rejected" so that no one is
confused about two branches currently being proposed for the same thing.
 Thanks,

Dan

On Thu, Jul 28, 2011 at 11:01 AM, Tyler Smith <email address hidden> wrote:

> Due to the issues I ran into (and ended up creating), I uploaded a fixed
> branch to:
>
> https://code.launchpad.net/~tylesmit/quantum/quantum-client-library-proper
>
> And the merge request:
>
>
> https://code.launchpad.net/~tylesmit/quantum/quantum-client-library-proper/+merge/69698
> --
>
> https://code.launchpad.net/~tylesmit/quantum/quantum-client-library/+merge/68247
> Your team Netstack Core Developers is subscribed to branch lp:quantum.
>

--
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dan Wendlandt
Nicira Networks, Inc.
www.nicira.com | www.openvswitch.org
Sr. Product Manager
cell: 650-906-2650
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Revision history for this message
Tyler Smith (tylesmit) wrote :

Yes, please reject this merge request.

Revision history for this message
Salvatore Orlando (salvatore-orlando) wrote :

Unmerged revisions

27. By Tyler Smith

Adding some negative unit tests for the client library

26. By Tyler Smith

Merge in the client-library branch

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'quantum/cli.py'
2--- quantum/cli.py 2011-07-05 16:50:30 +0000
3+++ quantum/cli.py 2011-07-23 18:23:02 +0000
4@@ -26,61 +26,9 @@
5
6 from manager import QuantumManager
7 from optparse import OptionParser
8-from quantum.common.wsgi import Serializer
9+from client import Client
10
11 FORMAT = "json"
12-CONTENT_TYPE = "application/" + FORMAT
13-
14-
15-### --- Miniclient (taking from the test directory)
16-### TODO(bgh): move this to a library within quantum
17-class MiniClient(object):
18- """A base client class - derived from Glance.BaseClient"""
19- action_prefix = '/v0.1/tenants/{tenant_id}'
20-
21- def __init__(self, host, port, use_ssl):
22- self.host = host
23- self.port = port
24- self.use_ssl = use_ssl
25- self.connection = None
26-
27- def get_connection_type(self):
28- if self.use_ssl:
29- return httplib.HTTPSConnection
30- else:
31- return httplib.HTTPConnection
32-
33- def do_request(self, tenant, method, action, body=None,
34- headers=None, params=None):
35- action = MiniClient.action_prefix + action
36- action = action.replace('{tenant_id}', tenant)
37- if type(params) is dict:
38- action += '?' + urllib.urlencode(params)
39- try:
40- connection_type = self.get_connection_type()
41- headers = headers or {}
42- # Open connection and send request
43- c = connection_type(self.host, self.port)
44- c.request(method, action, body, headers)
45- res = c.getresponse()
46- status_code = self.get_status_code(res)
47- if status_code in (httplib.OK, httplib.CREATED,
48- httplib.ACCEPTED, httplib.NO_CONTENT):
49- return res
50- else:
51- raise Exception("Server returned error: %s" % res.read())
52- except (socket.error, IOError), e:
53- raise Exception("Unable to connect to server. Got error: %s" % e)
54-
55- def get_status_code(self, response):
56- if hasattr(response, 'status_int'):
57- return response.status_int
58- else:
59- return response.status
60-### -- end of miniclient
61-
62-### -- Core CLI functions
63-
64
65 def list_nets(manager, *args):
66 tenant_id = args[0]
67@@ -91,61 +39,50 @@
68 name = net["net-name"]
69 print "\tNetwork ID:%s \n\tNetwork Name:%s \n" % (id, name)
70
71-
72 def api_list_nets(client, *args):
73 tenant_id = args[0]
74- res = client.do_request(tenant_id, 'GET', "/networks." + FORMAT)
75- resdict = json.loads(res.read())
76- LOG.debug(resdict)
77+ res = client.list_networks()
78+ LOG.debug(res)
79 print "Virtual Networks on Tenant:%s\n" % tenant_id
80- for n in resdict["networks"]:
81+ for n in res["networks"]:
82 net_id = n["id"]
83 print "\tNetwork ID:%s\n" % (net_id)
84 # TODO(bgh): we should make this call pass back the name too
85 # name = n["net-name"]
86 # LOG.info("\tNetwork ID:%s \n\tNetwork Name:%s \n" % (id, name))
87
88-
89 def create_net(manager, *args):
90 tid, name = args
91 new_net_id = manager.create_network(tid, name)
92 print "Created a new Virtual Network with ID:%s\n" % new_net_id
93
94-
95 def api_create_net(client, *args):
96 tid, name = args
97 data = {'network': {'network-name': '%s' % name}}
98- body = Serializer().serialize(data, CONTENT_TYPE)
99- res = client.do_request(tid, 'POST', "/networks." + FORMAT, body=body)
100- rd = json.loads(res.read())
101- LOG.debug(rd)
102+ res = client.create_network(data)
103+ LOG.debug(res)
104 nid = None
105 try:
106- nid = rd["networks"]["network"]["id"]
107+ nid = res["networks"]["network"]["id"]
108 except Exception, e:
109 print "Failed to create network"
110 # TODO(bgh): grab error details from ws request result
111 return
112 print "Created a new Virtual Network with ID:%s\n" % nid
113
114-
115 def delete_net(manager, *args):
116 tid, nid = args
117 manager.delete_network(tid, nid)
118 print "Deleted Virtual Network with ID:%s" % nid
119
120-
121 def api_delete_net(client, *args):
122 tid, nid = args
123- res = client.do_request(tid, 'DELETE', "/networks/" + nid + "." + FORMAT)
124- status = res.status
125- if status != 202:
126+ try:
127+ res = client.delete_network(nid)
128+ print "Deleted Virtual Network with ID:%s" % nid
129+ except Exception, e:
130 print "Failed to delete network"
131- output = res.read()
132- print output
133- else:
134- print "Deleted Virtual Network with ID:%s" % nid
135-
136+ LOG.error("Failed to delete network: %s" % e)
137
138 def detail_net(manager, *args):
139 tid, nid = args
140@@ -154,46 +91,44 @@
141 for iface in iface_list:
142 print "\tRemote interface:%s" % iface
143
144-
145 def api_detail_net(client, *args):
146 tid, nid = args
147- res = client.do_request(tid, 'GET',
148- "/networks/%s/ports.%s" % (nid, FORMAT))
149- output = res.read()
150- if res.status != 200:
151- LOG.error("Failed to list ports: %s" % output)
152- return
153- rd = json.loads(output)
154- LOG.debug(rd)
155+ try:
156+ res = client.list_network_details(nid)["networks"]["network"]
157+ except Exception, e:
158+ LOG.error("Failed to get network details: %s" % e)
159+ return
160+
161+ try:
162+ ports = client.list_ports(nid)
163+ except Exception, e:
164+ LOG.error("Failed to list ports: %s" % e)
165+ return
166+ print "Network %s (%s)" % (res['name'], res['id'])
167 print "Remote Interfaces on Virtual Network:%s\n" % nid
168- for port in rd["ports"]:
169+ for port in ports["ports"]:
170 pid = port["id"]
171- res = client.do_request(tid, 'GET',
172- "/networks/%s/ports/%s/attachment.%s" % (nid, pid, FORMAT))
173- output = res.read()
174- rd = json.loads(output)
175- LOG.debug(rd)
176- remote_iface = rd["attachment"]
177+ res = client.list_port_attachments(nid, pid)
178+ LOG.debug(res)
179+ remote_iface = res["attachment"]
180 print "\tRemote interface:%s" % remote_iface
181
182-
183 def rename_net(manager, *args):
184 tid, nid, name = args
185 manager.rename_network(tid, nid, name)
186 print "Renamed Virtual Network with ID:%s" % nid
187
188-
189 def api_rename_net(client, *args):
190 tid, nid, name = args
191 data = {'network': {'network-name': '%s' % name}}
192- body = Serializer().serialize(data, CONTENT_TYPE)
193- res = client.do_request(tid, 'PUT', "/networks/%s.%s" % (nid, FORMAT),
194- body=body)
195- resdict = json.loads(res.read())
196- LOG.debug(resdict)
197+ try:
198+ res = client.update_network(nid, data)
199+ except Exception, e:
200+ LOG.error("Failed to rename network %s: %s" % (nid,e))
201+ return
202+ LOG.debug(res)
203 print "Renamed Virtual Network with ID:%s" % nid
204
205-
206 def list_ports(manager, *args):
207 tid, nid = args
208 ports = manager.get_all_ports(tid, nid)
209@@ -201,61 +136,52 @@
210 for port in ports:
211 print "\tVirtual Port:%s" % port["port-id"]
212
213-
214 def api_list_ports(client, *args):
215 tid, nid = args
216- res = client.do_request(tid, 'GET',
217- "/networks/%s/ports.%s" % (nid, FORMAT))
218- output = res.read()
219- if res.status != 200:
220- LOG.error("Failed to list ports: %s" % output)
221+ try:
222+ ports = client.list_ports(nid)
223+ except Exception, e:
224+ LOG.error("Failed to list ports: %s" % e)
225 return
226- rd = json.loads(output)
227- LOG.debug(rd)
228+
229+ LOG.debug(ports)
230 print "Ports on Virtual Network:%s\n" % nid
231- for port in rd["ports"]:
232+ for port in ports["ports"]:
233 print "\tVirtual Port:%s" % port["id"]
234
235-
236 def create_port(manager, *args):
237 tid, nid = args
238 new_port = manager.create_port(tid, nid)
239 print "Created Virtual Port:%s " \
240 "on Virtual Network:%s" % (new_port, nid)
241
242-
243 def api_create_port(client, *args):
244 tid, nid = args
245- res = client.do_request(tid, 'POST',
246- "/networks/%s/ports.%s" % (nid, FORMAT))
247- output = res.read()
248- if res.status != 200:
249- LOG.error("Failed to create port: %s" % output)
250+ try:
251+ res = client.create_port(nid)
252+ except Exception, e:
253+ LOG.error("Failed to create port: %s" % e)
254 return
255- rd = json.loads(output)
256- new_port = rd["ports"]["port"]["id"]
257+ new_port = res["ports"]["port"]["id"]
258 print "Created Virtual Port:%s " \
259 "on Virtual Network:%s" % (new_port, nid)
260
261-
262 def delete_port(manager, *args):
263 tid, nid, pid = args
264- manager.delete_port(tid, nid, pid)
265 LOG.info("Deleted Virtual Port:%s " \
266 "on Virtual Network:%s" % (pid, nid))
267
268-
269 def api_delete_port(client, *args):
270 tid, nid, pid = args
271- res = client.do_request(tid, 'DELETE',
272- "/networks/%s/ports/%s.%s" % (nid, pid, FORMAT))
273- output = res.read()
274- if res.status != 202:
275- LOG.error("Failed to delete port: %s" % output)
276+ try:
277+ res = client.delete_port(nid, pid)
278+ except Exception, e:
279+ LOG.error("Failed to delete port: %s" % e)
280 return
281 LOG.info("Deleted Virtual Port:%s " \
282 "on Virtual Network:%s" % (pid, nid))
283-
284+ print "Deleted Virtual Port:%s " \
285+ "on Virtual Network:%s" % (pid, nid)
286
287 def detail_port(manager, *args):
288 tid, nid, pid = args
289@@ -263,115 +189,111 @@
290 print "Virtual Port:%s on Virtual Network:%s " \
291 "contains remote interface:%s" % (pid, nid, port_detail)
292
293-
294 def api_detail_port(client, *args):
295 tid, nid, pid = args
296- res = client.do_request(tid, 'GET',
297- "/networks/%s/ports/%s.%s" % (nid, pid, FORMAT))
298- output = res.read()
299- if res.status != 200:
300- LOG.error("Failed to get port details: %s" % output)
301+ try:
302+ port = client.list_port_details(nid, pid)["ports"]["port"]
303+ except Exception, e:
304+ LOG.error("Failed to get port details: %s" % e)
305 return
306- rd = json.loads(output)
307- port = rd["ports"]["port"]
308+
309 id = port["id"]
310 attachment = port["attachment"]
311 LOG.debug(port)
312 print "Virtual Port:%s on Virtual Network:%s " \
313 "contains remote interface:%s" % (pid, nid, attachment)
314
315-
316 def plug_iface(manager, *args):
317 tid, nid, pid, vid = args
318 manager.plug_interface(tid, nid, pid, vid)
319 print "Plugged remote interface:%s " \
320 "into Virtual Network:%s" % (vid, nid)
321
322-
323 def api_plug_iface(client, *args):
324- tid, nid, pid, vid = args
325- data = {'port': {'attachment-id': '%s' % vid}}
326- body = Serializer().serialize(data, CONTENT_TYPE)
327- res = client.do_request(tid, 'PUT',
328- "/networks/%s/ports/%s/attachment.%s" % (nid, pid, FORMAT), body=body)
329- output = res.read()
330- LOG.debug(output)
331- if res.status != 202:
332+ tid, nid, pid, vid = args
333+ try:
334+ data = {'port': {'attachment-id': '%s' % vid}}
335+ res = client.attach_resource(nid, pid, data)
336+ except Exception, e:
337 LOG.error("Failed to plug iface \"%s\" to port \"%s\": %s" % (vid,
338 pid, output))
339 return
340- print "Plugged interface \"%s\" to port:%s on network:%s" % (vid, pid,
341- nid)
342-
343-
344-def unplug_iface(manager, *args):
345+ LOG.debug(res)
346+ print "Plugged interface \"%s\" to port:%s on network:%s" % (vid, pid, nid)
347+
348+def unplug_iface(manager, *args):
349 tid, nid, pid = args
350 manager.unplug_interface(tid, nid, pid)
351 print "UnPlugged remote interface " \
352 "from Virtual Port:%s Virtual Network:%s" % (pid, nid)
353
354-
355 def api_unplug_iface(client, *args):
356 tid, nid, pid = args
357- data = {'port': {'attachment-id': ''}}
358- body = Serializer().serialize(data, CONTENT_TYPE)
359- res = client.do_request(tid, 'DELETE',
360- "/networks/%s/ports/%s/attachment.%s" % (nid, pid, FORMAT), body=body)
361- output = res.read()
362- LOG.debug(output)
363- if res.status != 202:
364- LOG.error("Failed to unplug iface from port \"%s\": %s" % \
365- (pid, output))
366+ try:
367+ res = client.detach_resource(nid, pid)
368+ except Exception, e:
369+ LOG.error("Failed to unplug iface from port \"%s\": %s" % (pid, e))
370 return
371+ LOG.debug(res)
372 print "Unplugged interface from port:%s on network:%s" % (pid, nid)
373
374-
375 commands = {
376 "list_nets": {
377 "func": list_nets,
378 "api_func": api_list_nets,
379- "args": ["tenant-id"]},
380+ "args": ["tenant-id"]
381+ },
382 "create_net": {
383 "func": create_net,
384 "api_func": api_create_net,
385- "args": ["tenant-id", "net-name"]},
386+ "args": ["tenant-id", "net-name"]
387+ },
388 "delete_net": {
389 "func": delete_net,
390 "api_func": api_delete_net,
391- "args": ["tenant-id", "net-id"]},
392+ "args": ["tenant-id", "net-id"]
393+ },
394 "detail_net": {
395 "func": detail_net,
396 "api_func": api_detail_net,
397- "args": ["tenant-id", "net-id"]},
398+ "args": ["tenant-id", "net-id"]
399+ },
400 "rename_net": {
401 "func": rename_net,
402 "api_func": api_rename_net,
403- "args": ["tenant-id", "net-id", "new-name"]},
404+ "args": ["tenant-id", "net-id", "new-name"]
405+ },
406 "list_ports": {
407 "func": list_ports,
408 "api_func": api_list_ports,
409- "args": ["tenant-id", "net-id"]},
410+ "args": ["tenant-id", "net-id"]
411+ },
412 "create_port": {
413 "func": create_port,
414 "api_func": api_create_port,
415- "args": ["tenant-id", "net-id"]},
416+ "args": ["tenant-id", "net-id"]
417+ },
418 "delete_port": {
419 "func": delete_port,
420 "api_func": api_delete_port,
421- "args": ["tenant-id", "net-id", "port-id"]},
422+ "args": ["tenant-id", "net-id", "port-id"]
423+ },
424 "detail_port": {
425 "func": detail_port,
426 "api_func": api_detail_port,
427- "args": ["tenant-id", "net-id", "port-id"]},
428+ "args": ["tenant-id", "net-id", "port-id"]
429+ },
430 "plug_iface": {
431 "func": plug_iface,
432 "api_func": api_plug_iface,
433- "args": ["tenant-id", "net-id", "port-id", "iface-id"]},
434+ "args": ["tenant-id", "net-id", "port-id", "iface-id"]
435+ },
436 "unplug_iface": {
437 "func": unplug_iface,
438 "api_func": api_unplug_iface,
439- "args": ["tenant-id", "net-id", "port-id"]}, }
440-
441+ "args": ["tenant-id", "net-id", "port-id"]
442+ },
443+ }
444
445 def help():
446 print "\nCommands:"
447@@ -379,7 +301,6 @@
448 print " %s %s" % (k,
449 " ".join(["<%s>" % y for y in commands[k]["args"]]))
450
451-
452 def build_args(cmd, cmdargs, arglist):
453 args = []
454 orig_arglist = arglist[:]
455@@ -401,7 +322,6 @@
456 return None
457 return args
458
459-
460 if __name__ == "__main__":
461 usagestr = "Usage: %prog [OPTIONS] <command> [args]"
462 parser = OptionParser(usage=usagestr)
463@@ -440,8 +360,9 @@
464 sys.exit(1)
465 LOG.debug("Executing command \"%s\" with args: %s" % (cmd, args))
466 if not options.load_plugin:
467- client = MiniClient(options.host, options.port, options.ssl)
468- if "api_func" not in commands[cmd]:
469+ client = Client(options.host, options.port, options.ssl,
470+ args[0], FORMAT)
471+ if not commands[cmd].has_key("api_func"):
472 LOG.error("API version of \"%s\" is not yet implemented" % cmd)
473 sys.exit(1)
474 commands[cmd]["api_func"](client, *args)
475
476=== added file 'quantum/client.py'
477--- quantum/client.py 1970-01-01 00:00:00 +0000
478+++ quantum/client.py 2011-07-23 18:23:02 +0000
479@@ -0,0 +1,254 @@
480+# vim: tabstop=4 shiftwidth=4 softtabstop=4
481+
482+# Copyright 2011 Citrix Systems
483+# All Rights Reserved.
484+#
485+# Licensed under the Apache License, Version 2.0 (the "License"); you may
486+# not use this file except in compliance with the License. You may obtain
487+# a copy of the License at
488+#
489+# http://www.apache.org/licenses/LICENSE-2.0
490+#
491+# Unless required by applicable law or agreed to in writing, software
492+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
493+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
494+# License for the specific language governing permissions and limitations
495+# under the License.
496+
497+import httplib
498+import socket
499+import urllib
500+from quantum.common.wsgi import Serializer
501+
502+class api_call(object):
503+ """A Decorator to add support for format and tenant overriding"""
504+ def __init__(self, f):
505+ self.f = f
506+
507+ def __get__(self, instance, owner):
508+ def with_params(*args, **kwargs):
509+ # Backup the format and tenant, then temporarily change them if needed
510+ (format, tenant) = (instance.format, instance.tenant)
511+
512+ if 'format' in kwargs:
513+ instance.format = kwargs['format']
514+ if 'tenant' in kwargs:
515+ instance.tenant = kwargs['tenant']
516+
517+ ret = self.f(instance, *args)
518+ (instance.format, instance.tenant) = (format, tenant)
519+ return ret
520+ return with_params
521+
522+class Client(object):
523+
524+ """A base client class - derived from Glance.BaseClient"""
525+
526+ action_prefix = '/v0.1/tenants/{tenant_id}'
527+
528+ """Action query strings"""
529+ networks_path = "/networks"
530+ network_path = "/networks/%s"
531+ ports_path = "/networks/%s/ports"
532+ port_path = "/networks/%s/ports/%s"
533+ attachment_path = "/networks/%s/ports/%s/attachment"
534+
535+ def __init__(self, host, port, use_ssl,
536+ tenant=None, format="xml", testingStub=None):
537+ """
538+ Creates a new client to some service.
539+
540+ :param host: The host where service resides
541+ :param port: The port where service resides
542+ :param use_ssl: Should we use HTTPS?
543+ :param tenant: The tenant ID to make requests with
544+ :param format: The format to query the server with
545+ :param testingStub: A class that stubs basic server attributes for tests
546+ """
547+ self.host = host
548+ self.port = port
549+ self.use_ssl = use_ssl
550+ self.tenant = tenant
551+ self.format = format
552+ self.connection = None
553+ self.testingStub = testingStub
554+
555+ def get_connection_type(self):
556+ """
557+ Returns the proper connection type
558+ """
559+ if self.testingStub:
560+ return self.testingStub
561+ if self.use_ssl:
562+ return httplib.HTTPSConnection
563+ else:
564+ return httplib.HTTPConnection
565+
566+ def do_request(self, method, action, body=None,
567+ headers=None, params=None):
568+ """
569+ Connects to the server and issues a request.
570+ Returns the result data, or raises an appropriate exception if
571+ HTTP status code is not 2xx
572+
573+ :param method: HTTP method ("GET", "POST", "PUT", etc...)
574+ :param body: string of data to send, or None (default)
575+ :param headers: mapping of key/value pairs to add as headers
576+ :param params: dictionary of key/value pairs to add to append
577+ to action
578+
579+ """
580+
581+ # Ensure we have a tenant id
582+ if not self.tenant:
583+ raise Exception("Tenant ID not set")
584+
585+ # Add format and tenant_id
586+ action += ".%s" % self.format
587+ action = Client.action_prefix + action
588+ action = action.replace('{tenant_id}',self.tenant)
589+
590+ if type(params) is dict:
591+ action += '?' + urllib.urlencode(params)
592+
593+ try:
594+ connection_type = self.get_connection_type()
595+ headers = headers or {}
596+
597+ # Open connection and send request
598+ c = connection_type(self.host, self.port)
599+ c.request(method, action, body, headers)
600+ res = c.getresponse()
601+ status_code = self.get_status_code(res)
602+ if status_code in (httplib.OK,
603+ httplib.CREATED,
604+ httplib.ACCEPTED,
605+ httplib.NO_CONTENT):
606+ return self.deserialize(res)
607+ else:
608+ raise Exception("Server returned error: %s" % res.read())
609+
610+ except (socket.error, IOError), e:
611+ raise Exception("Unable to connect to "
612+ "server. Got error: %s" % e)
613+
614+ def get_status_code(self, response):
615+ """
616+ Returns the integer status code from the response, which
617+ can be either a Webob.Response (used in testing) or httplib.Response
618+ """
619+ if hasattr(response, 'status_int'):
620+ return response.status_int
621+ else:
622+ return response.status
623+
624+ def serialize(self, data):
625+ if type(data) is dict:
626+ return Serializer().serialize(data, self.content_type())
627+
628+ def deserialize(self, data):
629+ if self.get_status_code(data) == 202:
630+ return data.read()
631+ return Serializer().deserialize(data.read(), self.content_type())
632+
633+ def content_type(self, format=None):
634+ if not format:
635+ format = self.format
636+ return "application/%s" % (format)
637+
638+ @api_call
639+ def list_networks(self):
640+ """
641+ Queries the server for a list of networks
642+ """
643+ return self.do_request("GET", self.networks_path)
644+
645+ @api_call
646+ def list_network_details(self, network):
647+ """
648+ Queries the server for the details of a certain network
649+ """
650+ return self.do_request("GET", (self.network_path%network))
651+
652+ @api_call
653+ def create_network(self, body=None):
654+ """
655+ Creates a new network on the server
656+ """
657+ body = self.serialize(body)
658+ return self.do_request("POST", self.networks_path, body=body)
659+
660+ @api_call
661+ def update_network(self, network, body=None):
662+ """
663+ Updates a network on the server
664+ """
665+ body = self.serialize(body)
666+ return self.do_request("PUT", self.network_path % (network),body=body)
667+
668+ @api_call
669+ def delete_network(self, network):
670+ """
671+ Deletes a network on the server
672+ """
673+ return self.do_request("DELETE", self.network_path % (network))
674+
675+ @api_call
676+ def list_ports(self, network):
677+ """
678+ Queries the server for a list of ports on a given network
679+ """
680+ return self.do_request("GET", self.ports_path % (network))
681+
682+ @api_call
683+ def list_port_details(self, network, port):
684+ """
685+ Queries the server for a list of ports on a given network
686+ """
687+ return self.do_request("GET", self.port_path % (network,port))
688+
689+ @api_call
690+ def create_port(self, network):
691+ """
692+ Creates a new port on a network on the server
693+ """
694+ return self.do_request("POST", self.ports_path % (network))
695+
696+ @api_call
697+ def delete_port(self, network, port):
698+ """
699+ Deletes a port from a network on the server
700+ """
701+ return self.do_request("DELETE", self.port_path % (network,port))
702+
703+ @api_call
704+ def set_port_state(self, network, port, body=None):
705+ """
706+ Sets the state of a port on the server
707+ """
708+ body = self.serialize(body)
709+ return self.do_request("PUT",
710+ self.port_path % (network,port), body=body)
711+
712+ @api_call
713+ def list_port_attachments(self, network, port):
714+ """
715+ Deletes a port from a network on the server
716+ """
717+ return self.do_request("GET", self.attachment_path % (network,port))
718+
719+ @api_call
720+ def attach_resource(self, network, port, body=None):
721+ """
722+ Deletes a port from a network on the server
723+ """
724+ body = self.serialize(body)
725+ return self.do_request("PUT",
726+ self.attachment_path % (network,port), body=body)
727+
728+ @api_call
729+ def detach_resource(self, network, port):
730+ """
731+ Deletes a port from a network on the server
732+ """
733+ return self.do_request("DELETE", self.attachment_path % (network,port))
734
735=== added directory 'tests'
736=== removed directory 'tests'
737=== added file 'tests/__init__.py'
738=== removed file 'tests/__init__.py'
739=== added directory 'tests/unit'
740=== removed directory 'tests/unit'
741=== added file 'tests/unit/__init__.py'
742--- tests/unit/__init__.py 1970-01-01 00:00:00 +0000
743+++ tests/unit/__init__.py 2011-07-23 18:23:02 +0000
744@@ -0,0 +1,32 @@
745+# vim: tabstop=4 shiftwidth=4 softtabstop=4
746+
747+# Copyright 2011 OpenStack LLC.
748+# All Rights Reserved.
749+#
750+# Licensed under the Apache License, Version 2.0 (the "License"); you may
751+# not use this file except in compliance with the License. You may obtain
752+# a copy of the License at
753+#
754+# http://www.apache.org/licenses/LICENSE-2.0
755+#
756+# Unless required by applicable law or agreed to in writing, software
757+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
758+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
759+# License for the specific language governing permissions and limitations
760+# under the License.
761+
762+# See http://code.google.com/p/python-nose/issues/detail?id=373
763+# The code below enables nosetests to work with i18n _() blocks
764+import __builtin__
765+import unittest
766+setattr(__builtin__, '_', lambda x: x)
767+
768+
769+class BaseTest(unittest.TestCase):
770+
771+ def setUp(self):
772+ pass
773+
774+
775+def setUp():
776+ pass
777
778=== removed file 'tests/unit/__init__.py'
779--- tests/unit/__init__.py 2011-06-08 08:52:51 +0000
780+++ tests/unit/__init__.py 1970-01-01 00:00:00 +0000
781@@ -1,32 +0,0 @@
782-# vim: tabstop=4 shiftwidth=4 softtabstop=4
783-
784-# Copyright 2011 OpenStack LLC.
785-# All Rights Reserved.
786-#
787-# Licensed under the Apache License, Version 2.0 (the "License"); you may
788-# not use this file except in compliance with the License. You may obtain
789-# a copy of the License at
790-#
791-# http://www.apache.org/licenses/LICENSE-2.0
792-#
793-# Unless required by applicable law or agreed to in writing, software
794-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
795-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
796-# License for the specific language governing permissions and limitations
797-# under the License.
798-
799-# See http://code.google.com/p/python-nose/issues/detail?id=373
800-# The code below enables nosetests to work with i18n _() blocks
801-import __builtin__
802-import unittest
803-setattr(__builtin__, '_', lambda x: x)
804-
805-
806-class BaseTest(unittest.TestCase):
807-
808- def setUp(self):
809- pass
810-
811-
812-def setUp():
813- pass
814
815=== added file 'tests/unit/api.py'
816--- tests/unit/api.py 1970-01-01 00:00:00 +0000
817+++ tests/unit/api.py 2011-07-23 18:23:02 +0000
818@@ -0,0 +1,603 @@
819+import logging
820+import unittest
821+import re
822+
823+from quantum.common.wsgi import Serializer
824+from quantum.client import Client
825+
826+LOG = logging.getLogger('quantum.tests.test_api')
827+
828+# Set a couple tenants to use for testing
829+TENANT_1 = 'totore'
830+TENANT_2 = 'totore2'
831+
832+class ServerStub():
833+ """This class stubs a basic server for the API client to talk to"""
834+
835+ class Response(object):
836+ """This class stubs a basic response to send the API client"""
837+ def __init__(self, content = None, status = None):
838+ self.content = content
839+ self.status = status
840+
841+ def read(self):
842+ return self.content
843+
844+ def status(self):
845+ return status
846+
847+ # To test error codes, set the host to 10.0.0.1, and the port to the code
848+ def __init__(self, host, port):
849+ self.host = host
850+ self.port = port
851+
852+ def request(self, method, action, body, headers):
853+ self.method = method
854+ self.action = action
855+ self.body = body
856+
857+ def status(self, status=None):
858+ return status or 200
859+
860+ def getresponse(self):
861+ res = self.Response(status = self.status())
862+
863+ # If the host is 10.0.0.1, return the port as an error code
864+ if self.host == "10.0.0.1":
865+ res.status = self.port
866+ return res
867+
868+ # Extract important information from the action string to assure sanity
869+ match = re.search('tenants/(.+?)/(.+)\.(json|xml)$', self.action)
870+
871+ (tenant,path,format) = (match.group(1),match.group(2),match.group(3))
872+
873+ data = {'data': {'method':self.method, 'action':self.action,
874+ 'body':self.body,'tenant':tenant, 'path':path, 'format':format}}
875+
876+ # Serialize it to the proper format so the API client can deserialize it
877+ if data['data']['format'] == 'json':
878+ res.content = Serializer().serialize(data, "application/json")
879+ else:
880+ res.content = Serializer().serialize(data, "application/xml")
881+ return res
882+
883+class APITest(unittest.TestCase):
884+
885+ def setUp(self):
886+ """ Setups a test environment for the API client """
887+ HOST = '127.0.0.1'
888+ PORT = 9696
889+ USE_SSL = False
890+
891+ self.client = Client(HOST,PORT,USE_SSL,TENANT_1,'json',ServerStub)
892+
893+ def _assert_sanity(self, call, status, method, path, data=[], params={}):
894+ """ Perform common assertions to test the sanity of client requests """
895+
896+ # Handle an error case first
897+ if status != 200:
898+ (self.client.host,self.client.port) = ("10.0.0.1", status)
899+ self.assertRaises(Exception, call, *data, **params)
900+ return
901+
902+ # Not an error case
903+ # Make the call, then get the data from the root node and strip its data
904+ data = call(*data, **params)['data']
905+ for k in data:
906+ if data[k]:
907+ data[k] = data[k].strip()
908+
909+ self.assertEqual(data['method'], method)
910+ self.assertEqual(data['format'], params['format'])
911+ self.assertEqual(data['tenant'], params['tenant'])
912+ self.assertEqual(data['path'], path)
913+
914+
915+ def _test_list_networks(self, tenant=TENANT_1, format='json', status=200):
916+ LOG.debug("_test_list_networks - tenant:%s "\
917+ "- format:%s - START", format, tenant)
918+
919+ self._assert_sanity(self.client.list_networks,
920+ status,
921+ "GET",
922+ "networks",
923+ data = [],
924+ params = {'tenant':tenant, 'format':format},)
925+
926+ LOG.debug("_test_list_networks - tenant:%s "\
927+ "- format:%s - END", format, tenant)
928+
929+ def _test_list_network_details(self,
930+ tenant=TENANT_1,format='json',status=200):
931+ LOG.debug("_test_list_network_details - tenant:%s "\
932+ "- format:%s - START", format, tenant)
933+
934+ self._assert_sanity(self.client.list_network_details,
935+ status,
936+ "GET",
937+ "networks/001",
938+ data = ["001"],
939+ params = {'tenant':tenant, 'format':format})
940+
941+ LOG.debug("_test_list_network_details - tenant:%s "\
942+ "- format:%s - END", format, tenant)
943+
944+ def _test_create_network(self, tenant=TENANT_1, format='json', status=200):
945+ LOG.debug("_test_create_network - tenant:%s "\
946+ "- format:%s - START", format, tenant)
947+
948+ self._assert_sanity(self.client.create_network,
949+ status,
950+ "POST",
951+ "networks",
952+ data = [{'network': {'net-name': 'testNetwork'}}],
953+ params = {'tenant':tenant, 'format':format})
954+
955+ LOG.debug("_test_create_network - tenant:%s "\
956+ "- format:%s - END", format, tenant)
957+
958+ def _test_update_network(self, tenant=TENANT_1, format='json', status=200):
959+ LOG.debug("_test_update_network - tenant:%s "\
960+ "- format:%s - START", format, tenant)
961+
962+ self._assert_sanity(self.client.update_network,
963+ status,
964+ "PUT",
965+ "networks/001",
966+ data = [
967+ "001",
968+ {'network': {'net-name': 'newName'}}
969+ ],
970+ params = {'tenant':tenant, 'format':format})
971+
972+ LOG.debug("_test_update_network - tenant:%s "\
973+ "- format:%s - END", format, tenant)
974+
975+ def _test_delete_network(self, tenant=TENANT_1, format='json', status=200):
976+ LOG.debug("_test_delete_network - tenant:%s "\
977+ "- format:%s - START", format, tenant)
978+
979+ self._assert_sanity(self.client.delete_network,
980+ status,
981+ "DELETE",
982+ "networks/001",
983+ data = ["001"],
984+ params = {'tenant':tenant, 'format':format})
985+
986+ LOG.debug("_test_delete_network - tenant:%s "\
987+ "- format:%s - END", format, tenant)
988+
989+ def _test_list_ports(self, tenant = TENANT_1, format = 'json', status=200):
990+ LOG.debug("_test_list_ports - tenant:%s "\
991+ "- format:%s - START", format, tenant)
992+
993+ self._assert_sanity(self.client.list_ports,
994+ status,
995+ "GET",
996+ "networks/001/ports",
997+ data = ["001"],
998+ params = {'tenant':tenant, 'format':format})
999+
1000+ LOG.debug("_test_list_ports - tenant:%s "\
1001+ "- format:%s - END", format, tenant)
1002+
1003+ def _test_list_port_details(self,
1004+ tenant=TENANT_1, format='json', status=200):
1005+ LOG.debug("_test_list_port_details - tenant:%s "\
1006+ "- format:%s - START", format, tenant)
1007+
1008+ self._assert_sanity(self.client.list_port_details,
1009+ status,
1010+ "GET",
1011+ "networks/001/ports/001",
1012+ data = ["001","001"],
1013+ params = {'tenant':tenant, 'format':format})
1014+
1015+ LOG.debug("_test_list_port_details - tenant:%s "\
1016+ "- format:%s - END", format, tenant)
1017+
1018+ def _test_create_port(self, tenant = TENANT_1, format = 'json', status=200):
1019+ LOG.debug("_test_create_port - tenant:%s "\
1020+ "- format:%s - START", format, tenant)
1021+
1022+ self._assert_sanity(self.client.create_port,
1023+ status,
1024+ "POST",
1025+ "networks/001/ports",
1026+ data = ["001"],
1027+ params = {'tenant':tenant, 'format':format})
1028+
1029+
1030+ LOG.debug("_test_create_port - tenant:%s "\
1031+ "- format:%s - END", format, tenant)
1032+
1033+ def _test_delete_port(self, tenant = TENANT_1, format = 'json', status=200):
1034+ LOG.debug("_test_delete_port - tenant:%s "\
1035+ "- format:%s - START", format, tenant)
1036+
1037+ self._assert_sanity(self.client.delete_port,
1038+ status,
1039+ "DELETE",
1040+ "networks/001/ports/001",
1041+ data = ["001","001"],
1042+ params = {'tenant':tenant, 'format':format})
1043+
1044+ LOG.debug("_test_delete_port - tenant:%s "\
1045+ "- format:%s - END", format, tenant)
1046+
1047+
1048+ def _test_set_port_state(self, tenant=TENANT_1, format='json', status=200):
1049+ LOG.debug("_test_set_port_state - tenant:%s "\
1050+ "- format:%s - START", format, tenant)
1051+
1052+ self._assert_sanity(self.client.set_port_state,
1053+ status,
1054+ "PUT",
1055+ "networks/001/ports/001",
1056+ data = ["001","001",{'port':{'state':'ACTIVE'}}],
1057+ params = {'tenant':tenant, 'format':format})
1058+
1059+ LOG.debug("_test_set_port_state - tenant:%s "\
1060+ "- format:%s - END", format, tenant)
1061+
1062+ def _test_list_port_attachments(self,
1063+ tenant=TENANT_1, format='json', status=200):
1064+ LOG.debug("_test_list_port_attachments - tenant:%s "\
1065+ "- format:%s - START", format, tenant)
1066+
1067+ self._assert_sanity(self.client.list_port_attachments,
1068+ status,
1069+ "GET",
1070+ "networks/001/ports/001/attachment",
1071+ data = ["001","001"],
1072+ params = {'tenant':tenant, 'format':format})
1073+
1074+ LOG.debug("_test_list_port_attachments - tenant:%s "\
1075+ "- format:%s - END", format, tenant)
1076+
1077+ def _test_attach_resource(self, tenant=TENANT_1, format='json', status=200):
1078+ LOG.debug("_test_attach_resource - tenant:%s "\
1079+ "- format:%s - START", format, tenant)
1080+
1081+ self._assert_sanity(self.client.attach_resource,
1082+ status,
1083+ "PUT",
1084+ "networks/001/ports/001/attachment",
1085+ data = ["001","001",{'resource':{'id':'1234'}}],
1086+ params = {'tenant':tenant, 'format':format})
1087+
1088+ LOG.debug("_test_attach_resource - tenant:%s "\
1089+ "- format:%s - END", format, tenant)
1090+
1091+ def _test_detach_resource(self, tenant=TENANT_1, format='json', status=200):
1092+ LOG.debug("_test_detach_resource - tenant:%s "\
1093+ "- format:%s - START", format, tenant)
1094+
1095+ self._assert_sanity(self.client.detach_resource,
1096+ status,
1097+ "DELETE",
1098+ "networks/001/ports/001/attachment",
1099+ data = ["001","001"],
1100+ params = {'tenant':tenant, 'format':format})
1101+
1102+ LOG.debug("_test_detach_resource - tenant:%s "\
1103+ "- format:%s - END", format, tenant)
1104+
1105+
1106+ def test_list_networks_json(self):
1107+ self._test_list_networks(format='json')
1108+
1109+ def test_list_networks_xml(self):
1110+ self._test_list_networks(format='xml')
1111+
1112+ def test_list_networks_alt_tenant(self):
1113+ self._test_list_networks(tenant=TENANT_2)
1114+
1115+ def test_list_networks_error_470(self):
1116+ self._test_list_networks(status=470)
1117+
1118+ def test_list_networks_error_401(self):
1119+ self._test_list_networks(status=401)
1120+
1121+
1122+
1123+ def test_list_network_details_json(self):
1124+ self._test_list_network_details(format='json')
1125+
1126+ def test_list_network_details_xml(self):
1127+ self._test_list_network_details(format='xml')
1128+
1129+ def test_list_network_details_alt_tenant(self):
1130+ self._test_list_network_details(tenant=TENANT_2)
1131+
1132+ def test_list_network_details_error_470(self):
1133+ self._test_list_network_details(status=470)
1134+
1135+ def test_list_network_details_error_401(self):
1136+ self._test_list_network_details(status=401)
1137+
1138+ def test_list_network_details_error_420(self):
1139+ self._test_list_network_details(status=420)
1140+
1141+
1142+
1143+ def test_create_network_json(self):
1144+ self._test_create_network(format='json')
1145+
1146+ def test_create_network_xml(self):
1147+ self._test_create_network(format='xml')
1148+
1149+ def test_create_network_alt_tenant(self):
1150+ self._test_create_network(tenant=TENANT_2)
1151+
1152+ def test_create_network_error_470(self):
1153+ self._test_create_network(status=470)
1154+
1155+ def test_create_network_error_401(self):
1156+ self._test_create_network(status=401)
1157+
1158+ def test_create_network_error_400(self):
1159+ self._test_create_network(status=400)
1160+
1161+ def test_create_network_error_422(self):
1162+ self._test_create_network(status=422)
1163+
1164+
1165+
1166+
1167+ def test_update_network_json(self):
1168+ self._test_update_network(format='json')
1169+
1170+ def test_update_network_xml(self):
1171+ self._test_update_network(format='xml')
1172+
1173+ def test_update_network_alt_tenant(self):
1174+ self._test_update_network(tenant=TENANT_2)
1175+
1176+ def test_update_network_error_470(self):
1177+ self._test_update_network(status=470)
1178+
1179+ def test_update_network_error_401(self):
1180+ self._test_update_network(status=401)
1181+
1182+ def test_update_network_error_400(self):
1183+ self._test_update_network(status=400)
1184+
1185+ def test_update_network_error_420(self):
1186+ self._test_update_network(status=420)
1187+
1188+ def test_update_network_error_422(self):
1189+ self._test_update_network(status=422)
1190+
1191+
1192+
1193+ def test_delete_network_json(self):
1194+ self._test_delete_network(format='json')
1195+
1196+ def test_delete_network_xml(self):
1197+ self._test_delete_network(format='xml')
1198+
1199+ def test_delete_network_alt_tenant(self):
1200+ self._test_delete_network(tenant=TENANT_2)
1201+
1202+ def test_delete_network_error_470(self):
1203+ self._test_delete_network(status=470)
1204+
1205+ def test_delete_network_error_401(self):
1206+ self._test_delete_network(status=401)
1207+
1208+ def test_delete_network_error_420(self):
1209+ self._test_delete_network(status=420)
1210+
1211+ def test_delete_network_error_421(self):
1212+ self._test_delete_network(status=421)
1213+
1214+
1215+
1216+ def test_list_ports_json(self):
1217+ self._test_list_ports(format='json')
1218+
1219+ def test_list_ports_xml(self):
1220+ self._test_list_ports(format='xml')
1221+
1222+ def test_list_ports_alt_tenant(self):
1223+ self._test_list_ports(tenant=TENANT_2)
1224+
1225+ def test_list_ports_error_470(self):
1226+ self._test_list_ports(status=470)
1227+
1228+ def test_list_ports_error_401(self):
1229+ self._test_list_ports(status=401)
1230+
1231+ def test_list_ports_error_420(self):
1232+ self._test_list_ports(status=420)
1233+
1234+
1235+
1236+ def test_list_port_details_json(self):
1237+ self._test_list_ports(format='json')
1238+
1239+ def test_list_port_details_xml(self):
1240+ self._test_list_ports(format='xml')
1241+
1242+ def test_list_port_details_alt_tenant(self):
1243+ self._test_list_ports(tenant=TENANT_2)
1244+
1245+ def test_list_port_details_error_470(self):
1246+ self._test_list_port_details(status=470)
1247+
1248+ def test_list_port_details_error_401(self):
1249+ self._test_list_ports(status=401)
1250+
1251+ def test_list_port_details_error_420(self):
1252+ self._test_list_ports(status=420)
1253+
1254+ def test_list_port_details_error_430(self):
1255+ self._test_list_ports(status=430)
1256+
1257+
1258+
1259+ def test_create_port_json(self):
1260+ self._test_create_port(format='json')
1261+
1262+ def test_create_port_xml(self):
1263+ self._test_create_port(format='xml')
1264+
1265+ def test_create_port_alt_tenant(self):
1266+ self._test_create_port(tenant=TENANT_2)
1267+
1268+ def test_create_port_error_470(self):
1269+ self._test_create_port(status=470)
1270+
1271+ def test_create_port_error_401(self):
1272+ self._test_create_port(status=401)
1273+
1274+ def test_create_port_error_400(self):
1275+ self._test_create_port(status=400)
1276+
1277+ def test_create_port_error_420(self):
1278+ self._test_create_port(status=420)
1279+
1280+ def test_create_port_error_430(self):
1281+ self._test_create_port(status=430)
1282+
1283+ def test_create_port_error_431(self):
1284+ self._test_create_port(status=431)
1285+
1286+
1287+
1288+ def test_delete_port_json(self):
1289+ self._test_delete_port(format='json')
1290+
1291+ def test_delete_port_xml(self):
1292+ self._test_delete_port(format='xml')
1293+
1294+ def test_delete_port_alt_tenant(self):
1295+ self._test_delete_port(tenant=TENANT_2)
1296+
1297+ def test_delete_port_error_470(self):
1298+ self._test_delete_port(status=470)
1299+
1300+ def test_delete_port_error_401(self):
1301+ self._test_delete_port(status=401)
1302+
1303+ def test_delete_port_error_420(self):
1304+ self._test_delete_port(status=420)
1305+
1306+ def test_delete_port_error_430(self):
1307+ self._test_delete_port(status=430)
1308+
1309+ def test_delete_port_error_432(self):
1310+ self._test_delete_port(status=432)
1311+
1312+
1313+
1314+ def test_set_port_state_json(self):
1315+ self._test_set_port_state(format='json')
1316+
1317+ def test_set_port_state_xml(self):
1318+ self._test_set_port_state(format='xml')
1319+
1320+ def test_set_port_state_alt_tenant(self):
1321+ self._test_set_port_state(tenant=TENANT_2)
1322+
1323+ def test_set_port_state_error_470(self):
1324+ self._test_set_port_state(status=470)
1325+
1326+ def test_set_port_state_error_401(self):
1327+ self._test_set_port_state(status=401)
1328+
1329+ def test_set_port_state_error_400(self):
1330+ self._test_set_port_state(status=400)
1331+
1332+ def test_set_port_state_error_420(self):
1333+ self._test_set_port_state(status=420)
1334+
1335+ def test_set_port_state_error_430(self):
1336+ self._test_set_port_state(status=430)
1337+
1338+ def test_set_port_state_error_431(self):
1339+ self._test_set_port_state(status=431)
1340+
1341+
1342+
1343+ def test_list_port_attachments_json(self):
1344+ self._test_list_port_attachments(format='json')
1345+
1346+ def test_list_port_attachments_xml(self):
1347+ self._test_list_port_attachments(format='xml')
1348+
1349+ def test_list_port_attachments_alt_tenant(self):
1350+ self._test_list_port_attachments(tenant=TENANT_2)
1351+
1352+ def test_list_port_attachments_error_470(self):
1353+ self._test_list_port_attachments(status=470)
1354+
1355+ def test_list_port_attachments_error_401(self):
1356+ self._test_list_port_attachments(status=401)
1357+
1358+ def test_list_port_attachments_error_400(self):
1359+ self._test_list_port_attachments(status=400)
1360+
1361+ def test_list_port_attachments_error_420(self):
1362+ self._test_list_port_attachments(status=420)
1363+
1364+ def test_list_port_attachments_error_430(self):
1365+ self._test_list_port_attachments(status=430)
1366+
1367+
1368+
1369+ def test_attach_resource_json(self):
1370+ self._test_attach_resource(format='json')
1371+
1372+ def test_attach_resource_xml(self):
1373+ self._test_attach_resource(format='xml')
1374+
1375+ def test_attach_resource_alt_tenant(self):
1376+ self._test_attach_resource(tenant=TENANT_2)
1377+
1378+ def test_attach_resource_error_470(self):
1379+ self._test_attach_resource(status=470)
1380+
1381+ def test_attach_resource_error_401(self):
1382+ self._test_attach_resource(status=401)
1383+
1384+ def test_attach_resource_error_400(self):
1385+ self._test_attach_resource(status=400)
1386+
1387+ def test_attach_resource_error_420(self):
1388+ self._test_attach_resource(status=420)
1389+
1390+ def test_attach_resource_error_430(self):
1391+ self._test_attach_resource(status=430)
1392+
1393+ def test_attach_resource_error_432(self):
1394+ self._test_attach_resource(status=432)
1395+
1396+ def test_attach_resource_error_440(self):
1397+ self._test_attach_resource(status=440)
1398+
1399+
1400+
1401+ def test_detach_resource_json(self):
1402+ self._test_detach_resource(format='json')
1403+
1404+ def test_detach_resource_xml(self):
1405+ self._test_detach_resource(format='xml')
1406+
1407+ def test_detach_resource_alt_tenant(self):
1408+ self._test_detach_resource(tenant=TENANT_2)
1409+
1410+ def test_detach_resource_error_470(self):
1411+ self._test_detach_resource(status=470)
1412+
1413+ def test_detach_resource_error_401(self):
1414+ self._test_detach_resource(status=401)
1415+
1416+ def test_detach_resource_error_420(self):
1417+ self._test_detach_resource(status=420)
1418+
1419+ def test_detach_resource_error_430(self):
1420+ self._test_detach_resource(status=430)
1421+
1422
1423=== added file 'tests/unit/test_api.py'
1424--- tests/unit/test_api.py 1970-01-01 00:00:00 +0000
1425+++ tests/unit/test_api.py 2011-07-23 18:23:02 +0000
1426@@ -0,0 +1,831 @@
1427+# vim: tabstop=4 shiftwidth=4 softtabstop=4
1428+
1429+# Copyright 2010-2011 ????
1430+# All Rights Reserved.
1431+#
1432+# Licensed under the Apache License, Version 2.0 (the "License"); you may
1433+# not use this file except in compliance with the License. You may obtain
1434+# a copy of the License at
1435+#
1436+# http://www.apache.org/licenses/LICENSE-2.0
1437+#
1438+# Unless required by applicable law or agreed to in writing, software
1439+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1440+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1441+# License for the specific language governing permissions and limitations
1442+# under the License.
1443+# @author: Brad Hall, Nicira Networks
1444+# @author: Salvatore Orlando, Citrix Systems
1445+
1446+import logging
1447+import unittest
1448+
1449+import tests.unit.testlib_api as testlib
1450+
1451+from quantum import api as server
1452+from quantum.db import api as db
1453+from quantum.common.wsgi import Serializer
1454+
1455+
1456+LOG = logging.getLogger('quantum.tests.test_api')
1457+
1458+
1459+class APITest(unittest.TestCase):
1460+
1461+ def _create_network(self, format, name=None, custom_req_body=None,
1462+ expected_res_status=200):
1463+ LOG.debug("Creating network")
1464+ content_type = "application/" + format
1465+ if name:
1466+ net_name = name
1467+ else:
1468+ net_name = self.network_name
1469+ network_req = testlib.new_network_request(self.tenant_id,
1470+ net_name, format,
1471+ custom_req_body)
1472+ network_res = network_req.get_response(self.api)
1473+ self.assertEqual(network_res.status_int, expected_res_status)
1474+ if expected_res_status == 200:
1475+ network_data = Serializer().deserialize(network_res.body,
1476+ content_type)
1477+ return network_data['networks']['network']['id']
1478+
1479+ def _create_port(self, network_id, port_state, format,
1480+ custom_req_body=None, expected_res_status=200):
1481+ LOG.debug("Creating port for network %s", network_id)
1482+ content_type = "application/%s" % format
1483+ port_req = testlib.new_port_request(self.tenant_id, network_id,
1484+ port_state, format,
1485+ custom_req_body)
1486+ port_res = port_req.get_response(self.api)
1487+ self.assertEqual(port_res.status_int, expected_res_status)
1488+ if expected_res_status == 200:
1489+ port_data = Serializer().deserialize(port_res.body, content_type)
1490+ return port_data['ports']['port']['id']
1491+
1492+ def _test_create_network(self, format):
1493+ LOG.debug("_test_create_network - format:%s - START", format)
1494+ content_type = "application/%s" % format
1495+ network_id = self._create_network(format)
1496+ show_network_req = testlib.show_network_request(self.tenant_id,
1497+ network_id,
1498+ format)
1499+ show_network_res = show_network_req.get_response(self.api)
1500+ self.assertEqual(show_network_res.status_int, 200)
1501+ network_data = Serializer().deserialize(show_network_res.body,
1502+ content_type)
1503+ self.assertEqual(network_id,
1504+ network_data['networks']['network']['id'])
1505+ LOG.debug("_test_create_network - format:%s - END", format)
1506+
1507+ def _test_create_network_badrequest(self, format):
1508+ LOG.debug("_test_create_network_badrequest - format:%s - START",
1509+ format)
1510+ bad_body = {'network': {'bad-attribute': 'very-bad'}}
1511+ self._create_network(format, custom_req_body=bad_body,
1512+ expected_res_status=400)
1513+ LOG.debug("_test_create_network_badrequest - format:%s - END",
1514+ format)
1515+
1516+ def _test_list_networks(self, format):
1517+ LOG.debug("_test_list_networks - format:%s - START", format)
1518+ content_type = "application/%s" % format
1519+ self._create_network(format, "net_1")
1520+ self._create_network(format, "net_2")
1521+ list_network_req = testlib.network_list_request(self.tenant_id,
1522+ format)
1523+ list_network_res = list_network_req.get_response(self.api)
1524+ self.assertEqual(list_network_res.status_int, 200)
1525+ network_data = Serializer().deserialize(list_network_res.body,
1526+ content_type)
1527+ # Check network count: should return 2
1528+ self.assertEqual(len(network_data['networks']), 2)
1529+ LOG.debug("_test_list_networks - format:%s - END", format)
1530+
1531+ def _test_show_network(self, format):
1532+ LOG.debug("_test_show_network - format:%s - START", format)
1533+ content_type = "application/%s" % format
1534+ network_id = self._create_network(format)
1535+ show_network_req = testlib.show_network_request(self.tenant_id,
1536+ network_id,
1537+ format)
1538+ show_network_res = show_network_req.get_response(self.api)
1539+ self.assertEqual(show_network_res.status_int, 200)
1540+ network_data = Serializer().deserialize(show_network_res.body,
1541+ content_type)
1542+ self.assertEqual({'id': network_id, 'name': self.network_name},
1543+ network_data['networks']['network'])
1544+ LOG.debug("_test_show_network - format:%s - END", format)
1545+
1546+ def _test_show_network_not_found(self, format):
1547+ LOG.debug("_test_show_network_not_found - format:%s - START", format)
1548+ show_network_req = testlib.show_network_request(self.tenant_id,
1549+ "A_BAD_ID",
1550+ format)
1551+ show_network_res = show_network_req.get_response(self.api)
1552+ self.assertEqual(show_network_res.status_int, 420)
1553+ LOG.debug("_test_show_network_not_found - format:%s - END", format)
1554+
1555+ def _test_rename_network(self, format):
1556+ LOG.debug("_test_rename_network - format:%s - START", format)
1557+ content_type = "application/%s" % format
1558+ new_name = 'new_network_name'
1559+ network_id = self._create_network(format)
1560+ update_network_req = testlib.update_network_request(self.tenant_id,
1561+ network_id,
1562+ new_name,
1563+ format)
1564+ update_network_res = update_network_req.get_response(self.api)
1565+ self.assertEqual(update_network_res.status_int, 202)
1566+ show_network_req = testlib.show_network_request(self.tenant_id,
1567+ network_id,
1568+ format)
1569+ show_network_res = show_network_req.get_response(self.api)
1570+ self.assertEqual(show_network_res.status_int, 200)
1571+ network_data = Serializer().deserialize(show_network_res.body,
1572+ content_type)
1573+ self.assertEqual({'id': network_id, 'name': new_name},
1574+ network_data['networks']['network'])
1575+ LOG.debug("_test_rename_network - format:%s - END", format)
1576+
1577+ def _test_rename_network_badrequest(self, format):
1578+ LOG.debug("_test_rename_network_badrequest - format:%s - START",
1579+ format)
1580+ network_id = self._create_network(format)
1581+ bad_body = {'network': {'bad-attribute': 'very-bad'}}
1582+ update_network_req = testlib.\
1583+ update_network_request(self.tenant_id,
1584+ network_id, format,
1585+ custom_req_body=bad_body)
1586+ update_network_res = update_network_req.get_response(self.api)
1587+ self.assertEqual(update_network_res.status_int, 400)
1588+ LOG.debug("_test_rename_network_badrequest - format:%s - END",
1589+ format)
1590+
1591+ def _test_rename_network_not_found(self, format):
1592+ LOG.debug("_test_rename_network_not_found - format:%s - START",
1593+ format)
1594+ new_name = 'new_network_name'
1595+ update_network_req = testlib.update_network_request(self.tenant_id,
1596+ "A BAD ID",
1597+ new_name,
1598+ format)
1599+ update_network_res = update_network_req.get_response(self.api)
1600+ self.assertEqual(update_network_res.status_int, 420)
1601+ LOG.debug("_test_rename_network_not_found - format:%s - END",
1602+ format)
1603+
1604+ def _test_delete_network(self, format):
1605+ LOG.debug("_test_delete_network - format:%s - START", format)
1606+ content_type = "application/%s" % format
1607+ network_id = self._create_network(format)
1608+ LOG.debug("Deleting network %(network_id)s"\
1609+ " of tenant %(tenant_id)s", locals())
1610+ delete_network_req = testlib.network_delete_request(self.tenant_id,
1611+ network_id,
1612+ format)
1613+ delete_network_res = delete_network_req.get_response(self.api)
1614+ self.assertEqual(delete_network_res.status_int, 202)
1615+ list_network_req = testlib.network_list_request(self.tenant_id,
1616+ format)
1617+ list_network_res = list_network_req.get_response(self.api)
1618+ network_list_data = Serializer().deserialize(list_network_res.body,
1619+ content_type)
1620+ network_count = len(network_list_data['networks'])
1621+ self.assertEqual(network_count, 0)
1622+ LOG.debug("_test_delete_network - format:%s - END", format)
1623+
1624+ def _test_delete_network_in_use(self, format):
1625+ LOG.debug("_test_delete_network_in_use - format:%s - START", format)
1626+ content_type = "application/%s" % format
1627+ port_state = "ACTIVE"
1628+ attachment_id = "test_attachment"
1629+ network_id = self._create_network(format)
1630+ LOG.debug("Deleting network %(network_id)s"\
1631+ " of tenant %(tenant_id)s", locals())
1632+ port_id = self._create_port(network_id, port_state, format)
1633+ #plug an attachment into the port
1634+ LOG.debug("Putting attachment into port %s", port_id)
1635+ attachment_req = testlib.put_attachment_request(self.tenant_id,
1636+ network_id,
1637+ port_id,
1638+ attachment_id)
1639+ attachment_res = attachment_req.get_response(self.api)
1640+ self.assertEquals(attachment_res.status_int, 202)
1641+
1642+ LOG.debug("Deleting network %(network_id)s"\
1643+ " of tenant %(tenant_id)s", locals())
1644+ delete_network_req = testlib.network_delete_request(self.tenant_id,
1645+ network_id,
1646+ format)
1647+ delete_network_res = delete_network_req.get_response(self.api)
1648+ self.assertEqual(delete_network_res.status_int, 421)
1649+ LOG.debug("_test_delete_network_in_use - format:%s - END", format)
1650+
1651+ def _test_list_ports(self, format):
1652+ LOG.debug("_test_list_ports - format:%s - START", format)
1653+ content_type = "application/%s" % format
1654+ port_state = "ACTIVE"
1655+ network_id = self._create_network(format)
1656+ self._create_port(network_id, port_state, format)
1657+ self._create_port(network_id, port_state, format)
1658+ list_port_req = testlib.port_list_request(self.tenant_id,
1659+ network_id, format)
1660+ list_port_res = list_port_req.get_response(self.api)
1661+ self.assertEqual(list_port_res.status_int, 200)
1662+ port_data = Serializer().deserialize(list_port_res.body,
1663+ content_type)
1664+ # Check port count: should return 2
1665+ self.assertEqual(len(port_data['ports']), 2)
1666+ LOG.debug("_test_list_ports - format:%s - END", format)
1667+
1668+ def _test_show_port(self, format):
1669+ LOG.debug("_test_show_port - format:%s - START", format)
1670+ content_type = "application/%s" % format
1671+ port_state = "ACTIVE"
1672+ network_id = self._create_network(format)
1673+ port_id = self._create_port(network_id, port_state, format)
1674+ show_port_req = testlib.show_port_request(self.tenant_id,
1675+ network_id, port_id,
1676+ format)
1677+ show_port_res = show_port_req.get_response(self.api)
1678+ self.assertEqual(show_port_res.status_int, 200)
1679+ port_data = Serializer().deserialize(show_port_res.body,
1680+ content_type)
1681+ self.assertEqual({'id': port_id, 'state': port_state},
1682+ port_data['ports']['port'])
1683+ LOG.debug("_test_show_port - format:%s - END", format)
1684+
1685+ def _test_show_port_networknotfound(self, format):
1686+ LOG.debug("_test_show_port_networknotfound - format:%s - START",
1687+ format)
1688+ port_state = "ACTIVE"
1689+ network_id = self._create_network(format)
1690+ port_id = self._create_port(network_id, port_state, format)
1691+ show_port_req = testlib.show_port_request(self.tenant_id,
1692+ "A_BAD_ID", port_id,
1693+ format)
1694+ show_port_res = show_port_req.get_response(self.api)
1695+ self.assertEqual(show_port_res.status_int, 420)
1696+ LOG.debug("_test_show_port_networknotfound - format:%s - END",
1697+ format)
1698+
1699+ def _test_show_port_portnotfound(self, format):
1700+ LOG.debug("_test_show_port_portnotfound - format:%s - START", format)
1701+ network_id = self._create_network(format)
1702+ show_port_req = testlib.show_port_request(self.tenant_id,
1703+ network_id,
1704+ "A_BAD_ID",
1705+ format)
1706+ show_port_res = show_port_req.get_response(self.api)
1707+ self.assertEqual(show_port_res.status_int, 430)
1708+ LOG.debug("_test_show_port_portnotfound - format:%s - END", format)
1709+
1710+ def _test_create_port(self, format):
1711+ LOG.debug("_test_create_port - format:%s - START", format)
1712+ content_type = "application/%s" % format
1713+ port_state = "ACTIVE"
1714+ network_id = self._create_network(format)
1715+ port_id = self._create_port(network_id, port_state, format)
1716+ show_port_req = testlib.show_port_request(self.tenant_id,
1717+ network_id, port_id, format)
1718+ show_port_res = show_port_req.get_response(self.api)
1719+ self.assertEqual(show_port_res.status_int, 200)
1720+ port_data = Serializer().deserialize(show_port_res.body, content_type)
1721+ self.assertEqual(port_id, port_data['ports']['port']['id'])
1722+ LOG.debug("_test_create_port - format:%s - END", format)
1723+
1724+ def _test_create_port_networknotfound(self, format):
1725+ LOG.debug("_test_create_port_networknotfound - format:%s - START",
1726+ format)
1727+ port_state = "ACTIVE"
1728+ self._create_port("A_BAD_ID", port_state, format,
1729+ expected_res_status=420)
1730+ LOG.debug("_test_create_port_networknotfound - format:%s - END",
1731+ format)
1732+
1733+ def _test_create_port_badrequest(self, format):
1734+ LOG.debug("_test_create_port_badrequest - format:%s - START", format)
1735+ bad_body = {'bad-resource': {'bad-attribute': 'bad-value'}}
1736+ network_id = self._create_network(format)
1737+ port_state = "ACTIVE"
1738+ self._create_port(network_id, port_state, format,
1739+ custom_req_body=bad_body, expected_res_status=400)
1740+ LOG.debug("_test_create_port_badrequest - format:%s - END", format)
1741+
1742+ def _test_delete_port(self, format):
1743+ LOG.debug("_test_delete_port - format:%s - START", format)
1744+ content_type = "application/%s" % format
1745+ port_state = "ACTIVE"
1746+ network_id = self._create_network(format)
1747+ port_id = self._create_port(network_id, port_state, format)
1748+ LOG.debug("Deleting port %(port_id)s for network %(network_id)s"\
1749+ " of tenant %(tenant_id)s", locals())
1750+ delete_port_req = testlib.port_delete_request(self.tenant_id,
1751+ network_id, port_id,
1752+ format)
1753+ delete_port_res = delete_port_req.get_response(self.api)
1754+ self.assertEqual(delete_port_res.status_int, 202)
1755+ list_port_req = testlib.port_list_request(self.tenant_id, network_id,
1756+ format)
1757+ list_port_res = list_port_req.get_response(self.api)
1758+ port_list_data = Serializer().deserialize(list_port_res.body,
1759+ content_type)
1760+ port_count = len(port_list_data['ports'])
1761+ self.assertEqual(port_count, 0)
1762+ LOG.debug("_test_delete_port - format:%s - END", format)
1763+
1764+ def _test_delete_port_in_use(self, format):
1765+ LOG.debug("_test_delete_port_in_use - format:%s - START", format)
1766+ content_type = "application/" + format
1767+ port_state = "ACTIVE"
1768+ attachment_id = "test_attachment"
1769+ network_id = self._create_network(format)
1770+ port_id = self._create_port(network_id, port_state, format)
1771+ #plug an attachment into the port
1772+ LOG.debug("Putting attachment into port %s", port_id)
1773+ attachment_req = testlib.put_attachment_request(self.tenant_id,
1774+ network_id,
1775+ port_id,
1776+ attachment_id)
1777+ attachment_res = attachment_req.get_response(self.api)
1778+ self.assertEquals(attachment_res.status_int, 202)
1779+ LOG.debug("Deleting port %(port_id)s for network %(network_id)s"\
1780+ " of tenant %(tenant_id)s", locals())
1781+ delete_port_req = testlib.port_delete_request(self.tenant_id,
1782+ network_id, port_id,
1783+ format)
1784+ delete_port_res = delete_port_req.get_response(self.api)
1785+ self.assertEqual(delete_port_res.status_int, 432)
1786+ LOG.debug("_test_delete_port_in_use - format:%s - END", format)
1787+
1788+ def _test_delete_port_with_bad_id(self, format):
1789+ LOG.debug("_test_delete_port_with_bad_id - format:%s - START",
1790+ format)
1791+ port_state = "ACTIVE"
1792+ network_id = self._create_network(format)
1793+ self._create_port(network_id, port_state, format)
1794+ # Test for portnotfound
1795+ delete_port_req = testlib.port_delete_request(self.tenant_id,
1796+ network_id, "A_BAD_ID",
1797+ format)
1798+ delete_port_res = delete_port_req.get_response(self.api)
1799+ self.assertEqual(delete_port_res.status_int, 430)
1800+ LOG.debug("_test_delete_port_with_bad_id - format:%s - END", format)
1801+
1802+ def _test_delete_port_networknotfound(self, format):
1803+ LOG.debug("_test_delete_port_networknotfound - format:%s - START",
1804+ format)
1805+ port_state = "ACTIVE"
1806+ network_id = self._create_network(format)
1807+ port_id = self._create_port(network_id, port_state, format)
1808+ delete_port_req = testlib.port_delete_request(self.tenant_id,
1809+ "A_BAD_ID", port_id,
1810+ format)
1811+ delete_port_res = delete_port_req.get_response(self.api)
1812+ self.assertEqual(delete_port_res.status_int, 420)
1813+ LOG.debug("_test_delete_port_networknotfound - format:%s - END",
1814+ format)
1815+
1816+ def _test_set_port_state(self, format):
1817+ LOG.debug("_test_set_port_state - format:%s - START", format)
1818+ content_type = "application/%s" % format
1819+ port_state = 'DOWN'
1820+ new_port_state = 'ACTIVE'
1821+ network_id = self._create_network(format)
1822+ port_id = self._create_port(network_id, port_state, format)
1823+ update_port_req = testlib.update_port_request(self.tenant_id,
1824+ network_id, port_id,
1825+ new_port_state,
1826+ format)
1827+ update_port_res = update_port_req.get_response(self.api)
1828+ self.assertEqual(update_port_res.status_int, 200)
1829+ show_port_req = testlib.show_port_request(self.tenant_id,
1830+ network_id, port_id,
1831+ format)
1832+ show_port_res = show_port_req.get_response(self.api)
1833+ self.assertEqual(show_port_res.status_int, 200)
1834+ network_data = Serializer().deserialize(show_port_res.body,
1835+ content_type)
1836+ self.assertEqual({'id': port_id, 'state': new_port_state},
1837+ network_data['ports']['port'])
1838+ LOG.debug("_test_set_port_state - format:%s - END", format)
1839+
1840+ def _test_set_port_state_networknotfound(self, format):
1841+ LOG.debug("_test_set_port_state_networknotfound - format:%s - START",
1842+ format)
1843+ port_state = 'DOWN'
1844+ new_port_state = 'ACTIVE'
1845+ network_id = self._create_network(format)
1846+ port_id = self._create_port(network_id, port_state, format)
1847+ update_port_req = testlib.update_port_request(self.tenant_id,
1848+ "A_BAD_ID", port_id,
1849+ new_port_state,
1850+ format)
1851+ update_port_res = update_port_req.get_response(self.api)
1852+ self.assertEqual(update_port_res.status_int, 420)
1853+ LOG.debug("_test_set_port_state_networknotfound - format:%s - END",
1854+ format)
1855+
1856+ def _test_set_port_state_portnotfound(self, format):
1857+ LOG.debug("_test_set_port_state_portnotfound - format:%s - START",
1858+ format)
1859+ port_state = 'DOWN'
1860+ new_port_state = 'ACTIVE'
1861+ network_id = self._create_network(format)
1862+ self._create_port(network_id, port_state, format)
1863+ update_port_req = testlib.update_port_request(self.tenant_id,
1864+ network_id,
1865+ "A_BAD_ID",
1866+ new_port_state,
1867+ format)
1868+ update_port_res = update_port_req.get_response(self.api)
1869+ self.assertEqual(update_port_res.status_int, 430)
1870+ LOG.debug("_test_set_port_state_portnotfound - format:%s - END",
1871+ format)
1872+
1873+ def _test_set_port_state_stateinvalid(self, format):
1874+ LOG.debug("_test_set_port_state_stateinvalid - format:%s - START",
1875+ format)
1876+ port_state = 'DOWN'
1877+ new_port_state = 'A_BAD_STATE'
1878+ network_id = self._create_network(format)
1879+ port_id = self._create_port(network_id, port_state, format)
1880+ update_port_req = testlib.update_port_request(self.tenant_id,
1881+ network_id, port_id,
1882+ new_port_state,
1883+ format)
1884+ update_port_res = update_port_req.get_response(self.api)
1885+ self.assertEqual(update_port_res.status_int, 431)
1886+ LOG.debug("_test_set_port_state_stateinvalid - format:%s - END",
1887+ format)
1888+
1889+ def _test_show_attachment(self, format):
1890+ LOG.debug("_test_show_attachment - format:%s - START", format)
1891+ content_type = "application/%s" % format
1892+ port_state = "ACTIVE"
1893+ network_id = self._create_network(format)
1894+ interface_id = "test_interface"
1895+ port_id = self._create_port(network_id, port_state, format)
1896+ put_attachment_req = testlib.put_attachment_request(self.tenant_id,
1897+ network_id,
1898+ port_id,
1899+ interface_id,
1900+ format)
1901+ put_attachment_res = put_attachment_req.get_response(self.api)
1902+ self.assertEqual(put_attachment_res.status_int, 202)
1903+ get_attachment_req = testlib.get_attachment_request(self.tenant_id,
1904+ network_id,
1905+ port_id,
1906+ format)
1907+ get_attachment_res = get_attachment_req.get_response(self.api)
1908+ attachment_data = Serializer().deserialize(get_attachment_res.body,
1909+ content_type)
1910+ self.assertEqual(attachment_data['attachment'], interface_id)
1911+ LOG.debug("_test_show_attachment - format:%s - END", format)
1912+
1913+ def _test_show_attachment_networknotfound(self, format):
1914+ LOG.debug("_test_show_attachment_networknotfound - format:%s - START",
1915+ format)
1916+ port_state = "ACTIVE"
1917+ network_id = self._create_network(format)
1918+ port_id = self._create_port(network_id, port_state, format)
1919+ get_attachment_req = testlib.get_attachment_request(self.tenant_id,
1920+ "A_BAD_ID",
1921+ port_id,
1922+ format)
1923+ get_attachment_res = get_attachment_req.get_response(self.api)
1924+ self.assertEqual(get_attachment_res.status_int, 420)
1925+ LOG.debug("_test_show_attachment_networknotfound - format:%s - END",
1926+ format)
1927+
1928+ def _test_show_attachment_portnotfound(self, format):
1929+ LOG.debug("_test_show_attachment_portnotfound - format:%s - START",
1930+ format)
1931+ port_state = "ACTIVE"
1932+ network_id = self._create_network(format)
1933+ self._create_port(network_id, port_state, format)
1934+ get_attachment_req = testlib.get_attachment_request(self.tenant_id,
1935+ network_id,
1936+ "A_BAD_ID",
1937+ format)
1938+ get_attachment_res = get_attachment_req.get_response(self.api)
1939+ self.assertEqual(get_attachment_res.status_int, 430)
1940+ LOG.debug("_test_show_attachment_portnotfound - format:%s - END",
1941+ format)
1942+
1943+ def _test_put_attachment(self, format):
1944+ LOG.debug("_test_put_attachment - format:%s - START", format)
1945+ port_state = "ACTIVE"
1946+ network_id = self._create_network(format)
1947+ interface_id = "test_interface"
1948+ port_id = self._create_port(network_id, port_state, format)
1949+ put_attachment_req = testlib.put_attachment_request(self.tenant_id,
1950+ network_id,
1951+ port_id,
1952+ interface_id,
1953+ format)
1954+ put_attachment_res = put_attachment_req.get_response(self.api)
1955+ self.assertEqual(put_attachment_res.status_int, 202)
1956+ LOG.debug("_test_put_attachment - format:%s - END", format)
1957+
1958+ def _test_put_attachment_networknotfound(self, format):
1959+ LOG.debug("_test_put_attachment_networknotfound - format:%s - START",
1960+ format)
1961+ port_state = 'DOWN'
1962+ interface_id = "test_interface"
1963+ network_id = self._create_network(format)
1964+ port_id = self._create_port(network_id, port_state, format)
1965+ put_attachment_req = testlib.put_attachment_request(self.tenant_id,
1966+ "A_BAD_ID",
1967+ port_id,
1968+ interface_id,
1969+ format)
1970+ put_attachment_res = put_attachment_req.get_response(self.api)
1971+ self.assertEqual(put_attachment_res.status_int, 420)
1972+ LOG.debug("_test_put_attachment_networknotfound - format:%s - END",
1973+ format)
1974+
1975+ def _test_put_attachment_portnotfound(self, format):
1976+ LOG.debug("_test_put_attachment_portnotfound - format:%s - START",
1977+ format)
1978+ port_state = 'DOWN'
1979+ interface_id = "test_interface"
1980+ network_id = self._create_network(format)
1981+ self._create_port(network_id, port_state, format)
1982+ put_attachment_req = testlib.put_attachment_request(self.tenant_id,
1983+ network_id,
1984+ "A_BAD_ID",
1985+ interface_id,
1986+ format)
1987+ put_attachment_res = put_attachment_req.get_response(self.api)
1988+ self.assertEqual(put_attachment_res.status_int, 430)
1989+ LOG.debug("_test_put_attachment_portnotfound - format:%s - END",
1990+ format)
1991+
1992+ def _test_delete_attachment(self, format):
1993+ LOG.debug("_test_delete_attachment - format:%s - START", format)
1994+ port_state = "ACTIVE"
1995+ network_id = self._create_network(format)
1996+ interface_id = "test_interface"
1997+ port_id = self._create_port(network_id, port_state, format)
1998+ put_attachment_req = testlib.put_attachment_request(self.tenant_id,
1999+ network_id,
2000+ port_id,
2001+ interface_id,
2002+ format)
2003+ put_attachment_res = put_attachment_req.get_response(self.api)
2004+ self.assertEqual(put_attachment_res.status_int, 202)
2005+ del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
2006+ network_id,
2007+ port_id,
2008+ format)
2009+ del_attachment_res = del_attachment_req.get_response(self.api)
2010+ self.assertEqual(del_attachment_res.status_int, 202)
2011+ LOG.debug("_test_delete_attachment - format:%s - END", format)
2012+
2013+ def _test_delete_attachment_networknotfound(self, format):
2014+ LOG.debug("_test_delete_attachment_networknotfound -" \
2015+ " format:%s - START", format)
2016+ port_state = "ACTIVE"
2017+ network_id = self._create_network(format)
2018+ port_id = self._create_port(network_id, port_state, format)
2019+ del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
2020+ "A_BAD_ID",
2021+ port_id,
2022+ format)
2023+ del_attachment_res = del_attachment_req.get_response(self.api)
2024+ self.assertEqual(del_attachment_res.status_int, 420)
2025+ LOG.debug("_test_delete_attachment_networknotfound -" \
2026+ " format:%s - END", format)
2027+
2028+ def _test_delete_attachment_portnotfound(self, format):
2029+ LOG.debug("_test_delete_attachment_portnotfound - " \
2030+ " format:%s - START", format)
2031+ port_state = "ACTIVE"
2032+ network_id = self._create_network(format)
2033+ self._create_port(network_id, port_state, format)
2034+ del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
2035+ network_id,
2036+ "A_BAD_ID",
2037+ format)
2038+ del_attachment_res = del_attachment_req.get_response(self.api)
2039+ self.assertEqual(del_attachment_res.status_int, 430)
2040+ LOG.debug("_test_delete_attachment_portnotfound - " \
2041+ "format:%s - END", format)
2042+
2043+ def setUp(self):
2044+ options = {}
2045+ options['plugin_provider'] = 'quantum.plugins.SamplePlugin.FakePlugin'
2046+ self.api = server.APIRouterV01(options)
2047+ self.tenant_id = "test_tenant"
2048+ self.network_name = "test_network"
2049+
2050+ def tearDown(self):
2051+ """Clear the test environment"""
2052+ # Remove database contents
2053+ db.clear_db()
2054+
2055+ def test_list_networks_json(self):
2056+ self._test_list_networks('json')
2057+
2058+ def test_list_networks_xml(self):
2059+ self._test_list_networks('xml')
2060+
2061+ def test_create_network_json(self):
2062+ self._test_create_network('json')
2063+
2064+ def test_create_network_xml(self):
2065+ self._test_create_network('xml')
2066+
2067+ def test_create_network_badrequest_json(self):
2068+ self._test_create_network_badrequest('json')
2069+
2070+ def test_create_network_badreqyest_xml(self):
2071+ self._test_create_network_badrequest('xml')
2072+
2073+ def test_show_network_not_found_json(self):
2074+ self._test_show_network_not_found('json')
2075+
2076+ def test_show_network_not_found_xml(self):
2077+ self._test_show_network_not_found('xml')
2078+
2079+ def test_show_network_json(self):
2080+ self._test_show_network('json')
2081+
2082+ def test_show_network_xml(self):
2083+ self._test_show_network('xml')
2084+
2085+ def test_delete_network_json(self):
2086+ self._test_delete_network('json')
2087+
2088+ def test_delete_network_xml(self):
2089+ self._test_delete_network('xml')
2090+
2091+ def test_rename_network_json(self):
2092+ self._test_rename_network('json')
2093+
2094+ def test_rename_network_xml(self):
2095+ self._test_rename_network('xml')
2096+
2097+ def test_rename_network_badrequest_json(self):
2098+ self._test_rename_network_badrequest('json')
2099+
2100+ def test_rename_network_badrequest_xml(self):
2101+ self._test_rename_network_badrequest('xml')
2102+
2103+ def test_rename_network_not_found_json(self):
2104+ self._test_rename_network_not_found('json')
2105+
2106+ def test_rename_network_not_found_xml(self):
2107+ self._test_rename_network_not_found('xml')
2108+
2109+ def test_delete_network_in_use_json(self):
2110+ self._test_delete_network_in_use('json')
2111+
2112+ def test_delete_network_in_use_xml(self):
2113+ self._test_delete_network_in_use('xml')
2114+
2115+ def test_list_ports_json(self):
2116+ self._test_list_ports('json')
2117+
2118+ def test_list_ports_xml(self):
2119+ self._test_list_ports('xml')
2120+
2121+ def test_show_port_json(self):
2122+ self._test_show_port('json')
2123+
2124+ def test_show_port_xml(self):
2125+ self._test_show_port('xml')
2126+
2127+ def test_show_port_networknotfound_json(self):
2128+ self._test_show_port_networknotfound('json')
2129+
2130+ def test_show_port_networknotfound_xml(self):
2131+ self._test_show_port_networknotfound('xml')
2132+
2133+ def test_show_port_portnotfound_json(self):
2134+ self._test_show_port_portnotfound('json')
2135+
2136+ def test_show_port_portnotfound_xml(self):
2137+ self._test_show_port_portnotfound('xml')
2138+
2139+ def test_create_port_json(self):
2140+ self._test_create_port('json')
2141+
2142+ def test_create_port_xml(self):
2143+ self._test_create_port('xml')
2144+
2145+ def test_create_port_networknotfound_json(self):
2146+ self._test_create_port_networknotfound('json')
2147+
2148+ def test_create_port_networknotfound_xml(self):
2149+ self._test_create_port_networknotfound('xml')
2150+
2151+ def test_create_port_badrequest_json(self):
2152+ self._test_create_port_badrequest('json')
2153+
2154+ def test_create_port_badrequest_xml(self):
2155+ self._test_create_port_badrequest('xml')
2156+
2157+ def test_delete_port_xml(self):
2158+ self._test_delete_port('xml')
2159+
2160+ def test_delete_port_json(self):
2161+ self._test_delete_port('json')
2162+
2163+ def test_delete_port_in_use_xml(self):
2164+ self._test_delete_port_in_use('xml')
2165+
2166+ def test_delete_port_in_use_json(self):
2167+ self._test_delete_port_in_use('json')
2168+
2169+ def test_delete_port_networknotfound_xml(self):
2170+ self._test_delete_port_networknotfound('xml')
2171+
2172+ def test_delete_port_networknotfound_json(self):
2173+ self._test_delete_port_networknotfound('json')
2174+
2175+ def test_delete_port_with_bad_id_xml(self):
2176+ self._test_delete_port_with_bad_id('xml')
2177+
2178+ def test_delete_port_with_bad_id_json(self):
2179+ self._test_delete_port_with_bad_id('json')
2180+
2181+ def test_set_port_state_xml(self):
2182+ self._test_set_port_state('xml')
2183+
2184+ def test_set_port_state_json(self):
2185+ self._test_set_port_state('json')
2186+
2187+ def test_set_port_state_networknotfound_xml(self):
2188+ self._test_set_port_state_networknotfound('xml')
2189+
2190+ def test_set_port_state_networknotfound_json(self):
2191+ self._test_set_port_state_networknotfound('json')
2192+
2193+ def test_set_port_state_portnotfound_xml(self):
2194+ self._test_set_port_state_portnotfound('xml')
2195+
2196+ def test_set_port_state_portnotfound_json(self):
2197+ self._test_set_port_state_portnotfound('json')
2198+
2199+ def test_set_port_state_stateinvalid_xml(self):
2200+ self._test_set_port_state_stateinvalid('xml')
2201+
2202+ def test_set_port_state_stateinvalid_json(self):
2203+ self._test_set_port_state_stateinvalid('json')
2204+
2205+ def test_show_attachment_xml(self):
2206+ self._test_show_attachment('xml')
2207+
2208+ def test_show_attachment_json(self):
2209+ self._test_show_attachment('json')
2210+
2211+ def test_show_attachment_networknotfound_xml(self):
2212+ self._test_show_attachment_networknotfound('xml')
2213+
2214+ def test_show_attachment_networknotfound_json(self):
2215+ self._test_show_attachment_networknotfound('json')
2216+
2217+ def test_show_attachment_portnotfound_xml(self):
2218+ self._test_show_attachment_portnotfound('xml')
2219+
2220+ def test_show_attachment_portnotfound_json(self):
2221+ self._test_show_attachment_portnotfound('json')
2222+
2223+ def test_put_attachment_xml(self):
2224+ self._test_put_attachment('xml')
2225+
2226+ def test_put_attachment_json(self):
2227+ self._test_put_attachment('json')
2228+
2229+ def test_put_attachment_networknotfound_xml(self):
2230+ self._test_put_attachment_networknotfound('xml')
2231+
2232+ def test_put_attachment_networknotfound_json(self):
2233+ self._test_put_attachment_networknotfound('json')
2234+
2235+ def test_put_attachment_portnotfound_xml(self):
2236+ self._test_put_attachment_portnotfound('xml')
2237+
2238+ def test_put_attachment_portnotfound_json(self):
2239+ self._test_put_attachment_portnotfound('json')
2240+
2241+ def test_delete_attachment_xml(self):
2242+ self._test_delete_attachment('xml')
2243+
2244+ def test_delete_attachment_json(self):
2245+ self._test_delete_attachment('json')
2246+
2247+ def test_delete_attachment_networknotfound_xml(self):
2248+ self._test_delete_attachment_networknotfound('xml')
2249+
2250+ def test_delete_attachment_networknotfound_json(self):
2251+ self._test_delete_attachment_networknotfound('json')
2252+
2253+ def test_delete_attachment_portnotfound_xml(self):
2254+ self._test_delete_attachment_portnotfound('xml')
2255+
2256+ def test_delete_attachment_portnotfound_json(self):
2257+ self._test_delete_attachment_portnotfound('json')
2258
2259=== removed file 'tests/unit/test_api.py'
2260--- tests/unit/test_api.py 2011-07-21 15:34:58 +0000
2261+++ tests/unit/test_api.py 1970-01-01 00:00:00 +0000
2262@@ -1,831 +0,0 @@
2263-# vim: tabstop=4 shiftwidth=4 softtabstop=4
2264-
2265-# Copyright 2010-2011 ????
2266-# All Rights Reserved.
2267-#
2268-# Licensed under the Apache License, Version 2.0 (the "License"); you may
2269-# not use this file except in compliance with the License. You may obtain
2270-# a copy of the License at
2271-#
2272-# http://www.apache.org/licenses/LICENSE-2.0
2273-#
2274-# Unless required by applicable law or agreed to in writing, software
2275-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2276-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2277-# License for the specific language governing permissions and limitations
2278-# under the License.
2279-# @author: Brad Hall, Nicira Networks
2280-# @author: Salvatore Orlando, Citrix Systems
2281-
2282-import logging
2283-import unittest
2284-
2285-import tests.unit.testlib_api as testlib
2286-
2287-from quantum import api as server
2288-from quantum.db import api as db
2289-from quantum.common.wsgi import Serializer
2290-
2291-
2292-LOG = logging.getLogger('quantum.tests.test_api')
2293-
2294-
2295-class APITest(unittest.TestCase):
2296-
2297- def _create_network(self, format, name=None, custom_req_body=None,
2298- expected_res_status=200):
2299- LOG.debug("Creating network")
2300- content_type = "application/" + format
2301- if name:
2302- net_name = name
2303- else:
2304- net_name = self.network_name
2305- network_req = testlib.new_network_request(self.tenant_id,
2306- net_name, format,
2307- custom_req_body)
2308- network_res = network_req.get_response(self.api)
2309- self.assertEqual(network_res.status_int, expected_res_status)
2310- if expected_res_status == 200:
2311- network_data = Serializer().deserialize(network_res.body,
2312- content_type)
2313- return network_data['networks']['network']['id']
2314-
2315- def _create_port(self, network_id, port_state, format,
2316- custom_req_body=None, expected_res_status=200):
2317- LOG.debug("Creating port for network %s", network_id)
2318- content_type = "application/%s" % format
2319- port_req = testlib.new_port_request(self.tenant_id, network_id,
2320- port_state, format,
2321- custom_req_body)
2322- port_res = port_req.get_response(self.api)
2323- self.assertEqual(port_res.status_int, expected_res_status)
2324- if expected_res_status == 200:
2325- port_data = Serializer().deserialize(port_res.body, content_type)
2326- return port_data['ports']['port']['id']
2327-
2328- def _test_create_network(self, format):
2329- LOG.debug("_test_create_network - format:%s - START", format)
2330- content_type = "application/%s" % format
2331- network_id = self._create_network(format)
2332- show_network_req = testlib.show_network_request(self.tenant_id,
2333- network_id,
2334- format)
2335- show_network_res = show_network_req.get_response(self.api)
2336- self.assertEqual(show_network_res.status_int, 200)
2337- network_data = Serializer().deserialize(show_network_res.body,
2338- content_type)
2339- self.assertEqual(network_id,
2340- network_data['networks']['network']['id'])
2341- LOG.debug("_test_create_network - format:%s - END", format)
2342-
2343- def _test_create_network_badrequest(self, format):
2344- LOG.debug("_test_create_network_badrequest - format:%s - START",
2345- format)
2346- bad_body = {'network': {'bad-attribute': 'very-bad'}}
2347- self._create_network(format, custom_req_body=bad_body,
2348- expected_res_status=400)
2349- LOG.debug("_test_create_network_badrequest - format:%s - END",
2350- format)
2351-
2352- def _test_list_networks(self, format):
2353- LOG.debug("_test_list_networks - format:%s - START", format)
2354- content_type = "application/%s" % format
2355- self._create_network(format, "net_1")
2356- self._create_network(format, "net_2")
2357- list_network_req = testlib.network_list_request(self.tenant_id,
2358- format)
2359- list_network_res = list_network_req.get_response(self.api)
2360- self.assertEqual(list_network_res.status_int, 200)
2361- network_data = Serializer().deserialize(list_network_res.body,
2362- content_type)
2363- # Check network count: should return 2
2364- self.assertEqual(len(network_data['networks']), 2)
2365- LOG.debug("_test_list_networks - format:%s - END", format)
2366-
2367- def _test_show_network(self, format):
2368- LOG.debug("_test_show_network - format:%s - START", format)
2369- content_type = "application/%s" % format
2370- network_id = self._create_network(format)
2371- show_network_req = testlib.show_network_request(self.tenant_id,
2372- network_id,
2373- format)
2374- show_network_res = show_network_req.get_response(self.api)
2375- self.assertEqual(show_network_res.status_int, 200)
2376- network_data = Serializer().deserialize(show_network_res.body,
2377- content_type)
2378- self.assertEqual({'id': network_id, 'name': self.network_name},
2379- network_data['networks']['network'])
2380- LOG.debug("_test_show_network - format:%s - END", format)
2381-
2382- def _test_show_network_not_found(self, format):
2383- LOG.debug("_test_show_network_not_found - format:%s - START", format)
2384- show_network_req = testlib.show_network_request(self.tenant_id,
2385- "A_BAD_ID",
2386- format)
2387- show_network_res = show_network_req.get_response(self.api)
2388- self.assertEqual(show_network_res.status_int, 420)
2389- LOG.debug("_test_show_network_not_found - format:%s - END", format)
2390-
2391- def _test_rename_network(self, format):
2392- LOG.debug("_test_rename_network - format:%s - START", format)
2393- content_type = "application/%s" % format
2394- new_name = 'new_network_name'
2395- network_id = self._create_network(format)
2396- update_network_req = testlib.update_network_request(self.tenant_id,
2397- network_id,
2398- new_name,
2399- format)
2400- update_network_res = update_network_req.get_response(self.api)
2401- self.assertEqual(update_network_res.status_int, 202)
2402- show_network_req = testlib.show_network_request(self.tenant_id,
2403- network_id,
2404- format)
2405- show_network_res = show_network_req.get_response(self.api)
2406- self.assertEqual(show_network_res.status_int, 200)
2407- network_data = Serializer().deserialize(show_network_res.body,
2408- content_type)
2409- self.assertEqual({'id': network_id, 'name': new_name},
2410- network_data['networks']['network'])
2411- LOG.debug("_test_rename_network - format:%s - END", format)
2412-
2413- def _test_rename_network_badrequest(self, format):
2414- LOG.debug("_test_rename_network_badrequest - format:%s - START",
2415- format)
2416- network_id = self._create_network(format)
2417- bad_body = {'network': {'bad-attribute': 'very-bad'}}
2418- update_network_req = testlib.\
2419- update_network_request(self.tenant_id,
2420- network_id, format,
2421- custom_req_body=bad_body)
2422- update_network_res = update_network_req.get_response(self.api)
2423- self.assertEqual(update_network_res.status_int, 400)
2424- LOG.debug("_test_rename_network_badrequest - format:%s - END",
2425- format)
2426-
2427- def _test_rename_network_not_found(self, format):
2428- LOG.debug("_test_rename_network_not_found - format:%s - START",
2429- format)
2430- new_name = 'new_network_name'
2431- update_network_req = testlib.update_network_request(self.tenant_id,
2432- "A BAD ID",
2433- new_name,
2434- format)
2435- update_network_res = update_network_req.get_response(self.api)
2436- self.assertEqual(update_network_res.status_int, 420)
2437- LOG.debug("_test_rename_network_not_found - format:%s - END",
2438- format)
2439-
2440- def _test_delete_network(self, format):
2441- LOG.debug("_test_delete_network - format:%s - START", format)
2442- content_type = "application/%s" % format
2443- network_id = self._create_network(format)
2444- LOG.debug("Deleting network %(network_id)s"\
2445- " of tenant %(tenant_id)s", locals())
2446- delete_network_req = testlib.network_delete_request(self.tenant_id,
2447- network_id,
2448- format)
2449- delete_network_res = delete_network_req.get_response(self.api)
2450- self.assertEqual(delete_network_res.status_int, 202)
2451- list_network_req = testlib.network_list_request(self.tenant_id,
2452- format)
2453- list_network_res = list_network_req.get_response(self.api)
2454- network_list_data = Serializer().deserialize(list_network_res.body,
2455- content_type)
2456- network_count = len(network_list_data['networks'])
2457- self.assertEqual(network_count, 0)
2458- LOG.debug("_test_delete_network - format:%s - END", format)
2459-
2460- def _test_delete_network_in_use(self, format):
2461- LOG.debug("_test_delete_network_in_use - format:%s - START", format)
2462- content_type = "application/%s" % format
2463- port_state = "ACTIVE"
2464- attachment_id = "test_attachment"
2465- network_id = self._create_network(format)
2466- LOG.debug("Deleting network %(network_id)s"\
2467- " of tenant %(tenant_id)s", locals())
2468- port_id = self._create_port(network_id, port_state, format)
2469- #plug an attachment into the port
2470- LOG.debug("Putting attachment into port %s", port_id)
2471- attachment_req = testlib.put_attachment_request(self.tenant_id,
2472- network_id,
2473- port_id,
2474- attachment_id)
2475- attachment_res = attachment_req.get_response(self.api)
2476- self.assertEquals(attachment_res.status_int, 202)
2477-
2478- LOG.debug("Deleting network %(network_id)s"\
2479- " of tenant %(tenant_id)s", locals())
2480- delete_network_req = testlib.network_delete_request(self.tenant_id,
2481- network_id,
2482- format)
2483- delete_network_res = delete_network_req.get_response(self.api)
2484- self.assertEqual(delete_network_res.status_int, 421)
2485- LOG.debug("_test_delete_network_in_use - format:%s - END", format)
2486-
2487- def _test_list_ports(self, format):
2488- LOG.debug("_test_list_ports - format:%s - START", format)
2489- content_type = "application/%s" % format
2490- port_state = "ACTIVE"
2491- network_id = self._create_network(format)
2492- self._create_port(network_id, port_state, format)
2493- self._create_port(network_id, port_state, format)
2494- list_port_req = testlib.port_list_request(self.tenant_id,
2495- network_id, format)
2496- list_port_res = list_port_req.get_response(self.api)
2497- self.assertEqual(list_port_res.status_int, 200)
2498- port_data = Serializer().deserialize(list_port_res.body,
2499- content_type)
2500- # Check port count: should return 2
2501- self.assertEqual(len(port_data['ports']), 2)
2502- LOG.debug("_test_list_ports - format:%s - END", format)
2503-
2504- def _test_show_port(self, format):
2505- LOG.debug("_test_show_port - format:%s - START", format)
2506- content_type = "application/%s" % format
2507- port_state = "ACTIVE"
2508- network_id = self._create_network(format)
2509- port_id = self._create_port(network_id, port_state, format)
2510- show_port_req = testlib.show_port_request(self.tenant_id,
2511- network_id, port_id,
2512- format)
2513- show_port_res = show_port_req.get_response(self.api)
2514- self.assertEqual(show_port_res.status_int, 200)
2515- port_data = Serializer().deserialize(show_port_res.body,
2516- content_type)
2517- self.assertEqual({'id': port_id, 'state': port_state},
2518- port_data['ports']['port'])
2519- LOG.debug("_test_show_port - format:%s - END", format)
2520-
2521- def _test_show_port_networknotfound(self, format):
2522- LOG.debug("_test_show_port_networknotfound - format:%s - START",
2523- format)
2524- port_state = "ACTIVE"
2525- network_id = self._create_network(format)
2526- port_id = self._create_port(network_id, port_state, format)
2527- show_port_req = testlib.show_port_request(self.tenant_id,
2528- "A_BAD_ID", port_id,
2529- format)
2530- show_port_res = show_port_req.get_response(self.api)
2531- self.assertEqual(show_port_res.status_int, 420)
2532- LOG.debug("_test_show_port_networknotfound - format:%s - END",
2533- format)
2534-
2535- def _test_show_port_portnotfound(self, format):
2536- LOG.debug("_test_show_port_portnotfound - format:%s - START", format)
2537- network_id = self._create_network(format)
2538- show_port_req = testlib.show_port_request(self.tenant_id,
2539- network_id,
2540- "A_BAD_ID",
2541- format)
2542- show_port_res = show_port_req.get_response(self.api)
2543- self.assertEqual(show_port_res.status_int, 430)
2544- LOG.debug("_test_show_port_portnotfound - format:%s - END", format)
2545-
2546- def _test_create_port(self, format):
2547- LOG.debug("_test_create_port - format:%s - START", format)
2548- content_type = "application/%s" % format
2549- port_state = "ACTIVE"
2550- network_id = self._create_network(format)
2551- port_id = self._create_port(network_id, port_state, format)
2552- show_port_req = testlib.show_port_request(self.tenant_id,
2553- network_id, port_id, format)
2554- show_port_res = show_port_req.get_response(self.api)
2555- self.assertEqual(show_port_res.status_int, 200)
2556- port_data = Serializer().deserialize(show_port_res.body, content_type)
2557- self.assertEqual(port_id, port_data['ports']['port']['id'])
2558- LOG.debug("_test_create_port - format:%s - END", format)
2559-
2560- def _test_create_port_networknotfound(self, format):
2561- LOG.debug("_test_create_port_networknotfound - format:%s - START",
2562- format)
2563- port_state = "ACTIVE"
2564- self._create_port("A_BAD_ID", port_state, format,
2565- expected_res_status=420)
2566- LOG.debug("_test_create_port_networknotfound - format:%s - END",
2567- format)
2568-
2569- def _test_create_port_badrequest(self, format):
2570- LOG.debug("_test_create_port_badrequest - format:%s - START", format)
2571- bad_body = {'bad-resource': {'bad-attribute': 'bad-value'}}
2572- network_id = self._create_network(format)
2573- port_state = "ACTIVE"
2574- self._create_port(network_id, port_state, format,
2575- custom_req_body=bad_body, expected_res_status=400)
2576- LOG.debug("_test_create_port_badrequest - format:%s - END", format)
2577-
2578- def _test_delete_port(self, format):
2579- LOG.debug("_test_delete_port - format:%s - START", format)
2580- content_type = "application/%s" % format
2581- port_state = "ACTIVE"
2582- network_id = self._create_network(format)
2583- port_id = self._create_port(network_id, port_state, format)
2584- LOG.debug("Deleting port %(port_id)s for network %(network_id)s"\
2585- " of tenant %(tenant_id)s", locals())
2586- delete_port_req = testlib.port_delete_request(self.tenant_id,
2587- network_id, port_id,
2588- format)
2589- delete_port_res = delete_port_req.get_response(self.api)
2590- self.assertEqual(delete_port_res.status_int, 202)
2591- list_port_req = testlib.port_list_request(self.tenant_id, network_id,
2592- format)
2593- list_port_res = list_port_req.get_response(self.api)
2594- port_list_data = Serializer().deserialize(list_port_res.body,
2595- content_type)
2596- port_count = len(port_list_data['ports'])
2597- self.assertEqual(port_count, 0)
2598- LOG.debug("_test_delete_port - format:%s - END", format)
2599-
2600- def _test_delete_port_in_use(self, format):
2601- LOG.debug("_test_delete_port_in_use - format:%s - START", format)
2602- content_type = "application/" + format
2603- port_state = "ACTIVE"
2604- attachment_id = "test_attachment"
2605- network_id = self._create_network(format)
2606- port_id = self._create_port(network_id, port_state, format)
2607- #plug an attachment into the port
2608- LOG.debug("Putting attachment into port %s", port_id)
2609- attachment_req = testlib.put_attachment_request(self.tenant_id,
2610- network_id,
2611- port_id,
2612- attachment_id)
2613- attachment_res = attachment_req.get_response(self.api)
2614- self.assertEquals(attachment_res.status_int, 202)
2615- LOG.debug("Deleting port %(port_id)s for network %(network_id)s"\
2616- " of tenant %(tenant_id)s", locals())
2617- delete_port_req = testlib.port_delete_request(self.tenant_id,
2618- network_id, port_id,
2619- format)
2620- delete_port_res = delete_port_req.get_response(self.api)
2621- self.assertEqual(delete_port_res.status_int, 432)
2622- LOG.debug("_test_delete_port_in_use - format:%s - END", format)
2623-
2624- def _test_delete_port_with_bad_id(self, format):
2625- LOG.debug("_test_delete_port_with_bad_id - format:%s - START",
2626- format)
2627- port_state = "ACTIVE"
2628- network_id = self._create_network(format)
2629- self._create_port(network_id, port_state, format)
2630- # Test for portnotfound
2631- delete_port_req = testlib.port_delete_request(self.tenant_id,
2632- network_id, "A_BAD_ID",
2633- format)
2634- delete_port_res = delete_port_req.get_response(self.api)
2635- self.assertEqual(delete_port_res.status_int, 430)
2636- LOG.debug("_test_delete_port_with_bad_id - format:%s - END", format)
2637-
2638- def _test_delete_port_networknotfound(self, format):
2639- LOG.debug("_test_delete_port_networknotfound - format:%s - START",
2640- format)
2641- port_state = "ACTIVE"
2642- network_id = self._create_network(format)
2643- port_id = self._create_port(network_id, port_state, format)
2644- delete_port_req = testlib.port_delete_request(self.tenant_id,
2645- "A_BAD_ID", port_id,
2646- format)
2647- delete_port_res = delete_port_req.get_response(self.api)
2648- self.assertEqual(delete_port_res.status_int, 420)
2649- LOG.debug("_test_delete_port_networknotfound - format:%s - END",
2650- format)
2651-
2652- def _test_set_port_state(self, format):
2653- LOG.debug("_test_set_port_state - format:%s - START", format)
2654- content_type = "application/%s" % format
2655- port_state = 'DOWN'
2656- new_port_state = 'ACTIVE'
2657- network_id = self._create_network(format)
2658- port_id = self._create_port(network_id, port_state, format)
2659- update_port_req = testlib.update_port_request(self.tenant_id,
2660- network_id, port_id,
2661- new_port_state,
2662- format)
2663- update_port_res = update_port_req.get_response(self.api)
2664- self.assertEqual(update_port_res.status_int, 200)
2665- show_port_req = testlib.show_port_request(self.tenant_id,
2666- network_id, port_id,
2667- format)
2668- show_port_res = show_port_req.get_response(self.api)
2669- self.assertEqual(show_port_res.status_int, 200)
2670- network_data = Serializer().deserialize(show_port_res.body,
2671- content_type)
2672- self.assertEqual({'id': port_id, 'state': new_port_state},
2673- network_data['ports']['port'])
2674- LOG.debug("_test_set_port_state - format:%s - END", format)
2675-
2676- def _test_set_port_state_networknotfound(self, format):
2677- LOG.debug("_test_set_port_state_networknotfound - format:%s - START",
2678- format)
2679- port_state = 'DOWN'
2680- new_port_state = 'ACTIVE'
2681- network_id = self._create_network(format)
2682- port_id = self._create_port(network_id, port_state, format)
2683- update_port_req = testlib.update_port_request(self.tenant_id,
2684- "A_BAD_ID", port_id,
2685- new_port_state,
2686- format)
2687- update_port_res = update_port_req.get_response(self.api)
2688- self.assertEqual(update_port_res.status_int, 420)
2689- LOG.debug("_test_set_port_state_networknotfound - format:%s - END",
2690- format)
2691-
2692- def _test_set_port_state_portnotfound(self, format):
2693- LOG.debug("_test_set_port_state_portnotfound - format:%s - START",
2694- format)
2695- port_state = 'DOWN'
2696- new_port_state = 'ACTIVE'
2697- network_id = self._create_network(format)
2698- self._create_port(network_id, port_state, format)
2699- update_port_req = testlib.update_port_request(self.tenant_id,
2700- network_id,
2701- "A_BAD_ID",
2702- new_port_state,
2703- format)
2704- update_port_res = update_port_req.get_response(self.api)
2705- self.assertEqual(update_port_res.status_int, 430)
2706- LOG.debug("_test_set_port_state_portnotfound - format:%s - END",
2707- format)
2708-
2709- def _test_set_port_state_stateinvalid(self, format):
2710- LOG.debug("_test_set_port_state_stateinvalid - format:%s - START",
2711- format)
2712- port_state = 'DOWN'
2713- new_port_state = 'A_BAD_STATE'
2714- network_id = self._create_network(format)
2715- port_id = self._create_port(network_id, port_state, format)
2716- update_port_req = testlib.update_port_request(self.tenant_id,
2717- network_id, port_id,
2718- new_port_state,
2719- format)
2720- update_port_res = update_port_req.get_response(self.api)
2721- self.assertEqual(update_port_res.status_int, 431)
2722- LOG.debug("_test_set_port_state_stateinvalid - format:%s - END",
2723- format)
2724-
2725- def _test_show_attachment(self, format):
2726- LOG.debug("_test_show_attachment - format:%s - START", format)
2727- content_type = "application/%s" % format
2728- port_state = "ACTIVE"
2729- network_id = self._create_network(format)
2730- interface_id = "test_interface"
2731- port_id = self._create_port(network_id, port_state, format)
2732- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
2733- network_id,
2734- port_id,
2735- interface_id,
2736- format)
2737- put_attachment_res = put_attachment_req.get_response(self.api)
2738- self.assertEqual(put_attachment_res.status_int, 202)
2739- get_attachment_req = testlib.get_attachment_request(self.tenant_id,
2740- network_id,
2741- port_id,
2742- format)
2743- get_attachment_res = get_attachment_req.get_response(self.api)
2744- attachment_data = Serializer().deserialize(get_attachment_res.body,
2745- content_type)
2746- self.assertEqual(attachment_data['attachment'], interface_id)
2747- LOG.debug("_test_show_attachment - format:%s - END", format)
2748-
2749- def _test_show_attachment_networknotfound(self, format):
2750- LOG.debug("_test_show_attachment_networknotfound - format:%s - START",
2751- format)
2752- port_state = "ACTIVE"
2753- network_id = self._create_network(format)
2754- port_id = self._create_port(network_id, port_state, format)
2755- get_attachment_req = testlib.get_attachment_request(self.tenant_id,
2756- "A_BAD_ID",
2757- port_id,
2758- format)
2759- get_attachment_res = get_attachment_req.get_response(self.api)
2760- self.assertEqual(get_attachment_res.status_int, 420)
2761- LOG.debug("_test_show_attachment_networknotfound - format:%s - END",
2762- format)
2763-
2764- def _test_show_attachment_portnotfound(self, format):
2765- LOG.debug("_test_show_attachment_portnotfound - format:%s - START",
2766- format)
2767- port_state = "ACTIVE"
2768- network_id = self._create_network(format)
2769- self._create_port(network_id, port_state, format)
2770- get_attachment_req = testlib.get_attachment_request(self.tenant_id,
2771- network_id,
2772- "A_BAD_ID",
2773- format)
2774- get_attachment_res = get_attachment_req.get_response(self.api)
2775- self.assertEqual(get_attachment_res.status_int, 430)
2776- LOG.debug("_test_show_attachment_portnotfound - format:%s - END",
2777- format)
2778-
2779- def _test_put_attachment(self, format):
2780- LOG.debug("_test_put_attachment - format:%s - START", format)
2781- port_state = "ACTIVE"
2782- network_id = self._create_network(format)
2783- interface_id = "test_interface"
2784- port_id = self._create_port(network_id, port_state, format)
2785- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
2786- network_id,
2787- port_id,
2788- interface_id,
2789- format)
2790- put_attachment_res = put_attachment_req.get_response(self.api)
2791- self.assertEqual(put_attachment_res.status_int, 202)
2792- LOG.debug("_test_put_attachment - format:%s - END", format)
2793-
2794- def _test_put_attachment_networknotfound(self, format):
2795- LOG.debug("_test_put_attachment_networknotfound - format:%s - START",
2796- format)
2797- port_state = 'DOWN'
2798- interface_id = "test_interface"
2799- network_id = self._create_network(format)
2800- port_id = self._create_port(network_id, port_state, format)
2801- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
2802- "A_BAD_ID",
2803- port_id,
2804- interface_id,
2805- format)
2806- put_attachment_res = put_attachment_req.get_response(self.api)
2807- self.assertEqual(put_attachment_res.status_int, 420)
2808- LOG.debug("_test_put_attachment_networknotfound - format:%s - END",
2809- format)
2810-
2811- def _test_put_attachment_portnotfound(self, format):
2812- LOG.debug("_test_put_attachment_portnotfound - format:%s - START",
2813- format)
2814- port_state = 'DOWN'
2815- interface_id = "test_interface"
2816- network_id = self._create_network(format)
2817- self._create_port(network_id, port_state, format)
2818- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
2819- network_id,
2820- "A_BAD_ID",
2821- interface_id,
2822- format)
2823- put_attachment_res = put_attachment_req.get_response(self.api)
2824- self.assertEqual(put_attachment_res.status_int, 430)
2825- LOG.debug("_test_put_attachment_portnotfound - format:%s - END",
2826- format)
2827-
2828- def _test_delete_attachment(self, format):
2829- LOG.debug("_test_delete_attachment - format:%s - START", format)
2830- port_state = "ACTIVE"
2831- network_id = self._create_network(format)
2832- interface_id = "test_interface"
2833- port_id = self._create_port(network_id, port_state, format)
2834- put_attachment_req = testlib.put_attachment_request(self.tenant_id,
2835- network_id,
2836- port_id,
2837- interface_id,
2838- format)
2839- put_attachment_res = put_attachment_req.get_response(self.api)
2840- self.assertEqual(put_attachment_res.status_int, 202)
2841- del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
2842- network_id,
2843- port_id,
2844- format)
2845- del_attachment_res = del_attachment_req.get_response(self.api)
2846- self.assertEqual(del_attachment_res.status_int, 202)
2847- LOG.debug("_test_delete_attachment - format:%s - END", format)
2848-
2849- def _test_delete_attachment_networknotfound(self, format):
2850- LOG.debug("_test_delete_attachment_networknotfound -" \
2851- " format:%s - START", format)
2852- port_state = "ACTIVE"
2853- network_id = self._create_network(format)
2854- port_id = self._create_port(network_id, port_state, format)
2855- del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
2856- "A_BAD_ID",
2857- port_id,
2858- format)
2859- del_attachment_res = del_attachment_req.get_response(self.api)
2860- self.assertEqual(del_attachment_res.status_int, 420)
2861- LOG.debug("_test_delete_attachment_networknotfound -" \
2862- " format:%s - END", format)
2863-
2864- def _test_delete_attachment_portnotfound(self, format):
2865- LOG.debug("_test_delete_attachment_portnotfound - " \
2866- " format:%s - START", format)
2867- port_state = "ACTIVE"
2868- network_id = self._create_network(format)
2869- self._create_port(network_id, port_state, format)
2870- del_attachment_req = testlib.delete_attachment_request(self.tenant_id,
2871- network_id,
2872- "A_BAD_ID",
2873- format)
2874- del_attachment_res = del_attachment_req.get_response(self.api)
2875- self.assertEqual(del_attachment_res.status_int, 430)
2876- LOG.debug("_test_delete_attachment_portnotfound - " \
2877- "format:%s - END", format)
2878-
2879- def setUp(self):
2880- options = {}
2881- options['plugin_provider'] = 'quantum.plugins.SamplePlugin.FakePlugin'
2882- self.api = server.APIRouterV01(options)
2883- self.tenant_id = "test_tenant"
2884- self.network_name = "test_network"
2885-
2886- def tearDown(self):
2887- """Clear the test environment"""
2888- # Remove database contents
2889- db.clear_db()
2890-
2891- def test_list_networks_json(self):
2892- self._test_list_networks('json')
2893-
2894- def test_list_networks_xml(self):
2895- self._test_list_networks('xml')
2896-
2897- def test_create_network_json(self):
2898- self._test_create_network('json')
2899-
2900- def test_create_network_xml(self):
2901- self._test_create_network('xml')
2902-
2903- def test_create_network_badrequest_json(self):
2904- self._test_create_network_badrequest('json')
2905-
2906- def test_create_network_badreqyest_xml(self):
2907- self._test_create_network_badrequest('xml')
2908-
2909- def test_show_network_not_found_json(self):
2910- self._test_show_network_not_found('json')
2911-
2912- def test_show_network_not_found_xml(self):
2913- self._test_show_network_not_found('xml')
2914-
2915- def test_show_network_json(self):
2916- self._test_show_network('json')
2917-
2918- def test_show_network_xml(self):
2919- self._test_show_network('xml')
2920-
2921- def test_delete_network_json(self):
2922- self._test_delete_network('json')
2923-
2924- def test_delete_network_xml(self):
2925- self._test_delete_network('xml')
2926-
2927- def test_rename_network_json(self):
2928- self._test_rename_network('json')
2929-
2930- def test_rename_network_xml(self):
2931- self._test_rename_network('xml')
2932-
2933- def test_rename_network_badrequest_json(self):
2934- self._test_rename_network_badrequest('json')
2935-
2936- def test_rename_network_badrequest_xml(self):
2937- self._test_rename_network_badrequest('xml')
2938-
2939- def test_rename_network_not_found_json(self):
2940- self._test_rename_network_not_found('json')
2941-
2942- def test_rename_network_not_found_xml(self):
2943- self._test_rename_network_not_found('xml')
2944-
2945- def test_delete_network_in_use_json(self):
2946- self._test_delete_network_in_use('json')
2947-
2948- def test_delete_network_in_use_xml(self):
2949- self._test_delete_network_in_use('xml')
2950-
2951- def test_list_ports_json(self):
2952- self._test_list_ports('json')
2953-
2954- def test_list_ports_xml(self):
2955- self._test_list_ports('xml')
2956-
2957- def test_show_port_json(self):
2958- self._test_show_port('json')
2959-
2960- def test_show_port_xml(self):
2961- self._test_show_port('xml')
2962-
2963- def test_show_port_networknotfound_json(self):
2964- self._test_show_port_networknotfound('json')
2965-
2966- def test_show_port_networknotfound_xml(self):
2967- self._test_show_port_networknotfound('xml')
2968-
2969- def test_show_port_portnotfound_json(self):
2970- self._test_show_port_portnotfound('json')
2971-
2972- def test_show_port_portnotfound_xml(self):
2973- self._test_show_port_portnotfound('xml')
2974-
2975- def test_create_port_json(self):
2976- self._test_create_port('json')
2977-
2978- def test_create_port_xml(self):
2979- self._test_create_port('xml')
2980-
2981- def test_create_port_networknotfound_json(self):
2982- self._test_create_port_networknotfound('json')
2983-
2984- def test_create_port_networknotfound_xml(self):
2985- self._test_create_port_networknotfound('xml')
2986-
2987- def test_create_port_badrequest_json(self):
2988- self._test_create_port_badrequest('json')
2989-
2990- def test_create_port_badrequest_xml(self):
2991- self._test_create_port_badrequest('xml')
2992-
2993- def test_delete_port_xml(self):
2994- self._test_delete_port('xml')
2995-
2996- def test_delete_port_json(self):
2997- self._test_delete_port('json')
2998-
2999- def test_delete_port_in_use_xml(self):
3000- self._test_delete_port_in_use('xml')
3001-
3002- def test_delete_port_in_use_json(self):
3003- self._test_delete_port_in_use('json')
3004-
3005- def test_delete_port_networknotfound_xml(self):
3006- self._test_delete_port_networknotfound('xml')
3007-
3008- def test_delete_port_networknotfound_json(self):
3009- self._test_delete_port_networknotfound('json')
3010-
3011- def test_delete_port_with_bad_id_xml(self):
3012- self._test_delete_port_with_bad_id('xml')
3013-
3014- def test_delete_port_with_bad_id_json(self):
3015- self._test_delete_port_with_bad_id('json')
3016-
3017- def test_set_port_state_xml(self):
3018- self._test_set_port_state('xml')
3019-
3020- def test_set_port_state_json(self):
3021- self._test_set_port_state('json')
3022-
3023- def test_set_port_state_networknotfound_xml(self):
3024- self._test_set_port_state_networknotfound('xml')
3025-
3026- def test_set_port_state_networknotfound_json(self):
3027- self._test_set_port_state_networknotfound('json')
3028-
3029- def test_set_port_state_portnotfound_xml(self):
3030- self._test_set_port_state_portnotfound('xml')
3031-
3032- def test_set_port_state_portnotfound_json(self):
3033- self._test_set_port_state_portnotfound('json')
3034-
3035- def test_set_port_state_stateinvalid_xml(self):
3036- self._test_set_port_state_stateinvalid('xml')
3037-
3038- def test_set_port_state_stateinvalid_json(self):
3039- self._test_set_port_state_stateinvalid('json')
3040-
3041- def test_show_attachment_xml(self):
3042- self._test_show_attachment('xml')
3043-
3044- def test_show_attachment_json(self):
3045- self._test_show_attachment('json')
3046-
3047- def test_show_attachment_networknotfound_xml(self):
3048- self._test_show_attachment_networknotfound('xml')
3049-
3050- def test_show_attachment_networknotfound_json(self):
3051- self._test_show_attachment_networknotfound('json')
3052-
3053- def test_show_attachment_portnotfound_xml(self):
3054- self._test_show_attachment_portnotfound('xml')
3055-
3056- def test_show_attachment_portnotfound_json(self):
3057- self._test_show_attachment_portnotfound('json')
3058-
3059- def test_put_attachment_xml(self):
3060- self._test_put_attachment('xml')
3061-
3062- def test_put_attachment_json(self):
3063- self._test_put_attachment('json')
3064-
3065- def test_put_attachment_networknotfound_xml(self):
3066- self._test_put_attachment_networknotfound('xml')
3067-
3068- def test_put_attachment_networknotfound_json(self):
3069- self._test_put_attachment_networknotfound('json')
3070-
3071- def test_put_attachment_portnotfound_xml(self):
3072- self._test_put_attachment_portnotfound('xml')
3073-
3074- def test_put_attachment_portnotfound_json(self):
3075- self._test_put_attachment_portnotfound('json')
3076-
3077- def test_delete_attachment_xml(self):
3078- self._test_delete_attachment('xml')
3079-
3080- def test_delete_attachment_json(self):
3081- self._test_delete_attachment('json')
3082-
3083- def test_delete_attachment_networknotfound_xml(self):
3084- self._test_delete_attachment_networknotfound('xml')
3085-
3086- def test_delete_attachment_networknotfound_json(self):
3087- self._test_delete_attachment_networknotfound('json')
3088-
3089- def test_delete_attachment_portnotfound_xml(self):
3090- self._test_delete_attachment_portnotfound('xml')
3091-
3092- def test_delete_attachment_portnotfound_json(self):
3093- self._test_delete_attachment_portnotfound('json')
3094
3095=== added file 'tests/unit/testlib_api.py'
3096--- tests/unit/testlib_api.py 1970-01-01 00:00:00 +0000
3097+++ tests/unit/testlib_api.py 2011-07-23 18:23:02 +0000
3098@@ -0,0 +1,130 @@
3099+import webob
3100+
3101+from quantum.common.wsgi import Serializer
3102+
3103+
3104+def create_request(path, body, content_type, method='GET'):
3105+ req = webob.Request.blank(path)
3106+ req.method = method
3107+ req.headers = {}
3108+ req.headers['Accept'] = content_type
3109+ req.body = body
3110+ return req
3111+
3112+
3113+def network_list_request(tenant_id, format='xml'):
3114+ method = 'GET'
3115+ path = "/tenants/%(tenant_id)s/networks.%(format)s" % locals()
3116+ content_type = "application/%s" % format
3117+ return create_request(path, None, content_type, method)
3118+
3119+
3120+def show_network_request(tenant_id, network_id, format='xml'):
3121+ method = 'GET'
3122+ path = "/tenants/%(tenant_id)s/networks" \
3123+ "/%(network_id)s.%(format)s" % locals()
3124+ content_type = "application/%s" % format
3125+ return create_request(path, None, content_type, method)
3126+
3127+
3128+def new_network_request(tenant_id, network_name='new_name',
3129+ format='xml', custom_req_body=None):
3130+ method = 'POST'
3131+ path = "/tenants/%(tenant_id)s/networks.%(format)s" % locals()
3132+ data = custom_req_body or {'network': {'net-name': '%s' % network_name}}
3133+ content_type = "application/%s" % format
3134+ body = Serializer().serialize(data, content_type)
3135+ return create_request(path, body, content_type, method)
3136+
3137+
3138+def update_network_request(tenant_id, network_id, network_name, format='xml',
3139+ custom_req_body=None):
3140+ method = 'PUT'
3141+ path = "/tenants/%(tenant_id)s/networks" \
3142+ "/%(network_id)s.%(format)s" % locals()
3143+ data = custom_req_body or {'network': {'net-name': '%s' % network_name}}
3144+ content_type = "application/%s" % format
3145+ body = Serializer().serialize(data, content_type)
3146+ return create_request(path, body, content_type, method)
3147+
3148+
3149+def network_delete_request(tenant_id, network_id, format='xml'):
3150+ method = 'DELETE'
3151+ path = "/tenants/%(tenant_id)s/networks/" \
3152+ "%(network_id)s.%(format)s" % locals()
3153+ content_type = "application/%s" % format
3154+ return create_request(path, None, content_type, method)
3155+
3156+
3157+def port_list_request(tenant_id, network_id, format='xml'):
3158+ method = 'GET'
3159+ path = "/tenants/%(tenant_id)s/networks/" \
3160+ "%(network_id)s/ports.%(format)s" % locals()
3161+ content_type = "application/%s" % format
3162+ return create_request(path, None, content_type, method)
3163+
3164+
3165+def show_port_request(tenant_id, network_id, port_id, format='xml'):
3166+ method = 'GET'
3167+ path = "/tenants/%(tenant_id)s/networks/%(network_id)s" \
3168+ "/ports/%(port_id)s.%(format)s" % locals()
3169+ content_type = "application/%s" % format
3170+ return create_request(path, None, content_type, method)
3171+
3172+
3173+def new_port_request(tenant_id, network_id, port_state,
3174+ format='xml', custom_req_body=None):
3175+ method = 'POST'
3176+ path = "/tenants/%(tenant_id)s/networks/" \
3177+ "%(network_id)s/ports.%(format)s" % locals()
3178+ data = custom_req_body or {'port': {'port-state': '%s' % port_state}}
3179+ content_type = "application/%s" % format
3180+ body = Serializer().serialize(data, content_type)
3181+ return create_request(path, body, content_type, method)
3182+
3183+
3184+def port_delete_request(tenant_id, network_id, port_id, format='xml'):
3185+ method = 'DELETE'
3186+ path = "/tenants/%(tenant_id)s/networks/" \
3187+ "%(network_id)s/ports/%(port_id)s.%(format)s" % locals()
3188+ content_type = "application/%s" % format
3189+ return create_request(path, None, content_type, method)
3190+
3191+
3192+def update_port_request(tenant_id, network_id, port_id, port_state,
3193+ format='xml', custom_req_body=None):
3194+ method = 'PUT'
3195+ path = "/tenants/%(tenant_id)s/networks" \
3196+ "/%(network_id)s/ports/%(port_id)s.%(format)s" % locals()
3197+ data = custom_req_body or {'port': {'port-state': '%s' % port_state}}
3198+ content_type = "application/%s" % format
3199+ body = Serializer().serialize(data, content_type)
3200+ return create_request(path, body, content_type, method)
3201+
3202+
3203+def get_attachment_request(tenant_id, network_id, port_id, format='xml'):
3204+ method = 'GET'
3205+ path = "/tenants/%(tenant_id)s/networks/" \
3206+ "%(network_id)s/ports/%(port_id)s/attachment.%(format)s" % locals()
3207+ content_type = "application/%s" % format
3208+ return create_request(path, None, content_type, method)
3209+
3210+
3211+def put_attachment_request(tenant_id, network_id, port_id,
3212+ attachment_id, format='xml'):
3213+ method = 'PUT'
3214+ path = "/tenants/%(tenant_id)s/networks/" \
3215+ "%(network_id)s/ports/%(port_id)s/attachment.%(format)s" % locals()
3216+ data = {'port': {'attachment-id': attachment_id}}
3217+ content_type = "application/%s" % format
3218+ body = Serializer().serialize(data, content_type)
3219+ return create_request(path, body, content_type, method)
3220+
3221+
3222+def delete_attachment_request(tenant_id, network_id, port_id,
3223+ attachment_id, format='xml'):
3224+ method = 'DELETE'
3225+ path = "/tenants/%(tenant_id)s/networks/" \
3226+ "%(network_id)s/ports/%(port_id)s/attachment.%(format)s" % locals()
3227+ content_type = "application/%s" % format
3228+ return create_request(path, None, content_type, method)
3229
3230=== removed file 'tests/unit/testlib_api.py'
3231--- tests/unit/testlib_api.py 2011-07-18 22:51:22 +0000
3232+++ tests/unit/testlib_api.py 1970-01-01 00:00:00 +0000
3233@@ -1,130 +0,0 @@
3234-import webob
3235-
3236-from quantum.common.wsgi import Serializer
3237-
3238-
3239-def create_request(path, body, content_type, method='GET'):
3240- req = webob.Request.blank(path)
3241- req.method = method
3242- req.headers = {}
3243- req.headers['Accept'] = content_type
3244- req.body = body
3245- return req
3246-
3247-
3248-def network_list_request(tenant_id, format='xml'):
3249- method = 'GET'
3250- path = "/tenants/%(tenant_id)s/networks.%(format)s" % locals()
3251- content_type = "application/%s" % format
3252- return create_request(path, None, content_type, method)
3253-
3254-
3255-def show_network_request(tenant_id, network_id, format='xml'):
3256- method = 'GET'
3257- path = "/tenants/%(tenant_id)s/networks" \
3258- "/%(network_id)s.%(format)s" % locals()
3259- content_type = "application/%s" % format
3260- return create_request(path, None, content_type, method)
3261-
3262-
3263-def new_network_request(tenant_id, network_name='new_name',
3264- format='xml', custom_req_body=None):
3265- method = 'POST'
3266- path = "/tenants/%(tenant_id)s/networks.%(format)s" % locals()
3267- data = custom_req_body or {'network': {'net-name': '%s' % network_name}}
3268- content_type = "application/%s" % format
3269- body = Serializer().serialize(data, content_type)
3270- return create_request(path, body, content_type, method)
3271-
3272-
3273-def update_network_request(tenant_id, network_id, network_name, format='xml',
3274- custom_req_body=None):
3275- method = 'PUT'
3276- path = "/tenants/%(tenant_id)s/networks" \
3277- "/%(network_id)s.%(format)s" % locals()
3278- data = custom_req_body or {'network': {'net-name': '%s' % network_name}}
3279- content_type = "application/%s" % format
3280- body = Serializer().serialize(data, content_type)
3281- return create_request(path, body, content_type, method)
3282-
3283-
3284-def network_delete_request(tenant_id, network_id, format='xml'):
3285- method = 'DELETE'
3286- path = "/tenants/%(tenant_id)s/networks/" \
3287- "%(network_id)s.%(format)s" % locals()
3288- content_type = "application/%s" % format
3289- return create_request(path, None, content_type, method)
3290-
3291-
3292-def port_list_request(tenant_id, network_id, format='xml'):
3293- method = 'GET'
3294- path = "/tenants/%(tenant_id)s/networks/" \
3295- "%(network_id)s/ports.%(format)s" % locals()
3296- content_type = "application/%s" % format
3297- return create_request(path, None, content_type, method)
3298-
3299-
3300-def show_port_request(tenant_id, network_id, port_id, format='xml'):
3301- method = 'GET'
3302- path = "/tenants/%(tenant_id)s/networks/%(network_id)s" \
3303- "/ports/%(port_id)s.%(format)s" % locals()
3304- content_type = "application/%s" % format
3305- return create_request(path, None, content_type, method)
3306-
3307-
3308-def new_port_request(tenant_id, network_id, port_state,
3309- format='xml', custom_req_body=None):
3310- method = 'POST'
3311- path = "/tenants/%(tenant_id)s/networks/" \
3312- "%(network_id)s/ports.%(format)s" % locals()
3313- data = custom_req_body or {'port': {'port-state': '%s' % port_state}}
3314- content_type = "application/%s" % format
3315- body = Serializer().serialize(data, content_type)
3316- return create_request(path, body, content_type, method)
3317-
3318-
3319-def port_delete_request(tenant_id, network_id, port_id, format='xml'):
3320- method = 'DELETE'
3321- path = "/tenants/%(tenant_id)s/networks/" \
3322- "%(network_id)s/ports/%(port_id)s.%(format)s" % locals()
3323- content_type = "application/%s" % format
3324- return create_request(path, None, content_type, method)
3325-
3326-
3327-def update_port_request(tenant_id, network_id, port_id, port_state,
3328- format='xml', custom_req_body=None):
3329- method = 'PUT'
3330- path = "/tenants/%(tenant_id)s/networks" \
3331- "/%(network_id)s/ports/%(port_id)s.%(format)s" % locals()
3332- data = custom_req_body or {'port': {'port-state': '%s' % port_state}}
3333- content_type = "application/%s" % format
3334- body = Serializer().serialize(data, content_type)
3335- return create_request(path, body, content_type, method)
3336-
3337-
3338-def get_attachment_request(tenant_id, network_id, port_id, format='xml'):
3339- method = 'GET'
3340- path = "/tenants/%(tenant_id)s/networks/" \
3341- "%(network_id)s/ports/%(port_id)s/attachment.%(format)s" % locals()
3342- content_type = "application/%s" % format
3343- return create_request(path, None, content_type, method)
3344-
3345-
3346-def put_attachment_request(tenant_id, network_id, port_id,
3347- attachment_id, format='xml'):
3348- method = 'PUT'
3349- path = "/tenants/%(tenant_id)s/networks/" \
3350- "%(network_id)s/ports/%(port_id)s/attachment.%(format)s" % locals()
3351- data = {'port': {'attachment-id': attachment_id}}
3352- content_type = "application/%s" % format
3353- body = Serializer().serialize(data, content_type)
3354- return create_request(path, body, content_type, method)
3355-
3356-
3357-def delete_attachment_request(tenant_id, network_id, port_id,
3358- attachment_id, format='xml'):
3359- method = 'DELETE'
3360- path = "/tenants/%(tenant_id)s/networks/" \
3361- "%(network_id)s/ports/%(port_id)s/attachment.%(format)s" % locals()
3362- content_type = "application/%s" % format
3363- return create_request(path, None, content_type, method)

Subscribers

People subscribed via source and target branches