Merge lp:~termie/nova/move_tests into lp:~hudson-openstack/nova/trunk

Proposed by termie
Status: Rejected
Rejected by: Eric Day
Proposed branch: lp:~termie/nova/move_tests
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 4302 lines
To merge this branch: bzr merge lp:~termie/nova/move_tests
Reviewer Review Type Date Requested Status
Eric Day (community) Disapprove
Soren Hansen (community) Disapprove
Review via email: mp+30739@code.launchpad.net

Description of the change

Move tests out of nova directory.

Mainly so that they aren't packaged with the nova code,
but also just for cleanliness.

Had to fix a small bug in the Network unittests where it was using relative paths.

To post a comment you must log in.
Revision history for this message
Soren Hansen (soren) wrote :

I actually prefer the tests right where they are, i.e. below the namespace to which they pertain. Looking through the python packages I have installed on my system, it also seems to be the prevailing approach, so -1 from me, I'm afraid.

review: Disapprove
Revision history for this message
Soren Hansen (soren) wrote :

Oh, you should set your bzr whomi properly, by the way. "bzr help whoami" for more info.

Revision history for this message
Soren Hansen (soren) wrote :

And one last thing: bzr supports moving files (using "bzr move" or "bzr rename" (one is an alias for the other)). Please use that when moving files in the future.

Revision history for this message
termie (termie) wrote :

If that seems to be the common approach no objection here, I'm used to seeing it the other way around. A quick scan through the python repositories I have copies of on my laptop shows:

PIL --
boto -- out
bzr -- in
bzr-fastimport -- out
django -- out
eventlet -- out
google-app-engine-django -- in
gunicorn -- out
mercurial -- out
nose -- out
redis-py -- out
pylint -- ?? wtf are they doing
pyosc -- n/a
python-cloudfiles -- out
python-daemon -- n/a
python-gflags -- n/a
twisted -- in
virtualenv -- n/a
zope -- in

TOTAL:
tests in package: 4
tests outside of package: 9
no package / no test: 5

... which actually makes me inclined to believe that having it out is actually the more common way.

Reconsider?

Revision history for this message
termie (termie) wrote :

oh, forgot to delete PIL from the list, I had a source zip file.

Revision history for this message
termie (termie) wrote :

swift also has them out.

If you will approve I will remake a branch using move/rename to clean this up.

Revision history for this message
Monty Taylor (mordred) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 07/26/2010 03:10 PM, termie wrote:
> If that seems to be the common approach no objection here, I'm used to seeing it the other way around. A quick scan through the python repositories I have copies of on my laptop shows:
>
> PIL --
> boto -- out
> bzr -- in
> bzr-fastimport -- out
> django -- out
> eventlet -- out
> google-app-engine-django -- in
> gunicorn -- out
> mercurial -- out
> nose -- out
> redis-py -- out
> pylint -- ?? wtf are they doing
> pyosc -- n/a
> python-cloudfiles -- out
> python-daemon -- n/a
> python-gflags -- n/a
> twisted -- in
> virtualenv -- n/a
> zope -- in
>
>
> TOTAL:
> tests in package: 4
> tests outside of package: 9
> no package / no test: 5
>
> ... which actually makes me inclined to believe that having it out is actually the more common way.
>
> Reconsider?

I can make good arguments for either... my personal preference is out
though. My arguments for out:

When I run pep8/pylint, I run it on nova/ ... if you have tests out,
then you don't have to keep them clean. :)

They don't get installed.

Tests are in a location, which means you can find them - and then they
consume the package to be tested just like anyone else. If they're in,
then they're sort of _part_ of that package, which means they may have a
slightly different view of things than things which are not part of that
package.

HOWEVER - I would vote that whichever we pick we should apply to both
swift and nova and then make that our best-practice for openstack
projects. Swift is currently out. Nova is currently in.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkxOCW4ACgkQ2Jv7/VK1RgHgXQCguzts8sb7B2iTalDx/LHgFXPC
V0YAnRtvnwWn5b3829GmfcXaAi+FoLTP
=Pgtq
-----END PGP SIGNATURE-----

Revision history for this message
Eric Day (eday) wrote :

My preference would probably by out as well, and don't install them. I would still require pylint/pep8 to pass for everything in tests/ though, no reason to be sloppy there. :)

If we do go this way, definitely need to recreate this branch with proper move/rename though.

review: Needs Fixing
Revision history for this message
Soren Hansen (soren) wrote :

On Mon, Jul 26, 2010 at 10:18:59PM -0000, Monty Taylor wrote:
> I can make good arguments for either... my personal preference is out
> though. My arguments for out:
>
> When I run pep8/pylint, I run it on nova/ ... if you have tests out,
> then you don't have to keep them clean. :)
>
> They don't get installed.

To me, both of those are good reasons why we should keep them in. :)

Revision history for this message
Soren Hansen (soren) wrote :

To elaborate a bit: Tests are code. It should be just as pretty, neat, and wonderful as any other piece of code.

I want them to be installed so that people can run tests on the installed code as well. There might be environmental things that factor into the tests, so I think it's very valuable to be able to tell people who report bugs to run the test suite, for instance.

In fact, I think I'd much rather move the tests for e.g. the objectstore into nova/objectstore/tests. It feels perfectly natural to me that tests pertaining to nova.objectstore are in nova.objectstore.tests.

Revision history for this message
termie (termie) wrote :

> To elaborate a bit: Tests are code. It should be just as pretty, neat, and
> wonderful as any other piece of code.
>

I agree on the cleanliness, but that has little to do with where the tests live.

> I want them to be installed so that people can run tests on the installed code
> as well. There might be environmental things that factor into the tests, so I
> think it's very valuable to be able to tell people who report bugs to run the
> test suite, for instance.

I think this is a bogus statement, I don't think anybody has ever convinced a 'regular' user to run a test suite and I think any developer who is going to go through the trouble is fine downloading a package or checkout (or more likely going back to the package or checkout they've already downloaded and left in a folder somewhere) to get at the tests.

>
> In fact, I think I'd much rather move the tests for e.g. the objectstore into
> nova/objectstore/tests. It feels perfectly natural to me that tests pertaining
> to nova.objectstore are in nova.objectstore.tests.

That to me feels obscene, my opinion on subdirectories/submodules is that they exist to hide things, putting tests further down a hole only makes you forget it is there and makes it that much more difficult to keep track of and to get to when you are changing something: making things separate that have no need to be separate for the sake of having little bins to put everything in just means more bins to sort through when you need to find something.

Test-code is self-similar, much more so than it is similar to, say, objectstore's code, and more than it is to anything else in the nova directory. Test code should generally look the same as other test code and, I think, should be thought of as an entity outside of nova twisting the switches and pulling the nobs to make sure all the lights come on at the right times.

In general I don't want people thinking that the test code is part of the nova install, I don't want people referencing the test code from their code, it is stuff that should never be run on a production machine and has no place there. We also already have 'smoketests' that are outside the repo, so there is some precedent.

Revision history for this message
Soren Hansen (soren) wrote :
Download full text (4.1 KiB)

On Tue, Jul 27, 2010 at 12:59:43PM -0000, termie wrote:
>> To elaborate a bit: Tests are code. It should be just as pretty,
>> neat, and wonderful as any other piece of code.
> I agree on the cleanliness, but that has little to do with where the
> tests live.

I agree. It was a response to Monty's comment about not having pylint
shout at him about tests if they were not inside nova/.

>> I want them to be installed so that people can run tests on the
>> installed code as well. There might be environmental things that
>> factor into the tests, so I think it's very valuable to be able to
>> tell people who report bugs to run the test suite, for instance.
> I think this is a bogus statement, I don't think anybody has ever
> convinced a 'regular' user to run a test suite

I don't think I understand why you find it so far-fetched to tell a user
to "please run nova-run-tests" if they've reported a bug that looks odd
in some way. It can help identify broken dependencies, user-modified
code (people tend to tinker with stuff if they can, and since this is
all Python, bugs are just a simple $EDITOR away).

> and I think any developer who is going to go through the trouble is
> fine downloading a package or checkout (or more likely going back to
> the package or checkout they've already downloaded and left in a
> folder somewhere) to get at the tests.

I expect people doing vcs checkouts or otherwise installing from source
will be a rarity compared to people who install from packages from their
respective Linux distro.

>> In fact, I think I'd much rather move the tests for e.g. the
>> objectstore into nova/objectstore/tests. It feels perfectly natural
>> to me that tests pertaining to nova.objectstore are in
>> nova.objectstore.tests.
> That to me feels obscene, my opinion on subdirectories/submodules is
> that they exist to hide things,

In that case, I think this conversation is going to difficult :) I treat
subdirectories much like shelves in my book case. I use both to keep
things orderly and arrange stuff according to some set of criteria. I
try to put stuff on the shelves instead of throwing them all on the
floor in front of bookcase. Sure, if the directory structure was
random, it'd be counterproductive, but if it's consistent and
predictable, it's a huge help in organising stuff.

> putting tests further down a hole only makes you forget it is there
> and makes it that much more difficult to keep track of and to get to
> when you are changing something: making things separate that have no
> need to be separate for the sake of having little bins to put
> everything in just means more bins to sort through when you need to
> find something.

I'm completely missing how this is an argument for putting the tests
_all the way outside the tree_.

> Test-code is self-similar, much more so than it is similar to, say,
> objectstore's code, and more than it is to anything else in the nova
> directory. Test code should generally look the same as other test code
> and, I think, should be thought of as an entity outside of nova
> twisting the switches and pulling the nobs to make sure all the lights
> come on at the right times.

I fundamentally disagree. I...

Read more...

Revision history for this message
termie (termie) wrote :
Download full text (8.5 KiB)

> >> I want them to be installed so that people can run tests on the
> >> installed code as well. There might be environmental things that
> >> factor into the tests, so I think it's very valuable to be able to
> >> tell people who report bugs to run the test suite, for instance.
> > I think this is a bogus statement, I don't think anybody has ever
> > convinced a 'regular' user to run a test suite
>
> I don't think I understand why you find it so far-fetched to tell a user
> to "please run nova-run-tests" if they've reported a bug that looks odd
> in some way. It can help identify broken dependencies, user-modified
> code (people tend to tinker with stuff if they can, and since this is
> all Python, bugs are just a simple $EDITOR away).

I agree with the sentiment, but

(a) I don't think unit tests should be testing system compatibility or touching the system much at all, though they still detect missing / invalid python dependencies from time to time. While it is true that we have a mixed bag of tests at the moment, I hope that in the future we will eventually manage to separate the integration tests from the unit tests.

(b) In the event that we have some tests that were relevant towards actually exercising the system they would also have to be pretty sure to "above all, do no harm" if we are expecting some poor user in an already unknown broken state to run them and not have his system worse off afterwards, at the moment the tests litter rather heavily.

(c) I think this use case is much better targeted by a specific set of checks that look for system compatibility / sanity and make sure they are non-invasive. And we would write tests for those checks to make sure they work that wouldn't be run when you run the checks. And since they non-invasive we can run them on install, or any other time.

>
> > and I think any developer who is going to go through the trouble is
> > fine downloading a package or checkout (or more likely going back to
> > the package or checkout they've already downloaded and left in a
> > folder somewhere) to get at the tests.
>
> I expect people doing vcs checkouts or otherwise installing from source
> will be a rarity compared to people who install from packages from their
> respective Linux distro.

Agreed that they are the the rarity, my point was that other users are less likely to be useful candidates for running a test suite.

>
> >> In fact, I think I'd much rather move the tests for e.g. the
> >> objectstore into nova/objectstore/tests. It feels perfectly natural
> >> to me that tests pertaining to nova.objectstore are in
> >> nova.objectstore.tests.
> > That to me feels obscene, my opinion on subdirectories/submodules is
> > that they exist to hide things,
>
> In that case, I think this conversation is going to difficult :) I treat
> subdirectories much like shelves in my book case. I use both to keep
> things orderly and arrange stuff according to some set of criteria. I
> try to put stuff on the shelves instead of throwing them all on the
> floor in front of bookcase. Sure, if the directory structure was
> random, it'd be counterproductive, but if it's consistent and
> predictable, it's a huge h...

Read more...

Revision history for this message
Soren Hansen (soren) wrote :

On Tue, Jul 27, 2010 at 11:36:49PM -0000, termie wrote:
> A better one is your office, you keep the things you use often out in
> the open and you put the things you use less often and want out of
> sight in a tray or on a shelf (like a book, because you are unlikely
> to be using a book often). On my desk you will generally find a phone,
> a usb cable, my wallet, my keys and a variety of junk that could be
> put in a box but I would just have to take it back out of the box
> every couple days when I want to use it. Somewhere in the room will be
> drawers (what do you have in your drawers? do you even open them? I
> have ping pong paddles) and shelves. It's messy but if you were to
> attempt to find something on my desk it would be obvious how to
> proceed and you'd likely do it seconds.

Would your rather we put e.g. objectstore tests in
nova/objectstore/tests.py? That should also address your prominence
concern.

--
Soren Hansen
Ubuntu Developer
http://www.ubuntu.com/

Revision history for this message
Eric Day (eday) wrote :

So, this thread has died. We should decide one way or another so we don't have an outstanding merge request. Anyone feel strongly enough to decide one way or another? The difference between 'nova/tests' vs just 'tests' seems pretty minor.

I actually like the idea of having the tests right alongside the files they test as Soren suggests. For example:

nova/objectstire/test_handler.py
...
nova/objectstore/test.py # tests integration between all objectstore components
nova/rpc/test_rpc.py
...

I can see the argument that this litters tests too much, but the test code is just as real as the production code. :) Having a directory with the same structure for tests (nova/tests/...) seems redundant.

Thoughts?

Revision history for this message
Soren Hansen (soren) wrote :

Yes, test code is just as real as production code, but I also group production code into directories to keep things orderly. Such is my taste :)

...but sure, if this is what it takes to keep it inside nova/, let's go for it.

Revision history for this message
Eric Day (eday) wrote :

Marking this as rejected. We'll keep tests as is since this stalled, and if we did want to move the tests out, we would need a new patch that uses bzr renames instead of rm/add anyways.

review: Disapprove

Unmerged revisions

155. By termie

Move tests out of nova directory.

Mainly so that they aren't packaged with the nova code,
but also just for cleanliness.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed directory 'nova/tests'
=== removed directory 'nova/tests/CA'
=== removed file 'nova/tests/CA/cacert.pem'
--- nova/tests/CA/cacert.pem 2010-05-28 06:05:26 +0000
+++ nova/tests/CA/cacert.pem 1970-01-01 00:00:00 +0000
@@ -1,17 +0,0 @@
1-----BEGIN CERTIFICATE-----
2MIICyzCCAjSgAwIBAgIJANiqHZUcbScCMA0GCSqGSIb3DQEBBAUAME4xEjAQBgNV
3BAoTCU5PVkEgUk9PVDEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzETMBEGA1UECBMK
4Q2FsaWZvcm5pYTELMAkGA1UEBhMCVVMwHhcNMTAwNTI4MDExOTI1WhcNMTEwNTI4
5MDExOTI1WjBOMRIwEAYDVQQKEwlOT1ZBIFJPT1QxFjAUBgNVBAcTDU1vdW50YWlu
6IFZpZXcxEzARBgNVBAgTCkNhbGlmb3JuaWExCzAJBgNVBAYTAlVTMIGfMA0GCSqG
7SIb3DQEBAQUAA4GNADCBiQKBgQDobUnq8rpXA/HQZ2Uu9Me3SlqCayz3ws2wtvFQ
8koWPUzpriIYPkpprz2EaVu07Zb9uJHvjcoY07nYntl4jR8S7PH4XZhlVFn8AQWzs
9iThU4KJF71UfVM00dDrarSgVpyOIcFXO3iUvLoJj7+RUPjrWdLuJoMqnhicgLeHZ
10LAZ8ewIDAQABo4GwMIGtMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFMh1RMlTVtt8
11EdESYpsTU08r0FnpMH4GA1UdIwR3MHWAFMh1RMlTVtt8EdESYpsTU08r0FnpoVKk
12UDBOMRIwEAYDVQQKEwlOT1ZBIFJPT1QxFjAUBgNVBAcTDU1vdW50YWluIFZpZXcx
13EzARBgNVBAgTCkNhbGlmb3JuaWExCzAJBgNVBAYTAlVTggkA2KodlRxtJwIwDQYJ
14KoZIhvcNAQEEBQADgYEAq+YCgflK36HCdodNu2ya3O6UDRUE2dW8n96tAOmvHqmR
15v38k8GIW0pjWDo+lZYnFmeJYd+QGcJl9fLzXxffV5k+rNCfr/gEYtznWLNUX7AZB
16b/VC7L+yK9qz08C8n51TslXaf3fUGkfkQxsvEP7+hi0qavdd/8eTbdheWahYwWg=
17-----END CERTIFICATE-----
180
=== removed directory 'nova/tests/CA/private'
=== removed file 'nova/tests/CA/private/cakey.pem'
--- nova/tests/CA/private/cakey.pem 2010-05-28 06:05:26 +0000
+++ nova/tests/CA/private/cakey.pem 1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
1-----BEGIN RSA PRIVATE KEY-----
2MIICXQIBAAKBgQDobUnq8rpXA/HQZ2Uu9Me3SlqCayz3ws2wtvFQkoWPUzpriIYP
3kpprz2EaVu07Zb9uJHvjcoY07nYntl4jR8S7PH4XZhlVFn8AQWzsiThU4KJF71Uf
4VM00dDrarSgVpyOIcFXO3iUvLoJj7+RUPjrWdLuJoMqnhicgLeHZLAZ8ewIDAQAB
5AoGBANQonmZ2Nh2jniFrn/LiwULP/ho6Fov6J6N8+n1focaYZCUwM58XZRmv7KUM
6X/PuBnVVnDibm2HJodTSJM/zfODnGO15kdmJ9X23FkkdTyuvphO5tYF0ONARXdfX
79LbPcLYA14VSCZCKCye6mbv/xi0C/s7q6ZBoMl7XaeD9hgUxAkEA9lxQY/ZxcLV0
8Ae5I2spBbtuXEGns11YnKnppc59RrAono1gaDeYY2WZRwztIcD6VtUv7qkzH6ubo
9shAG4fvnPQJBAPGFaDODs2ckPvxnILEbjpnZXGQqDCpQ3sVJ6nfu+qdAWS92ESNo
10Y6DC8zFjFaQFbKy6Jxr1VsvYDXhF8cmy7hcCQHkLElSLGWGPRdhNA268QTn+mlJu
11OPf0VHoCex1cAfzNYHxZJTP/AeaO501NK2I63cOd+aDK6M75dQtH5JnT8uECQQCg
12jVydkhk6oV+1jiCvW3BKWbIPa9w2bRgJ8n8JRzYc5Kvk3wm5jfVcsvvTgtip9mkt
130XmZdCpEy9T4dRasTGP1AkBMhShiVP7+P+SIQlZtSn8ckTt9G6cefEjxsv0kVFZe
14SjkUO0ZifahF8r3Q1eEUSzdXEvicEwONvcpc7MLwfSD7
15-----END RSA PRIVATE KEY-----
160
=== removed file 'nova/tests/__init__.py'
--- nova/tests/__init__.py 2010-07-15 15:52:11 +0000
+++ nova/tests/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,31 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19"""
20:mod:`nova.tests` -- Nova Unittests
21=====================================================
22
23.. automodule:: nova.tests
24 :platform: Unix
25.. moduleauthor:: Jesse Andrews <jesse@ansolabs.com>
26.. moduleauthor:: Devin Carlen <devin.carlen@gmail.com>
27.. moduleauthor:: Vishvananda Ishaya <vishvananda@yahoo.com>
28.. moduleauthor:: Joshua McKenty <joshua@cognition.ca>
29.. moduleauthor:: Manish Singh <yosh@gimp.org>
30.. moduleauthor:: Andy Smith <andy@anarkystic.com>
31"""
320
=== removed file 'nova/tests/access_unittest.py'
--- nova/tests/access_unittest.py 2010-07-15 23:13:48 +0000
+++ nova/tests/access_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,165 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import unittest
20import logging
21
22from nova import exception
23from nova import flags
24from nova import test
25from nova.auth.users import UserManager
26from nova.auth import rbac
27
28
29FLAGS = flags.FLAGS
30class Context(object):
31 pass
32
33class AccessTestCase(test.BaseTestCase):
34 def setUp(self):
35 super(AccessTestCase, self).setUp()
36 FLAGS.fake_libvirt = True
37 FLAGS.fake_storage = True
38 um = UserManager.instance()
39 # Make test users
40 try:
41 self.testadmin = um.create_user('testadmin')
42 except Exception, err:
43 logging.error(str(err))
44 try:
45 self.testpmsys = um.create_user('testpmsys')
46 except: pass
47 try:
48 self.testnet = um.create_user('testnet')
49 except: pass
50 try:
51 self.testsys = um.create_user('testsys')
52 except: pass
53 # Assign some rules
54 try:
55 um.add_role('testadmin', 'cloudadmin')
56 except: pass
57 try:
58 um.add_role('testpmsys', 'sysadmin')
59 except: pass
60 try:
61 um.add_role('testnet', 'netadmin')
62 except: pass
63 try:
64 um.add_role('testsys', 'sysadmin')
65 except: pass
66
67 # Make a test project
68 try:
69 self.project = um.create_project('testproj', 'testpmsys', 'a test project', ['testpmsys', 'testnet', 'testsys'])
70 except: pass
71 try:
72 self.project.add_role(self.testnet, 'netadmin')
73 except: pass
74 try:
75 self.project.add_role(self.testsys, 'sysadmin')
76 except: pass
77 self.context = Context()
78 self.context.project = self.project
79 #user is set in each test
80
81 def tearDown(self):
82 um = UserManager.instance()
83 # Delete the test project
84 um.delete_project('testproj')
85 # Delete the test user
86 um.delete_user('testadmin')
87 um.delete_user('testpmsys')
88 um.delete_user('testnet')
89 um.delete_user('testsys')
90 super(AccessTestCase, self).tearDown()
91
92 def test_001_allow_all(self):
93 self.context.user = self.testadmin
94 self.assertTrue(self._allow_all(self.context))
95 self.context.user = self.testpmsys
96 self.assertTrue(self._allow_all(self.context))
97 self.context.user = self.testnet
98 self.assertTrue(self._allow_all(self.context))
99 self.context.user = self.testsys
100 self.assertTrue(self._allow_all(self.context))
101
102 def test_002_allow_none(self):
103 self.context.user = self.testadmin
104 self.assertTrue(self._allow_none(self.context))
105 self.context.user = self.testpmsys
106 self.assertRaises(exception.NotAuthorized, self._allow_none, self.context)
107 self.context.user = self.testnet
108 self.assertRaises(exception.NotAuthorized, self._allow_none, self.context)
109 self.context.user = self.testsys
110 self.assertRaises(exception.NotAuthorized, self._allow_none, self.context)
111
112 def test_003_allow_project_manager(self):
113 self.context.user = self.testadmin
114 self.assertTrue(self._allow_project_manager(self.context))
115 self.context.user = self.testpmsys
116 self.assertTrue(self._allow_project_manager(self.context))
117 self.context.user = self.testnet
118 self.assertRaises(exception.NotAuthorized, self._allow_project_manager, self.context)
119 self.context.user = self.testsys
120 self.assertRaises(exception.NotAuthorized, self._allow_project_manager, self.context)
121
122 def test_004_allow_sys_and_net(self):
123 self.context.user = self.testadmin
124 self.assertTrue(self._allow_sys_and_net(self.context))
125 self.context.user = self.testpmsys # doesn't have the per project sysadmin
126 self.assertRaises(exception.NotAuthorized, self._allow_sys_and_net, self.context)
127 self.context.user = self.testnet
128 self.assertTrue(self._allow_sys_and_net(self.context))
129 self.context.user = self.testsys
130 self.assertTrue(self._allow_sys_and_net(self.context))
131
132 def test_005_allow_sys_no_pm(self):
133 self.context.user = self.testadmin
134 self.assertTrue(self._allow_sys_no_pm(self.context))
135 self.context.user = self.testpmsys
136 self.assertRaises(exception.NotAuthorized, self._allow_sys_no_pm, self.context)
137 self.context.user = self.testnet
138 self.assertRaises(exception.NotAuthorized, self._allow_sys_no_pm, self.context)
139 self.context.user = self.testsys
140 self.assertTrue(self._allow_sys_no_pm(self.context))
141
142 @rbac.allow('all')
143 def _allow_all(self, context):
144 return True
145
146 @rbac.allow('none')
147 def _allow_none(self, context):
148 return True
149
150 @rbac.allow('projectmanager')
151 def _allow_project_manager(self, context):
152 return True
153
154 @rbac.allow('sysadmin', 'netadmin')
155 def _allow_sys_and_net(self, context):
156 return True
157
158 @rbac.allow('sysadmin')
159 @rbac.deny('projectmanager')
160 def _allow_sys_no_pm(self, context):
161 return True
162
163if __name__ == "__main__":
164 # TODO: Implement use_fake as an option
165 unittest.main()
1660
=== removed file 'nova/tests/api_integration.py'
--- nova/tests/api_integration.py 2010-07-15 23:13:48 +0000
+++ nova/tests/api_integration.py 1970-01-01 00:00:00 +0000
@@ -1,54 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19
20import boto
21from boto.ec2.regioninfo import RegionInfo
22import unittest
23
24
25ACCESS_KEY = 'fake'
26SECRET_KEY = 'fake'
27CLC_IP = '127.0.0.1'
28CLC_PORT = 8773
29REGION = 'test'
30
31def get_connection():
32 return boto.connect_ec2 (
33 aws_access_key_id=ACCESS_KEY,
34 aws_secret_access_key=SECRET_KEY,
35 is_secure=False,
36 region=RegionInfo(None, REGION, CLC_IP),
37 port=CLC_PORT,
38 path='/services/Cloud',
39 debug=99
40 )
41
42class APIIntegrationTests(unittest.TestCase):
43 def test_001_get_all_images(self):
44 conn = get_connection()
45 res = conn.get_all_images()
46
47
48if __name__ == '__main__':
49 unittest.main()
50
51#print conn.get_all_key_pairs()
52#print conn.create_key_pair
53#print conn.create_security_group('name', 'description')
54
550
=== removed file 'nova/tests/api_unittest.py'
--- nova/tests/api_unittest.py 2010-07-15 23:13:48 +0000
+++ nova/tests/api_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,199 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import boto
20from boto.ec2 import regioninfo
21import httplib
22import random
23import StringIO
24from tornado import httpserver
25from twisted.internet import defer
26
27from nova import flags
28from nova import test
29from nova.auth import users
30from nova.endpoint import api
31from nova.endpoint import cloud
32
33
34FLAGS = flags.FLAGS
35
36
37# NOTE(termie): These are a bunch of helper methods and classes to short
38# circuit boto calls and feed them into our tornado handlers,
39# it's pretty damn circuitous so apologies if you have to fix
40# a bug in it
41def boto_to_tornado(method, path, headers, data, host, connection=None):
42 """ translate boto requests into tornado requests
43
44 connection should be a FakeTornadoHttpConnection instance
45 """
46 headers = httpserver.HTTPHeaders()
47 for k, v in headers.iteritems():
48 headers[k] = v
49
50 req = httpserver.HTTPRequest(method=method,
51 uri=path,
52 headers=headers,
53 body=data,
54 host=host,
55 remote_ip='127.0.0.1',
56 connection=connection)
57 return req
58
59
60def raw_to_httpresponse(s):
61 """ translate a raw tornado http response into an httplib.HTTPResponse """
62 sock = FakeHttplibSocket(s)
63 resp = httplib.HTTPResponse(sock)
64 resp.begin()
65 return resp
66
67
68class FakeHttplibSocket(object):
69 """ a fake socket implementation for httplib.HTTPResponse, trivial """
70 def __init__(self, s):
71 self.fp = StringIO.StringIO(s)
72
73 def makefile(self, mode, other):
74 return self.fp
75
76
77class FakeTornadoStream(object):
78 """ a fake stream to satisfy tornado's assumptions, trivial """
79 def set_close_callback(self, f):
80 pass
81
82
83class FakeTornadoConnection(object):
84 """ a fake connection object for tornado to pass to its handlers
85
86 web requests are expected to write to this as they get data and call
87 finish when they are done with the request, we buffer the writes and
88 kick off a callback when it is done so that we can feed the result back
89 into boto.
90 """
91 def __init__(self, d):
92 self.d = d
93 self._buffer = StringIO.StringIO()
94
95 def write(self, chunk):
96 self._buffer.write(chunk)
97
98 def finish(self):
99 s = self._buffer.getvalue()
100 self.d.callback(s)
101
102 xheaders = None
103
104 @property
105 def stream(self):
106 return FakeTornadoStream()
107
108
109class FakeHttplibConnection(object):
110 """ a fake httplib.HTTPConnection for boto to use
111
112 requests made via this connection actually get translated and routed into
113 our tornado app, we then wait for the response and turn it back into
114 the httplib.HTTPResponse that boto expects.
115 """
116 def __init__(self, app, host, is_secure=False):
117 self.app = app
118 self.host = host
119 self.deferred = defer.Deferred()
120
121 def request(self, method, path, data, headers):
122 req = boto_to_tornado
123 conn = FakeTornadoConnection(self.deferred)
124 request = boto_to_tornado(connection=conn,
125 method=method,
126 path=path,
127 headers=headers,
128 data=data,
129 host=self.host)
130 handler = self.app(request)
131 self.deferred.addCallback(raw_to_httpresponse)
132
133 def getresponse(self):
134 @defer.inlineCallbacks
135 def _waiter():
136 result = yield self.deferred
137 defer.returnValue(result)
138 d = _waiter()
139 # NOTE(termie): defer.returnValue above should ensure that
140 # this deferred has already been called by the time
141 # we get here, we are going to cheat and return
142 # the result of the callback
143 return d.result
144
145 def close(self):
146 pass
147
148
149class ApiEc2TestCase(test.BaseTestCase):
150 def setUp(self):
151 super(ApiEc2TestCase, self).setUp()
152
153 self.users = users.UserManager.instance()
154 self.cloud = cloud.CloudController()
155
156 self.host = '127.0.0.1'
157
158 self.app = api.APIServerApplication({'Cloud': self.cloud})
159 self.ec2 = boto.connect_ec2(
160 aws_access_key_id='fake',
161 aws_secret_access_key='fake',
162 is_secure=False,
163 region=regioninfo.RegionInfo(None, 'test', self.host),
164 port=FLAGS.cc_port,
165 path='/services/Cloud')
166
167 self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
168
169 def expect_http(self, host=None, is_secure=False):
170 http = FakeHttplibConnection(
171 self.app, '%s:%d' % (self.host, FLAGS.cc_port), False)
172 self.ec2.new_http_connection(host, is_secure).AndReturn(http)
173 return http
174
175 def test_describe_instances(self):
176 self.expect_http()
177 self.mox.ReplayAll()
178 try:
179 self.users.create_user('fake', 'fake', 'fake')
180 except Exception, _err:
181 pass # User may already exist
182 self.assertEqual(self.ec2.get_all_instances(), [])
183 self.users.delete_user('fake')
184
185
186 def test_get_all_key_pairs(self):
187 self.expect_http()
188 self.mox.ReplayAll()
189 keyname = "".join(random.choice("sdiuisudfsdcnpaqwertasd") for x in range(random.randint(4, 8)))
190 try:
191 self.users.create_user('fake', 'fake', 'fake')
192 except Exception, _err:
193 pass # User may already exist
194 self.users.generate_key_pair('fake', keyname)
195
196 rv = self.ec2.get_all_key_pairs()
197 self.assertTrue(filter(lambda k: k.name == keyname, rv))
198 self.users.delete_user('fake')
199
2000
=== removed directory 'nova/tests/bundle'
=== removed file 'nova/tests/bundle/1mb.manifest.xml'
--- nova/tests/bundle/1mb.manifest.xml 2010-05-28 06:05:26 +0000
+++ nova/tests/bundle/1mb.manifest.xml 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
1<?xml version="1.0" ?><manifest><version>2007-10-10</version><bundler><name>euca-tools</name><version>1.2</version><release>31337</release></bundler><machine_configuration><architecture>x86_64</architecture></machine_configuration><image><name>1mb</name><user>42</user><type>machine</type><digest algorithm="SHA1">da39a3ee5e6b4b0d3255bfef95601890afd80709</digest><size>1048576</size><bundled_size>1136</bundled_size><ec2_encrypted_key algorithm="AES-128-CBC">33a2ea00dc64083dd9a10eb5e233635b42a7beb1670ab75452087d9de74c60aba1cd27c136fda56f62beb581de128fb1f10d072b9e556fd25e903107a57827c21f6ee8a93a4ff55b11311fcef217e3eefb07e81f71e88216f43b4b54029c1f2549f2925a839a73947d2d5aeecec4a62ece4af9156d557ae907978298296d9915</ec2_encrypted_key><user_encrypted_key algorithm="AES-128-CBC">4c11147fd8caf92447e90ce339928933d7579244c2f8ffb07cc0ea35f8738da8b90eff6c7a49671a84500e993e9462e4c36d5c19c0b3a2b397d035b4c0cce742b58e12552175d81d129b0425e9f71ebacb9aeb539fa9dd2ac36749fb82876f6902e5fb24b6ec19f35ec4c20acd50437fd30966e99c4d9a0647577970a8fa3023</user_encrypted_key><ec2_encrypted_iv>14bd082c9715f071160c69bbfb070f51d2ba1076775f1d988ccde150e515088156b248e4b5a64e46c4fe064feeeedfe14511f7fde478a51acb89f9b2f6c84b60593e5c3f792ba6b01fed9bf2158fdac03086374883b39d13a3ca74497eeaaf579fc3f26effc73bfd9446a2a8c4061f0874bfaca058905180e22d3d8881551cb3</ec2_encrypted_iv><user_encrypted_iv>8f7606f19f00e4e19535dd234b66b31b77e9c7bad3885d9c9efa75c863631fd4f82a009e17d789066d9cc6032a436f05384832f6d9a3283d3e63eab04fa0da5c8c87db9b17e854e842c3fb416507d067a266b44538125ce732e486098e8ebd1ca91fa3079f007fce7d14957a9b7e57282407ead3c6eb68fe975df3d83190021b</user_encrypted_iv><parts count="2"><part index="0"><filename>1mb.part.0</filename><digest algorithm="SHA1">c4413423cf7a57e71187e19bfd5cd4b514a64283</digest></part><part index="1"><filename>1mb.part.1</filename><digest algorithm="SHA1">9d4262e6589393d09a11a0332af169887bc2e57d</digest></part></parts></image><signature>4e00b5ba28114dda4a9df7eeae94be847ec46117a09a1cbe41e578660642f0660dda1776b39fb3bf826b6cfec019e2a5e9c566728d186b7400ebc989a30670eb1db26ce01e68bd9d3f31290370077a85b81c66b63c1e0d5499bac115c06c17a21a81b6d3a67ebbce6c17019095af7ab07f3796c708cc843e58efc12ddc788c5e</signature></manifest>
2\ No newline at end of file0\ No newline at end of file
31
=== removed file 'nova/tests/bundle/1mb.part.0'
4Binary files nova/tests/bundle/1mb.part.0 2010-05-28 06:05:26 +0000 and nova/tests/bundle/1mb.part.0 1970-01-01 00:00:00 +0000 differ2Binary files nova/tests/bundle/1mb.part.0 2010-05-28 06:05:26 +0000 and nova/tests/bundle/1mb.part.0 1970-01-01 00:00:00 +0000 differ
=== removed file 'nova/tests/bundle/1mb.part.1'
--- nova/tests/bundle/1mb.part.1 2010-05-28 06:05:26 +0000
+++ nova/tests/bundle/1mb.part.1 1970-01-01 00:00:00 +0000
@@ -1,1 +0,0 @@
1­´ˆà«€ç‰°Ƴ
2¡ÀiDHW̽×JÈ8ïrV¼³h§X’·@Yj“~Ø0¡ÀiDHW̽×JÈ8ïrV¼³h§X’·@Yj“~Ø
3·Gû5û 3Nt«˜•H6Ñ$§Ëgö™é Lá¢+³æ¤X†pm¬@,øŽ>7ÚÊ×užp¼ aü`¥V2X@£#á¶1·Gû5û 3Nt«˜•H6Ñ$§Ëgö™é Lá¢+³æ¤X†pm¬@,øŽ>7ÚÊ×užp¼ aü`¥V2X@£#á¶
4\ No newline at end of file2\ No newline at end of file
53
=== removed file 'nova/tests/cloud_unittest.py'
--- nova/tests/cloud_unittest.py 2010-07-15 23:13:48 +0000
+++ nova/tests/cloud_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,163 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import StringIO
21import time
22from tornado import ioloop
23from twisted.internet import defer
24import unittest
25from xml.etree import ElementTree
26
27from nova import flags
28from nova import rpc
29from nova import test
30from nova.auth import users
31from nova.compute import node
32from nova.endpoint import api
33from nova.endpoint import cloud
34
35
36FLAGS = flags.FLAGS
37
38
39class CloudTestCase(test.BaseTestCase):
40 def setUp(self):
41 super(CloudTestCase, self).setUp()
42 self.flags(fake_libvirt=True,
43 fake_storage=True,
44 fake_users=True)
45
46 self.conn = rpc.Connection.instance()
47 logging.getLogger().setLevel(logging.DEBUG)
48
49 # set up our cloud
50 self.cloud = cloud.CloudController()
51 self.cloud_consumer = rpc.AdapterConsumer(connection=self.conn,
52 topic=FLAGS.cloud_topic,
53 proxy=self.cloud)
54 self.injected.append(self.cloud_consumer.attach_to_tornado(self.ioloop))
55
56 # set up a node
57 self.node = node.Node()
58 self.node_consumer = rpc.AdapterConsumer(connection=self.conn,
59 topic=FLAGS.compute_topic,
60 proxy=self.node)
61 self.injected.append(self.node_consumer.attach_to_tornado(self.ioloop))
62
63 try:
64 users.UserManager.instance().create_user('admin', 'admin', 'admin')
65 except: pass
66 admin = users.UserManager.instance().get_user('admin')
67 project = users.UserManager.instance().create_project('proj', 'admin', 'proj')
68 self.context = api.APIRequestContext(handler=None,project=project,user=admin)
69
70 def tearDown(self):
71 users.UserManager.instance().delete_project('proj')
72 users.UserManager.instance().delete_user('admin')
73
74 def test_console_output(self):
75 if FLAGS.fake_libvirt:
76 logging.debug("Can't test instances without a real virtual env.")
77 return
78 instance_id = 'foo'
79 inst = yield self.node.run_instance(instance_id)
80 output = yield self.cloud.get_console_output(self.context, [instance_id])
81 logging.debug(output)
82 self.assert_(output)
83 rv = yield self.node.terminate_instance(instance_id)
84
85 def test_run_instances(self):
86 if FLAGS.fake_libvirt:
87 logging.debug("Can't test instances without a real virtual env.")
88 return
89 image_id = FLAGS.default_image
90 instance_type = FLAGS.default_instance_type
91 max_count = 1
92 kwargs = {'image_id': image_id,
93 'instance_type': instance_type,
94 'max_count': max_count}
95 rv = yield self.cloud.run_instances(self.context, **kwargs)
96 # TODO: check for proper response
97 instance = rv['reservationSet'][0][rv['reservationSet'][0].keys()[0]][0]
98 logging.debug("Need to watch instance %s until it's running..." % instance['instance_id'])
99 while True:
100 rv = yield defer.succeed(time.sleep(1))
101 info = self.cloud._get_instance(instance['instance_id'])
102 logging.debug(info['state'])
103 if info['state'] == node.Instance.RUNNING:
104 break
105 self.assert_(rv)
106
107 if not FLAGS.fake_libvirt:
108 time.sleep(45) # Should use boto for polling here
109 for reservations in rv['reservationSet']:
110 # for res_id in reservations.keys():
111 # logging.debug(reservations[res_id])
112 # for instance in reservations[res_id]:
113 for instance in reservations[reservations.keys()[0]]:
114 logging.debug("Terminating instance %s" % instance['instance_id'])
115 rv = yield self.node.terminate_instance(instance['instance_id'])
116
117 def test_instance_update_state(self):
118 def instance(num):
119 return {
120 'reservation_id': 'r-1',
121 'instance_id': 'i-%s' % num,
122 'image_id': 'ami-%s' % num,
123 'private_dns_name': '10.0.0.%s' % num,
124 'dns_name': '10.0.0%s' % num,
125 'ami_launch_index': str(num),
126 'instance_type': 'fake',
127 'availability_zone': 'fake',
128 'key_name': None,
129 'kernel_id': 'fake',
130 'ramdisk_id': 'fake',
131 'groups': ['default'],
132 'product_codes': None,
133 'state': 0x01,
134 'user_data': ''
135 }
136 rv = self.cloud._format_instances(self.context)
137 self.assert_(len(rv['reservationSet']) == 0)
138
139 # simulate launch of 5 instances
140 # self.cloud.instances['pending'] = {}
141 #for i in xrange(5):
142 # inst = instance(i)
143 # self.cloud.instances['pending'][inst['instance_id']] = inst
144
145 #rv = self.cloud._format_instances(self.admin)
146 #self.assert_(len(rv['reservationSet']) == 1)
147 #self.assert_(len(rv['reservationSet'][0]['instances_set']) == 5)
148 # report 4 nodes each having 1 of the instances
149 #for i in xrange(4):
150 # self.cloud.update_state('instances', {('node-%s' % i): {('i-%s' % i): instance(i)}})
151
152 # one instance should be pending still
153 #self.assert_(len(self.cloud.instances['pending'].keys()) == 1)
154
155 # check that the reservations collapse
156 #rv = self.cloud._format_instances(self.admin)
157 #self.assert_(len(rv['reservationSet']) == 1)
158 #self.assert_(len(rv['reservationSet'][0]['instances_set']) == 5)
159
160 # check that we can get metadata for each instance
161 #for i in xrange(4):
162 # data = self.cloud.get_metadata(instance(i)['private_dns_name'])
163 # self.assert_(data['meta-data']['ami-id'] == 'ami-%s' % i)
1640
=== removed file 'nova/tests/fake_flags.py'
--- nova/tests/fake_flags.py 2010-07-15 15:52:11 +0000
+++ nova/tests/fake_flags.py 1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19from nova import flags
20
21FLAGS = flags.FLAGS
22
23FLAGS.fake_libvirt = True
24FLAGS.fake_storage = True
25FLAGS.fake_rabbit = True
26FLAGS.fake_network = True
27FLAGS.fake_users = True
28FLAGS.verbose = True
290
=== removed file 'nova/tests/future_unittest.py'
--- nova/tests/future_unittest.py 2010-07-15 23:13:48 +0000
+++ nova/tests/future_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,75 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import mox
21import StringIO
22import time
23from tornado import ioloop
24from twisted.internet import defer
25import unittest
26from xml.etree import ElementTree
27
28from nova import cloud
29from nova import exception
30from nova import flags
31from nova import node
32from nova import rpc
33from nova import test
34
35
36FLAGS = flags.FLAGS
37
38
39class AdminTestCase(test.BaseTestCase):
40 def setUp(self):
41 super(AdminTestCase, self).setUp()
42 self.flags(fake_libvirt=True,
43 fake_rabbit=True)
44
45 self.conn = rpc.Connection.instance()
46
47 logging.getLogger().setLevel(logging.INFO)
48
49 # set up our cloud
50 self.cloud = cloud.CloudController()
51 self.cloud_consumer = rpc.AdapterConsumer(connection=self.conn,
52 topic=FLAGS.cloud_topic,
53 proxy=self.cloud)
54 self.injected.append(self.cloud_consumer.attach_to_tornado(self.ioloop))
55
56 # set up a node
57 self.node = node.Node()
58 self.node_consumer = rpc.AdapterConsumer(connection=self.conn,
59 topic=FLAGS.compute_topic,
60 proxy=self.node)
61 self.injected.append(self.node_consumer.attach_to_tornado(self.ioloop))
62
63 def test_flush_terminated(self):
64 # Launch an instance
65
66 # Wait until it's running
67
68 # Terminate it
69
70 # Wait until it's terminated
71
72 # Flush terminated nodes
73
74 # ASSERT that it's gone
75 pass
760
=== removed file 'nova/tests/model_unittest.py'
--- nova/tests/model_unittest.py 2010-07-15 23:13:48 +0000
+++ nova/tests/model_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,206 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import time
21from twisted.internet import defer
22
23from nova import exception
24from nova import flags
25from nova import test
26from nova import utils
27from nova.compute import model
28from nova.compute import node
29
30
31FLAGS = flags.FLAGS
32
33
34class ModelTestCase(test.TrialTestCase):
35 def setUp(self):
36 super(ModelTestCase, self).setUp()
37 self.flags(fake_libvirt=True,
38 fake_storage=True,
39 fake_users=True)
40
41 def tearDown(self):
42 model.Instance('i-test').destroy()
43 model.Host('testhost').destroy()
44 model.Daemon('testhost', 'nova-testdaemon').destroy()
45
46 def create_instance(self):
47 inst = model.Instance('i-test')
48 inst['reservation_id'] = 'r-test'
49 inst['launch_time'] = '10'
50 inst['user_id'] = 'fake'
51 inst['project_id'] = 'fake'
52 inst['instance_type'] = 'm1.tiny'
53 inst['node_name'] = FLAGS.node_name
54 inst['mac_address'] = utils.generate_mac()
55 inst['ami_launch_index'] = 0
56 inst.save()
57 return inst
58
59 def create_host(self):
60 host = model.Host('testhost')
61 host.save()
62 return host
63
64 def create_daemon(self):
65 daemon = model.Daemon('testhost', 'nova-testdaemon')
66 daemon.save()
67 return daemon
68
69 @defer.inlineCallbacks
70 def test_create_instance(self):
71 """store with create_instace, then test that a load finds it"""
72 instance = yield self.create_instance()
73 old = yield model.Instance(instance.identifier)
74 self.assertFalse(old.is_new_record())
75
76 @defer.inlineCallbacks
77 def test_delete_instance(self):
78 """create, then destroy, then make sure loads a new record"""
79 instance = yield self.create_instance()
80 yield instance.destroy()
81 newinst = yield model.Instance('i-test')
82 self.assertTrue(newinst.is_new_record())
83
84 @defer.inlineCallbacks
85 def test_instance_added_to_set(self):
86 """create, then check that it is listed for the project"""
87 instance = yield self.create_instance()
88 found = False
89 for x in model.InstanceDirectory().all:
90 if x.identifier == 'i-test':
91 found = True
92 self.assert_(found)
93
94 @defer.inlineCallbacks
95 def test_instance_associates_project(self):
96 """create, then check that it is listed for the project"""
97 instance = yield self.create_instance()
98 found = False
99 for x in model.InstanceDirectory().by_project(instance.project):
100 if x.identifier == 'i-test':
101 found = True
102 self.assert_(found)
103
104 @defer.inlineCallbacks
105 def test_host_class_finds_hosts(self):
106 host = yield self.create_host()
107 self.assertEqual('testhost', model.Host.lookup('testhost').identifier)
108
109 @defer.inlineCallbacks
110 def test_host_class_doesnt_find_missing_hosts(self):
111 rv = yield model.Host.lookup('woahnelly')
112 self.assertEqual(None, rv)
113
114 @defer.inlineCallbacks
115 def test_create_host(self):
116 """store with create_host, then test that a load finds it"""
117 host = yield self.create_host()
118 old = yield model.Host(host.identifier)
119 self.assertFalse(old.is_new_record())
120
121 @defer.inlineCallbacks
122 def test_delete_host(self):
123 """create, then destroy, then make sure loads a new record"""
124 instance = yield self.create_host()
125 yield instance.destroy()
126 newinst = yield model.Host('testhost')
127 self.assertTrue(newinst.is_new_record())
128
129 @defer.inlineCallbacks
130 def test_host_added_to_set(self):
131 """create, then check that it is included in list"""
132 instance = yield self.create_host()
133 found = False
134 for x in model.Host.all():
135 if x.identifier == 'testhost':
136 found = True
137 self.assert_(found)
138
139 @defer.inlineCallbacks
140 def test_create_daemon_two_args(self):
141 """create a daemon with two arguments"""
142 d = yield self.create_daemon()
143 d = model.Daemon('testhost', 'nova-testdaemon')
144 self.assertFalse(d.is_new_record())
145
146 @defer.inlineCallbacks
147 def test_create_daemon_single_arg(self):
148 """Create a daemon using the combined host:bin format"""
149 d = yield model.Daemon("testhost:nova-testdaemon")
150 d.save()
151 d = model.Daemon('testhost:nova-testdaemon')
152 self.assertFalse(d.is_new_record())
153
154 @defer.inlineCallbacks
155 def test_equality_of_daemon_single_and_double_args(self):
156 """Create a daemon using the combined host:bin arg, find with 2"""
157 d = yield model.Daemon("testhost:nova-testdaemon")
158 d.save()
159 d = model.Daemon('testhost', 'nova-testdaemon')
160 self.assertFalse(d.is_new_record())
161
162 @defer.inlineCallbacks
163 def test_equality_daemon_of_double_and_single_args(self):
164 """Create a daemon using the combined host:bin arg, find with 2"""
165 d = yield self.create_daemon()
166 d = model.Daemon('testhost:nova-testdaemon')
167 self.assertFalse(d.is_new_record())
168
169 @defer.inlineCallbacks
170 def test_delete_daemon(self):
171 """create, then destroy, then make sure loads a new record"""
172 instance = yield self.create_daemon()
173 yield instance.destroy()
174 newinst = yield model.Daemon('testhost', 'nova-testdaemon')
175 self.assertTrue(newinst.is_new_record())
176
177 @defer.inlineCallbacks
178 def test_daemon_heartbeat(self):
179 """Create a daemon, sleep, heartbeat, check for update"""
180 d = yield self.create_daemon()
181 ts = d['updated_at']
182 time.sleep(2)
183 d.heartbeat()
184 d2 = model.Daemon('testhost', 'nova-testdaemon')
185 ts2 = d2['updated_at']
186 self.assert_(ts2 > ts)
187
188 @defer.inlineCallbacks
189 def test_daemon_added_to_set(self):
190 """create, then check that it is included in list"""
191 instance = yield self.create_daemon()
192 found = False
193 for x in model.Daemon.all():
194 if x.identifier == 'testhost:nova-testdaemon':
195 found = True
196 self.assert_(found)
197
198 @defer.inlineCallbacks
199 def test_daemon_associates_host(self):
200 """create, then check that it is listed for the host"""
201 instance = yield self.create_daemon()
202 found = False
203 for x in model.Daemon.by_host('testhost'):
204 if x.identifier == 'testhost:nova-testdaemon':
205 found = True
206 self.assertTrue(found)
2070
=== removed file 'nova/tests/network_unittest.py'
--- nova/tests/network_unittest.py 2010-07-21 02:57:31 +0000
+++ nova/tests/network_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,219 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import IPy
20import os
21import logging
22
23from nova import flags
24from nova import test
25from nova import utils
26from nova.auth import users
27from nova.compute import network
28from nova.compute.exception import NoMoreAddresses
29
30FLAGS = flags.FLAGS
31
32class NetworkTestCase(test.TrialTestCase):
33 def setUp(self):
34 super(NetworkTestCase, self).setUp()
35 self.flags(fake_libvirt=True,
36 fake_storage=True,
37 fake_network=True,
38 network_size=32)
39 logging.getLogger().setLevel(logging.DEBUG)
40 self.manager = users.UserManager.instance()
41 self.dnsmasq = FakeDNSMasq()
42 try:
43 self.manager.create_user('netuser', 'netuser', 'netuser')
44 except: pass
45 for i in range(0, 6):
46 name = 'project%s' % i
47 if not self.manager.get_project(name):
48 self.manager.create_project(name, 'netuser', name)
49 self.network = network.PublicNetworkController()
50
51 def tearDown(self):
52 super(NetworkTestCase, self).tearDown()
53 for i in range(0, 6):
54 name = 'project%s' % i
55 self.manager.delete_project(name)
56 self.manager.delete_user('netuser')
57
58 def test_public_network_allocation(self):
59 pubnet = IPy.IP(flags.FLAGS.public_range)
60 address = self.network.allocate_ip("netuser", "project0", "public")
61 self.assertTrue(IPy.IP(address) in pubnet)
62 self.assertTrue(IPy.IP(address) in self.network.network)
63
64 def test_allocate_deallocate_ip(self):
65 address = network.allocate_ip(
66 "netuser", "project0", utils.generate_mac())
67 logging.debug("Was allocated %s" % (address))
68 net = network.get_project_network("project0", "default")
69 self.assertEqual(True, is_in_project(address, "project0"))
70 mac = utils.generate_mac()
71 hostname = "test-host"
72 self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name)
73 rv = network.deallocate_ip(address)
74
75 # Doesn't go away until it's dhcp released
76 self.assertEqual(True, is_in_project(address, "project0"))
77
78 self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
79 self.assertEqual(False, is_in_project(address, "project0"))
80
81 def test_range_allocation(self):
82 mac = utils.generate_mac()
83 secondmac = utils.generate_mac()
84 hostname = "test-host"
85 address = network.allocate_ip(
86 "netuser", "project0", mac)
87 secondaddress = network.allocate_ip(
88 "netuser", "project1", secondmac)
89 net = network.get_project_network("project0", "default")
90 secondnet = network.get_project_network("project1", "default")
91
92 self.assertEqual(True, is_in_project(address, "project0"))
93 self.assertEqual(True, is_in_project(secondaddress, "project1"))
94 self.assertEqual(False, is_in_project(address, "project1"))
95
96 # Addresses are allocated before they're issued
97 self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name)
98 self.dnsmasq.issue_ip(secondmac, secondaddress,
99 hostname, secondnet.bridge_name)
100
101 rv = network.deallocate_ip(address)
102 self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
103 self.assertEqual(False, is_in_project(address, "project0"))
104
105 # First address release shouldn't affect the second
106 self.assertEqual(True, is_in_project(secondaddress, "project1"))
107
108 rv = network.deallocate_ip(secondaddress)
109 self.dnsmasq.release_ip(secondmac, secondaddress,
110 hostname, secondnet.bridge_name)
111 self.assertEqual(False, is_in_project(secondaddress, "project1"))
112
113 def test_subnet_edge(self):
114 secondaddress = network.allocate_ip("netuser", "project0",
115 utils.generate_mac())
116 hostname = "toomany-hosts"
117 for project in range(1,5):
118 project_id = "project%s" % (project)
119 mac = utils.generate_mac()
120 mac2 = utils.generate_mac()
121 mac3 = utils.generate_mac()
122 address = network.allocate_ip(
123 "netuser", project_id, mac)
124 address2 = network.allocate_ip(
125 "netuser", project_id, mac2)
126 address3 = network.allocate_ip(
127 "netuser", project_id, mac3)
128 self.assertEqual(False, is_in_project(address, "project0"))
129 self.assertEqual(False, is_in_project(address2, "project0"))
130 self.assertEqual(False, is_in_project(address3, "project0"))
131 rv = network.deallocate_ip(address)
132 rv = network.deallocate_ip(address2)
133 rv = network.deallocate_ip(address3)
134 net = network.get_project_network(project_id, "default")
135 self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
136 self.dnsmasq.release_ip(mac2, address2, hostname, net.bridge_name)
137 self.dnsmasq.release_ip(mac3, address3, hostname, net.bridge_name)
138 net = network.get_project_network("project0", "default")
139 rv = network.deallocate_ip(secondaddress)
140 self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
141
142 def test_release_before_deallocate(self):
143 pass
144
145 def test_deallocate_before_issued(self):
146 pass
147
148 def test_too_many_addresses(self):
149 """
150 Here, we test that a proper NoMoreAddresses exception is raised.
151
152 However, the number of available IP addresses depends on the test
153 environment's setup.
154
155 Network size is set in test fixture's setUp method.
156
157 There are FLAGS.cnt_vpn_clients addresses reserved for VPN (NUM_RESERVED_VPN_IPS)
158
159 And there are NUM_STATIC_IPS that are always reserved by Nova for the necessary
160 services (gateway, CloudPipe, etc)
161
162 So we should get flags.network_size - (NUM_STATIC_IPS +
163 NUM_PREALLOCATED_IPS +
164 NUM_RESERVED_VPN_IPS)
165 usable addresses
166 """
167 net = network.get_project_network("project0", "default")
168
169 # Determine expected number of available IP addresses
170 num_static_ips = net.num_static_ips
171 num_preallocated_ips = len(net.hosts.keys())
172 num_reserved_vpn_ips = flags.FLAGS.cnt_vpn_clients
173 num_available_ips = flags.FLAGS.network_size - (num_static_ips + num_preallocated_ips + num_reserved_vpn_ips)
174
175 hostname = "toomany-hosts"
176 macs = {}
177 addresses = {}
178 for i in range(0, (num_available_ips - 1)):
179 macs[i] = utils.generate_mac()
180 addresses[i] = network.allocate_ip("netuser", "project0", macs[i])
181 self.dnsmasq.issue_ip(macs[i], addresses[i], hostname, net.bridge_name)
182
183 self.assertRaises(NoMoreAddresses, network.allocate_ip, "netuser", "project0", utils.generate_mac())
184
185 for i in range(0, (num_available_ips - 1)):
186 rv = network.deallocate_ip(addresses[i])
187 self.dnsmasq.release_ip(macs[i], addresses[i], hostname, net.bridge_name)
188
189def is_in_project(address, project_id):
190 return address in network.get_project_network(project_id).list_addresses()
191
192def _get_project_addresses(project_id):
193 project_addresses = []
194 for addr in network.get_project_network(project_id).list_addresses():
195 project_addresses.append(addr)
196 return project_addresses
197
198def binpath(script):
199 return os.path.abspath(os.path.join(__file__, "../../../bin", script))
200
201class FakeDNSMasq(object):
202 def issue_ip(self, mac, ip, hostname, interface):
203 cmd = "%s add %s %s %s" % (binpath('nova-dhcpbridge'),
204 mac, ip, hostname)
205 env = {'DNSMASQ_INTERFACE': interface,
206 'TESTING' : '1',
207 'FLAGFILE' : FLAGS.dhcpbridge_flagfile}
208 (out, err) = utils.execute(cmd, addl_env=env)
209 logging.debug("ISSUE_IP: %s, %s " % (out, err))
210
211 def release_ip(self, mac, ip, hostname, interface):
212 cmd = "%s del %s %s %s" % (binpath('nova-dhcpbridge'),
213 mac, ip, hostname)
214 env = {'DNSMASQ_INTERFACE': interface,
215 'TESTING' : '1',
216 'FLAGFILE' : FLAGS.dhcpbridge_flagfile}
217 (out, err) = utils.execute(cmd, addl_env=env)
218 logging.debug("RELEASE_IP: %s, %s " % (out, err))
219
2200
=== removed file 'nova/tests/node_unittest.py'
--- nova/tests/node_unittest.py 2010-07-15 23:13:48 +0000
+++ nova/tests/node_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,128 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import time
21from twisted.internet import defer
22from xml.etree import ElementTree
23
24from nova import exception
25from nova import flags
26from nova import test
27from nova import utils
28from nova.compute import model
29from nova.compute import node
30
31
32FLAGS = flags.FLAGS
33
34
35class InstanceXmlTestCase(test.TrialTestCase):
36 # @defer.inlineCallbacks
37 def test_serialization(self):
38 # TODO: Reimplement this, it doesn't make sense in redis-land
39 return
40
41 # instance_id = 'foo'
42 # first_node = node.Node()
43 # inst = yield first_node.run_instance(instance_id)
44 #
45 # # force the state so that we can verify that it changes
46 # inst._s['state'] = node.Instance.NOSTATE
47 # xml = inst.toXml()
48 # self.assert_(ElementTree.parse(StringIO.StringIO(xml)))
49 #
50 # second_node = node.Node()
51 # new_inst = node.Instance.fromXml(second_node._conn, pool=second_node._pool, xml=xml)
52 # self.assertEqual(new_inst.state, node.Instance.RUNNING)
53 # rv = yield first_node.terminate_instance(instance_id)
54
55
56class NodeConnectionTestCase(test.TrialTestCase):
57 def setUp(self):
58 logging.getLogger().setLevel(logging.DEBUG)
59 super(NodeConnectionTestCase, self).setUp()
60 self.flags(fake_libvirt=True,
61 fake_storage=True,
62 fake_users=True)
63 self.node = node.Node()
64
65 def create_instance(self):
66 instdir = model.InstanceDirectory()
67 inst = instdir.new()
68 # TODO(ja): add ami, ari, aki, user_data
69 inst['reservation_id'] = 'r-fakeres'
70 inst['launch_time'] = '10'
71 inst['user_id'] = 'fake'
72 inst['project_id'] = 'fake'
73 inst['instance_type'] = 'm1.tiny'
74 inst['node_name'] = FLAGS.node_name
75 inst['mac_address'] = utils.generate_mac()
76 inst['ami_launch_index'] = 0
77 inst.save()
78 return inst['instance_id']
79
80 @defer.inlineCallbacks
81 def test_run_describe_terminate(self):
82 instance_id = self.create_instance()
83
84 rv = yield self.node.run_instance(instance_id)
85
86 rv = yield self.node.describe_instances()
87 logging.info("Running instances: %s", rv)
88 self.assertEqual(rv[instance_id].name, instance_id)
89
90 rv = yield self.node.terminate_instance(instance_id)
91
92 rv = yield self.node.describe_instances()
93 logging.info("After terminating instances: %s", rv)
94 self.assertEqual(rv, {})
95
96 @defer.inlineCallbacks
97 def test_reboot(self):
98 instance_id = self.create_instance()
99 rv = yield self.node.run_instance(instance_id)
100
101 rv = yield self.node.describe_instances()
102 self.assertEqual(rv[instance_id].name, instance_id)
103
104 yield self.node.reboot_instance(instance_id)
105
106 rv = yield self.node.describe_instances()
107 self.assertEqual(rv[instance_id].name, instance_id)
108 rv = yield self.node.terminate_instance(instance_id)
109
110 @defer.inlineCallbacks
111 def test_console_output(self):
112 instance_id = self.create_instance()
113 rv = yield self.node.run_instance(instance_id)
114
115 console = yield self.node.get_console_output(instance_id)
116 self.assert_(console)
117 rv = yield self.node.terminate_instance(instance_id)
118
119 @defer.inlineCallbacks
120 def test_run_instance_existing(self):
121 instance_id = self.create_instance()
122 rv = yield self.node.run_instance(instance_id)
123
124 rv = yield self.node.describe_instances()
125 self.assertEqual(rv[instance_id].name, instance_id)
126
127 self.assertRaises(exception.Error, self.node.run_instance, instance_id)
128 rv = yield self.node.terminate_instance(instance_id)
1290
=== removed file 'nova/tests/objectstore_unittest.py'
--- nova/tests/objectstore_unittest.py 2010-07-15 23:13:48 +0000
+++ nova/tests/objectstore_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,203 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import glob
20import hashlib
21import logging
22import os
23import shutil
24import tempfile
25
26from nova import flags
27from nova import objectstore
28from nova import test
29from nova.auth import users
30
31
32FLAGS = flags.FLAGS
33
34oss_tempdir = tempfile.mkdtemp(prefix='test_oss-')
35
36
37# delete tempdirs from previous runs (we don't delete after test to allow
38# checking the contents after running tests)
39# TODO: This fails on the test box with a permission denied error
40# Also, doing these things in a global tempdir means that different runs of
41# the test suite on the same box could clobber each other.
42#for path in glob.glob(os.path.abspath(os.path.join(oss_tempdir, '../test_oss-*'))):
43# if path != oss_tempdir:
44# shutil.rmtree(path)
45
46
47# create bucket/images path
48os.makedirs(os.path.join(oss_tempdir, 'images'))
49os.makedirs(os.path.join(oss_tempdir, 'buckets'))
50
51class ObjectStoreTestCase(test.BaseTestCase):
52 def setUp(self):
53 super(ObjectStoreTestCase, self).setUp()
54 self.flags(fake_users=True,
55 buckets_path=os.path.join(oss_tempdir, 'buckets'),
56 images_path=os.path.join(oss_tempdir, 'images'),
57 ca_path=os.path.join(os.path.dirname(__file__), 'CA'))
58 logging.getLogger().setLevel(logging.DEBUG)
59
60 self.um = users.UserManager.instance()
61 try:
62 self.um.create_user('user1')
63 except: pass
64 try:
65 self.um.create_user('user2')
66 except: pass
67 try:
68 self.um.create_user('admin_user', admin=True)
69 except: pass
70 try:
71 self.um.create_project('proj1', 'user1', 'a proj', ['user1'])
72 except: pass
73 try:
74 self.um.create_project('proj2', 'user2', 'a proj', ['user2'])
75 except: pass
76 class Context(object): pass
77 self.context = Context()
78
79 def tearDown(self):
80 self.um.delete_project('proj1')
81 self.um.delete_project('proj2')
82 self.um.delete_user('user1')
83 self.um.delete_user('user2')
84 self.um.delete_user('admin_user')
85 super(ObjectStoreTestCase, self).tearDown()
86
87 def test_buckets(self):
88 self.context.user = self.um.get_user('user1')
89 self.context.project = self.um.get_project('proj1')
90 objectstore.bucket.Bucket.create('new_bucket', self.context)
91 bucket = objectstore.bucket.Bucket('new_bucket')
92
93 # creator is authorized to use bucket
94 self.assert_(bucket.is_authorized(self.context))
95
96 # another user is not authorized
97 self.context.user = self.um.get_user('user2')
98 self.context.project = self.um.get_project('proj2')
99 self.assert_(bucket.is_authorized(self.context) == False)
100
101 # admin is authorized to use bucket
102 self.context.user = self.um.get_user('admin_user')
103 self.context.project = None
104 self.assert_(bucket.is_authorized(self.context))
105
106 # new buckets are empty
107 self.assert_(bucket.list_keys()['Contents'] == [])
108
109 # storing keys works
110 bucket['foo'] = "bar"
111
112 self.assert_(len(bucket.list_keys()['Contents']) == 1)
113
114 self.assert_(bucket['foo'].read() == 'bar')
115
116 # md5 of key works
117 self.assert_(bucket['foo'].md5 == hashlib.md5('bar').hexdigest())
118
119 # deleting non-empty bucket throws exception
120 exception = False
121 try:
122 bucket.delete()
123 except:
124 exception = True
125
126 self.assert_(exception)
127
128 # deleting key
129 del bucket['foo']
130
131 # deleting empty button
132 bucket.delete()
133
134 # accessing deleted bucket throws exception
135 exception = False
136 try:
137 objectstore.bucket.Bucket('new_bucket')
138 except:
139 exception = True
140
141 self.assert_(exception)
142
143 def test_images(self):
144 self.context.user = self.um.get_user('user1')
145 self.context.project = self.um.get_project('proj1')
146
147 # create a bucket for our bundle
148 objectstore.bucket.Bucket.create('image_bucket', self.context)
149 bucket = objectstore.bucket.Bucket('image_bucket')
150
151 # upload an image manifest/parts
152 bundle_path = os.path.join(os.path.dirname(__file__), 'bundle')
153 for path in glob.glob(bundle_path + '/*'):
154 bucket[os.path.basename(path)] = open(path, 'rb').read()
155
156 # register an image
157 objectstore.image.Image.register_aws_image('i-testing', 'image_bucket/1mb.manifest.xml', self.context)
158
159 # verify image
160 my_img = objectstore.image.Image('i-testing')
161 result_image_file = os.path.join(my_img.path, 'image')
162 self.assertEqual(os.stat(result_image_file).st_size, 1048576)
163
164 sha = hashlib.sha1(open(result_image_file).read()).hexdigest()
165 self.assertEqual(sha, '3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3')
166
167 # verify image permissions
168 self.context.user = self.um.get_user('user2')
169 self.context.project = self.um.get_project('proj2')
170 self.assert_(my_img.is_authorized(self.context) == False)
171
172# class ApiObjectStoreTestCase(test.BaseTestCase):
173# def setUp(self):
174# super(ApiObjectStoreTestCase, self).setUp()
175# FLAGS.fake_users = True
176# FLAGS.buckets_path = os.path.join(tempdir, 'buckets')
177# FLAGS.images_path = os.path.join(tempdir, 'images')
178# FLAGS.ca_path = os.path.join(os.path.dirname(__file__), 'CA')
179#
180# self.users = users.UserManager.instance()
181# self.app = handler.Application(self.users)
182#
183# self.host = '127.0.0.1'
184#
185# self.conn = boto.s3.connection.S3Connection(
186# aws_access_key_id=user.access,
187# aws_secret_access_key=user.secret,
188# is_secure=False,
189# calling_format=boto.s3.connection.OrdinaryCallingFormat(),
190# port=FLAGS.s3_port,
191# host=FLAGS.s3_host)
192#
193# self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
194#
195# def tearDown(self):
196# FLAGS.Reset()
197# super(ApiObjectStoreTestCase, self).tearDown()
198#
199# def test_describe_instances(self):
200# self.expect_http()
201# self.mox.ReplayAll()
202#
203# self.assertEqual(self.ec2.get_all_instances(), [])
2040
=== removed file 'nova/tests/process_unittest.py'
--- nova/tests/process_unittest.py 2010-07-16 19:12:36 +0000
+++ nova/tests/process_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,122 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20from twisted.internet import defer
21from twisted.internet import reactor
22from xml.etree import ElementTree
23
24from nova import exception
25from nova import flags
26from nova import process
27from nova import test
28from nova import utils
29
30FLAGS = flags.FLAGS
31
32
33class ProcessTestCase(test.TrialTestCase):
34 def setUp(self):
35 logging.getLogger().setLevel(logging.DEBUG)
36 super(ProcessTestCase, self).setUp()
37
38 def test_execute_stdout(self):
39 pool = process.ProcessPool(2)
40 d = pool.simple_execute('echo test')
41 def _check(rv):
42 self.assertEqual(rv[0], 'test\n')
43 self.assertEqual(rv[1], '')
44
45 d.addCallback(_check)
46 d.addErrback(self.fail)
47 return d
48
49 def test_execute_stderr(self):
50 pool = process.ProcessPool(2)
51 d = pool.simple_execute('cat BAD_FILE', error_ok=1)
52 def _check(rv):
53 self.assertEqual(rv[0], '')
54 self.assert_('No such file' in rv[1])
55
56 d.addCallback(_check)
57 d.addErrback(self.fail)
58 return d
59
60 def test_execute_unexpected_stderr(self):
61 pool = process.ProcessPool(2)
62 d = pool.simple_execute('cat BAD_FILE')
63 d.addCallback(lambda x: self.fail('should have raised an error'))
64 d.addErrback(lambda failure: failure.trap(IOError))
65 return d
66
67 def test_max_processes(self):
68 pool = process.ProcessPool(2)
69 d1 = pool.simple_execute('sleep 0.01')
70 d2 = pool.simple_execute('sleep 0.01')
71 d3 = pool.simple_execute('sleep 0.005')
72 d4 = pool.simple_execute('sleep 0.005')
73
74 called = []
75 def _called(rv, name):
76 called.append(name)
77
78 d1.addCallback(_called, 'd1')
79 d2.addCallback(_called, 'd2')
80 d3.addCallback(_called, 'd3')
81 d4.addCallback(_called, 'd4')
82
83 # Make sure that d3 and d4 had to wait on the other two and were called
84 # in order
85 # NOTE(termie): there may be a race condition in this test if for some
86 # reason one of the sleeps takes longer to complete
87 # than it should
88 d4.addCallback(lambda x: self.assertEqual(called[2], 'd3'))
89 d4.addCallback(lambda x: self.assertEqual(called[3], 'd4'))
90 d4.addErrback(self.fail)
91 return d4
92
93 def test_kill_long_process(self):
94 pool = process.ProcessPool(2)
95
96 d1 = pool.simple_execute('sleep 1')
97 d2 = pool.simple_execute('sleep 0.005')
98
99 timeout = reactor.callLater(0.1, self.fail, 'should have been killed')
100
101 # kill d1 and wait on it to end then cancel the timeout
102 d2.addCallback(lambda _: d1.process.signalProcess('KILL'))
103 d2.addCallback(lambda _: d1)
104 d2.addBoth(lambda _: timeout.active() and timeout.cancel())
105 d2.addErrback(self.fail)
106 return d2
107
108 def test_process_exit_is_contained(self):
109 pool = process.ProcessPool(2)
110
111 d1 = pool.simple_execute('sleep 1')
112 d1.addCallback(lambda x: self.fail('should have errbacked'))
113 d1.addErrback(lambda fail: fail.trap(IOError))
114 reactor.callLater(0.05, d1.process.signalProcess, 'KILL')
115
116 return d1
117
118 def test_shared_pool_is_singleton(self):
119 pool1 = process.SharedPool()
120 pool2 = process.SharedPool()
121 self.assert_(id(pool1) == id(pool2))
122
1230
=== removed file 'nova/tests/real_flags.py'
--- nova/tests/real_flags.py 2010-07-15 15:52:11 +0000
+++ nova/tests/real_flags.py 1970-01-01 00:00:00 +0000
@@ -1,28 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19from nova import flags
20
21FLAGS = flags.FLAGS
22
23FLAGS.fake_libvirt = False
24FLAGS.fake_storage = False
25FLAGS.fake_rabbit = False
26FLAGS.fake_network = False
27FLAGS.fake_users = False
28FLAGS.verbose = False
290
=== removed file 'nova/tests/storage_unittest.py'
--- nova/tests/storage_unittest.py 2010-07-15 23:16:09 +0000
+++ nova/tests/storage_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,115 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20
21from nova import exception
22from nova import flags
23from nova import test
24from nova.compute import node
25from nova.volume import storage
26
27
28FLAGS = flags.FLAGS
29
30
31class StorageTestCase(test.TrialTestCase):
32 def setUp(self):
33 logging.getLogger().setLevel(logging.DEBUG)
34 super(StorageTestCase, self).setUp()
35 self.mynode = node.Node()
36 self.mystorage = None
37 self.flags(fake_libvirt=True,
38 fake_storage=True)
39 self.mystorage = storage.BlockStore()
40
41 def test_run_create_volume(self):
42 vol_size = '0'
43 user_id = 'fake'
44 project_id = 'fake'
45 volume_id = self.mystorage.create_volume(vol_size, user_id, project_id)
46 # TODO(termie): get_volume returns differently than create_volume
47 self.assertEqual(volume_id,
48 storage.get_volume(volume_id)['volume_id'])
49
50 rv = self.mystorage.delete_volume(volume_id)
51 self.assertRaises(exception.Error,
52 storage.get_volume,
53 volume_id)
54
55 def test_too_big_volume(self):
56 vol_size = '1001'
57 user_id = 'fake'
58 project_id = 'fake'
59 self.assertRaises(TypeError,
60 self.mystorage.create_volume,
61 vol_size, user_id, project_id)
62
63 def test_too_many_volumes(self):
64 vol_size = '1'
65 user_id = 'fake'
66 project_id = 'fake'
67 num_shelves = FLAGS.last_shelf_id - FLAGS.first_shelf_id + 1
68 total_slots = FLAGS.slots_per_shelf * num_shelves
69 vols = []
70 for i in xrange(total_slots):
71 vid = self.mystorage.create_volume(vol_size, user_id, project_id)
72 vols.append(vid)
73 self.assertRaises(storage.NoMoreVolumes,
74 self.mystorage.create_volume,
75 vol_size, user_id, project_id)
76 for id in vols:
77 self.mystorage.delete_volume(id)
78
79 def test_run_attach_detach_volume(self):
80 # Create one volume and one node to test with
81 instance_id = "storage-test"
82 vol_size = "5"
83 user_id = "fake"
84 project_id = 'fake'
85 mountpoint = "/dev/sdf"
86 volume_id = self.mystorage.create_volume(vol_size, user_id, project_id)
87
88 volume_obj = storage.get_volume(volume_id)
89 volume_obj.start_attach(instance_id, mountpoint)
90 rv = yield self.mynode.attach_volume(volume_id,
91 instance_id,
92 mountpoint)
93 self.assertEqual(volume_obj['status'], "in-use")
94 self.assertEqual(volume_obj['attachStatus'], "attached")
95 self.assertEqual(volume_obj['instance_id'], instance_id)
96 self.assertEqual(volume_obj['mountpoint'], mountpoint)
97
98 self.assertRaises(exception.Error,
99 self.mystorage.delete_volume,
100 volume_id)
101
102 rv = yield self.mystorage.detach_volume(volume_id)
103 volume_obj = storage.get_volume(volume_id)
104 self.assertEqual(volume_obj['status'], "available")
105
106 rv = self.mystorage.delete_volume(volume_id)
107 self.assertRaises(exception.Error,
108 storage.get_volume,
109 volume_id)
110
111 def test_multi_node(self):
112 # TODO(termie): Figure out how to test with two nodes,
113 # each of them having a different FLAG for storage_node
114 # This will allow us to test cross-node interactions
115 pass
1160
=== removed file 'nova/tests/users_unittest.py'
--- nova/tests/users_unittest.py 2010-07-15 23:13:48 +0000
+++ nova/tests/users_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,207 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20from M2Crypto import BIO
21from M2Crypto import RSA
22from M2Crypto import X509
23import unittest
24
25from nova import crypto
26from nova import flags
27from nova import test
28from nova.auth import users
29from nova.endpoint import cloud
30
31FLAGS = flags.FLAGS
32
33
34class UserTestCase(test.BaseTestCase):
35 flush_db = False
36 def setUp(self):
37 super(UserTestCase, self).setUp()
38 self.flags(fake_libvirt=True,
39 fake_storage=True)
40 self.users = users.UserManager.instance()
41
42 def test_001_can_create_users(self):
43 self.users.create_user('test1', 'access', 'secret')
44 self.users.create_user('test2')
45
46 def test_002_can_get_user(self):
47 user = self.users.get_user('test1')
48
49 def test_003_can_retreive_properties(self):
50 user = self.users.get_user('test1')
51 self.assertEqual('test1', user.id)
52 self.assertEqual('access', user.access)
53 self.assertEqual('secret', user.secret)
54
55 def test_004_signature_is_valid(self):
56 #self.assertTrue(self.users.authenticate( **boto.generate_url ... ? ? ? ))
57 pass
58 #raise NotImplementedError
59
60 def test_005_can_get_credentials(self):
61 return
62 credentials = self.users.get_user('test1').get_credentials()
63 self.assertEqual(credentials,
64 'export EC2_ACCESS_KEY="access"\n' +
65 'export EC2_SECRET_KEY="secret"\n' +
66 'export EC2_URL="http://127.0.0.1:8773/services/Cloud"\n' +
67 'export S3_URL="http://127.0.0.1:3333/"\n' +
68 'export EC2_USER_ID="test1"\n')
69
70 def test_006_test_key_storage(self):
71 user = self.users.get_user('test1')
72 user.create_key_pair('public', 'key', 'fingerprint')
73 key = user.get_key_pair('public')
74 self.assertEqual('key', key.public_key)
75 self.assertEqual('fingerprint', key.fingerprint)
76
77 def test_007_test_key_generation(self):
78 user = self.users.get_user('test1')
79 private_key, fingerprint = user.generate_key_pair('public2')
80 key = RSA.load_key_string(private_key, callback=lambda: None)
81 bio = BIO.MemoryBuffer()
82 public_key = user.get_key_pair('public2').public_key
83 key.save_pub_key_bio(bio)
84 converted = crypto.ssl_pub_to_ssh_pub(bio.read())
85 # assert key fields are equal
86 self.assertEqual(public_key.split(" ")[1].strip(),
87 converted.split(" ")[1].strip())
88
89 def test_008_can_list_key_pairs(self):
90 keys = self.users.get_user('test1').get_key_pairs()
91 self.assertTrue(filter(lambda k: k.name == 'public', keys))
92 self.assertTrue(filter(lambda k: k.name == 'public2', keys))
93
94 def test_009_can_delete_key_pair(self):
95 self.users.get_user('test1').delete_key_pair('public')
96 keys = self.users.get_user('test1').get_key_pairs()
97 self.assertFalse(filter(lambda k: k.name == 'public', keys))
98
99 def test_010_can_list_users(self):
100 users = self.users.get_users()
101 logging.warn(users)
102 self.assertTrue(filter(lambda u: u.id == 'test1', users))
103
104 def test_101_can_add_user_role(self):
105 self.assertFalse(self.users.has_role('test1', 'itsec'))
106 self.users.add_role('test1', 'itsec')
107 self.assertTrue(self.users.has_role('test1', 'itsec'))
108
109 def test_199_can_remove_user_role(self):
110 self.assertTrue(self.users.has_role('test1', 'itsec'))
111 self.users.remove_role('test1', 'itsec')
112 self.assertFalse(self.users.has_role('test1', 'itsec'))
113
114 def test_201_can_create_project(self):
115 project = self.users.create_project('testproj', 'test1', 'A test project', ['test1'])
116 self.assertTrue(filter(lambda p: p.name == 'testproj', self.users.get_projects()))
117 self.assertEqual(project.name, 'testproj')
118 self.assertEqual(project.description, 'A test project')
119 self.assertEqual(project.project_manager_id, 'test1')
120 self.assertTrue(project.has_member('test1'))
121
122 def test_202_user1_is_project_member(self):
123 self.assertTrue(self.users.get_user('test1').is_project_member('testproj'))
124
125 def test_203_user2_is_not_project_member(self):
126 self.assertFalse(self.users.get_user('test2').is_project_member('testproj'))
127
128 def test_204_user1_is_project_manager(self):
129 self.assertTrue(self.users.get_user('test1').is_project_manager('testproj'))
130
131 def test_205_user2_is_not_project_manager(self):
132 self.assertFalse(self.users.get_user('test2').is_project_manager('testproj'))
133
134 def test_206_can_add_user_to_project(self):
135 self.users.add_to_project('test2', 'testproj')
136 self.assertTrue(self.users.get_project('testproj').has_member('test2'))
137
138 def test_208_can_remove_user_from_project(self):
139 self.users.remove_from_project('test2', 'testproj')
140 self.assertFalse(self.users.get_project('testproj').has_member('test2'))
141
142 def test_209_can_generate_x509(self):
143 # MUST HAVE RUN CLOUD SETUP BY NOW
144 self.cloud = cloud.CloudController()
145 self.cloud.setup()
146 private_key, signed_cert_string = self.users.get_project('testproj').generate_x509_cert('test1')
147 logging.debug(signed_cert_string)
148
149 # Need to verify that it's signed by the right intermediate CA
150 full_chain = crypto.fetch_ca(project_id='testproj', chain=True)
151 int_cert = crypto.fetch_ca(project_id='testproj', chain=False)
152 cloud_cert = crypto.fetch_ca()
153 logging.debug("CA chain:\n\n =====\n%s\n\n=====" % full_chain)
154 signed_cert = X509.load_cert_string(signed_cert_string)
155 chain_cert = X509.load_cert_string(full_chain)
156 int_cert = X509.load_cert_string(int_cert)
157 cloud_cert = X509.load_cert_string(cloud_cert)
158 self.assertTrue(signed_cert.verify(chain_cert.get_pubkey()))
159 self.assertTrue(signed_cert.verify(int_cert.get_pubkey()))
160
161 if not FLAGS.use_intermediate_ca:
162 self.assertTrue(signed_cert.verify(cloud_cert.get_pubkey()))
163 else:
164 self.assertFalse(signed_cert.verify(cloud_cert.get_pubkey()))
165
166 def test_210_can_add_project_role(self):
167 project = self.users.get_project('testproj')
168 self.assertFalse(project.has_role('test1', 'sysadmin'))
169 self.users.add_role('test1', 'sysadmin')
170 self.assertFalse(project.has_role('test1', 'sysadmin'))
171 project.add_role('test1', 'sysadmin')
172 self.assertTrue(project.has_role('test1', 'sysadmin'))
173
174 def test_211_can_remove_project_role(self):
175 project = self.users.get_project('testproj')
176 self.assertTrue(project.has_role('test1', 'sysadmin'))
177 project.remove_role('test1', 'sysadmin')
178 self.assertFalse(project.has_role('test1', 'sysadmin'))
179 self.users.remove_role('test1', 'sysadmin')
180 self.assertFalse(project.has_role('test1', 'sysadmin'))
181
182 def test_212_vpn_ip_and_port_looks_valid(self):
183 project = self.users.get_project('testproj')
184 self.assert_(project.vpn_ip)
185 self.assert_(project.vpn_port >= FLAGS.vpn_start_port)
186 self.assert_(project.vpn_port <= FLAGS.vpn_end_port)
187
188 def test_213_too_many_vpns(self):
189 for i in xrange(users.Vpn.num_ports_for_ip(FLAGS.vpn_ip)):
190 users.Vpn.create("vpnuser%s" % i)
191 self.assertRaises(users.NoMorePorts, users.Vpn.create, "boom")
192
193 def test_299_can_delete_project(self):
194 self.users.delete_project('testproj')
195 self.assertFalse(filter(lambda p: p.name == 'testproj', self.users.get_projects()))
196
197 def test_999_can_delete_users(self):
198 self.users.delete_user('test1')
199 users = self.users.get_users()
200 self.assertFalse(filter(lambda u: u.id == 'test1', users))
201 self.users.delete_user('test2')
202 self.assertEqual(self.users.get_user('test2'), None)
203
204
205if __name__ == "__main__":
206 # TODO: Implement use_fake as an option
207 unittest.main()
2080
=== removed file 'nova/tests/validator_unittest.py'
--- nova/tests/validator_unittest.py 2010-07-15 23:13:48 +0000
+++ nova/tests/validator_unittest.py 1970-01-01 00:00:00 +0000
@@ -1,41 +0,0 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import unittest
21
22from nova import flags
23from nova import test
24from nova import validate
25
26
27class ValidationTestCase(test.TrialTestCase):
28 def setUp(self):
29 super(ValidationTestCase, self).setUp()
30
31 def tearDown(self):
32 super(ValidationTestCase, self).tearDown()
33
34 def test_type_validation(self):
35 self.assertTrue(type_case("foo", 5, 1))
36 self.assertRaises(TypeError, type_case, "bar", "5", 1)
37 self.assertRaises(TypeError, type_case, None, 5, 1)
38
39@validate.typetest(instanceid=str, size=int, number_of_instances=int)
40def type_case(instanceid, size, number_of_instances):
41 return True
420
=== modified file 'run_tests.py'
--- run_tests.py 2010-07-19 08:37:28 +0000
+++ run_tests.py 2010-07-23 03:41:08 +0000
@@ -49,17 +49,17 @@
49from nova import flags49from nova import flags
50from nova import twistd50from nova import twistd
5151
52from nova.tests.access_unittest import *52from tests.access_unittest import *
53from nova.tests.api_unittest import *53from tests.api_unittest import *
54from nova.tests.cloud_unittest import *54from tests.cloud_unittest import *
55from nova.tests.model_unittest import *55from tests.model_unittest import *
56from nova.tests.network_unittest import *56from tests.network_unittest import *
57from nova.tests.node_unittest import *57from tests.node_unittest import *
58from nova.tests.objectstore_unittest import *58from tests.objectstore_unittest import *
59from nova.tests.process_unittest import *59from tests.process_unittest import *
60from nova.tests.storage_unittest import *60from tests.storage_unittest import *
61from nova.tests.users_unittest import *61from tests.users_unittest import *
62from nova.tests.validator_unittest import *62from tests.validator_unittest import *
6363
6464
65FLAGS = flags.FLAGS65FLAGS = flags.FLAGS
@@ -79,7 +79,7 @@
7979
80 # TODO(termie): these should make a call instead of doing work on import80 # TODO(termie): these should make a call instead of doing work on import
81 if FLAGS.fake_tests:81 if FLAGS.fake_tests:
82 from nova.tests.fake_flags import *82 from tests.fake_flags import *
83 # use db 8 for fake tests83 # use db 8 for fake tests
84 FLAGS.redis_db = 884 FLAGS.redis_db = 8
85 if FLAGS.flush_db:85 if FLAGS.flush_db:
@@ -87,7 +87,7 @@
87 r = datastore.Redis.instance()87 r = datastore.Redis.instance()
88 r.flushdb()88 r.flushdb()
89 else:89 else:
90 from nova.tests.real_flags import *90 from tests.real_flags import *
9191
92 # Establish redirect for STDERR92 # Establish redirect for STDERR
93 sys.stderr.flush()93 sys.stderr.flush()
9494
=== added directory 'tests'
=== added directory 'tests/CA'
=== added file 'tests/CA/cacert.pem'
--- tests/CA/cacert.pem 1970-01-01 00:00:00 +0000
+++ tests/CA/cacert.pem 2010-07-23 03:41:08 +0000
@@ -0,0 +1,17 @@
1-----BEGIN CERTIFICATE-----
2MIICyzCCAjSgAwIBAgIJANiqHZUcbScCMA0GCSqGSIb3DQEBBAUAME4xEjAQBgNV
3BAoTCU5PVkEgUk9PVDEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzETMBEGA1UECBMK
4Q2FsaWZvcm5pYTELMAkGA1UEBhMCVVMwHhcNMTAwNTI4MDExOTI1WhcNMTEwNTI4
5MDExOTI1WjBOMRIwEAYDVQQKEwlOT1ZBIFJPT1QxFjAUBgNVBAcTDU1vdW50YWlu
6IFZpZXcxEzARBgNVBAgTCkNhbGlmb3JuaWExCzAJBgNVBAYTAlVTMIGfMA0GCSqG
7SIb3DQEBAQUAA4GNADCBiQKBgQDobUnq8rpXA/HQZ2Uu9Me3SlqCayz3ws2wtvFQ
8koWPUzpriIYPkpprz2EaVu07Zb9uJHvjcoY07nYntl4jR8S7PH4XZhlVFn8AQWzs
9iThU4KJF71UfVM00dDrarSgVpyOIcFXO3iUvLoJj7+RUPjrWdLuJoMqnhicgLeHZ
10LAZ8ewIDAQABo4GwMIGtMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFMh1RMlTVtt8
11EdESYpsTU08r0FnpMH4GA1UdIwR3MHWAFMh1RMlTVtt8EdESYpsTU08r0FnpoVKk
12UDBOMRIwEAYDVQQKEwlOT1ZBIFJPT1QxFjAUBgNVBAcTDU1vdW50YWluIFZpZXcx
13EzARBgNVBAgTCkNhbGlmb3JuaWExCzAJBgNVBAYTAlVTggkA2KodlRxtJwIwDQYJ
14KoZIhvcNAQEEBQADgYEAq+YCgflK36HCdodNu2ya3O6UDRUE2dW8n96tAOmvHqmR
15v38k8GIW0pjWDo+lZYnFmeJYd+QGcJl9fLzXxffV5k+rNCfr/gEYtznWLNUX7AZB
16b/VC7L+yK9qz08C8n51TslXaf3fUGkfkQxsvEP7+hi0qavdd/8eTbdheWahYwWg=
17-----END CERTIFICATE-----
018
=== added directory 'tests/CA/private'
=== added file 'tests/CA/private/cakey.pem'
--- tests/CA/private/cakey.pem 1970-01-01 00:00:00 +0000
+++ tests/CA/private/cakey.pem 2010-07-23 03:41:08 +0000
@@ -0,0 +1,15 @@
1-----BEGIN RSA PRIVATE KEY-----
2MIICXQIBAAKBgQDobUnq8rpXA/HQZ2Uu9Me3SlqCayz3ws2wtvFQkoWPUzpriIYP
3kpprz2EaVu07Zb9uJHvjcoY07nYntl4jR8S7PH4XZhlVFn8AQWzsiThU4KJF71Uf
4VM00dDrarSgVpyOIcFXO3iUvLoJj7+RUPjrWdLuJoMqnhicgLeHZLAZ8ewIDAQAB
5AoGBANQonmZ2Nh2jniFrn/LiwULP/ho6Fov6J6N8+n1focaYZCUwM58XZRmv7KUM
6X/PuBnVVnDibm2HJodTSJM/zfODnGO15kdmJ9X23FkkdTyuvphO5tYF0ONARXdfX
79LbPcLYA14VSCZCKCye6mbv/xi0C/s7q6ZBoMl7XaeD9hgUxAkEA9lxQY/ZxcLV0
8Ae5I2spBbtuXEGns11YnKnppc59RrAono1gaDeYY2WZRwztIcD6VtUv7qkzH6ubo
9shAG4fvnPQJBAPGFaDODs2ckPvxnILEbjpnZXGQqDCpQ3sVJ6nfu+qdAWS92ESNo
10Y6DC8zFjFaQFbKy6Jxr1VsvYDXhF8cmy7hcCQHkLElSLGWGPRdhNA268QTn+mlJu
11OPf0VHoCex1cAfzNYHxZJTP/AeaO501NK2I63cOd+aDK6M75dQtH5JnT8uECQQCg
12jVydkhk6oV+1jiCvW3BKWbIPa9w2bRgJ8n8JRzYc5Kvk3wm5jfVcsvvTgtip9mkt
130XmZdCpEy9T4dRasTGP1AkBMhShiVP7+P+SIQlZtSn8ckTt9G6cefEjxsv0kVFZe
14SjkUO0ZifahF8r3Q1eEUSzdXEvicEwONvcpc7MLwfSD7
15-----END RSA PRIVATE KEY-----
016
=== added file 'tests/__init__.py'
--- tests/__init__.py 1970-01-01 00:00:00 +0000
+++ tests/__init__.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,31 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19"""
20:mod:`tests` -- Nova Unittests
21=====================================================
22
23.. automodule:: tests
24 :platform: Unix
25.. moduleauthor:: Jesse Andrews <jesse@ansolabs.com>
26.. moduleauthor:: Devin Carlen <devin.carlen@gmail.com>
27.. moduleauthor:: Vishvananda Ishaya <vishvananda@yahoo.com>
28.. moduleauthor:: Joshua McKenty <joshua@cognition.ca>
29.. moduleauthor:: Manish Singh <yosh@gimp.org>
30.. moduleauthor:: Andy Smith <andy@anarkystic.com>
31"""
032
=== added file 'tests/access_unittest.py'
--- tests/access_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/access_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,165 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import unittest
20import logging
21
22from nova import exception
23from nova import flags
24from nova import test
25from nova.auth.users import UserManager
26from nova.auth import rbac
27
28
29FLAGS = flags.FLAGS
30class Context(object):
31 pass
32
33class AccessTestCase(test.BaseTestCase):
34 def setUp(self):
35 super(AccessTestCase, self).setUp()
36 FLAGS.fake_libvirt = True
37 FLAGS.fake_storage = True
38 um = UserManager.instance()
39 # Make test users
40 try:
41 self.testadmin = um.create_user('testadmin')
42 except Exception, err:
43 logging.error(str(err))
44 try:
45 self.testpmsys = um.create_user('testpmsys')
46 except: pass
47 try:
48 self.testnet = um.create_user('testnet')
49 except: pass
50 try:
51 self.testsys = um.create_user('testsys')
52 except: pass
53 # Assign some rules
54 try:
55 um.add_role('testadmin', 'cloudadmin')
56 except: pass
57 try:
58 um.add_role('testpmsys', 'sysadmin')
59 except: pass
60 try:
61 um.add_role('testnet', 'netadmin')
62 except: pass
63 try:
64 um.add_role('testsys', 'sysadmin')
65 except: pass
66
67 # Make a test project
68 try:
69 self.project = um.create_project('testproj', 'testpmsys', 'a test project', ['testpmsys', 'testnet', 'testsys'])
70 except: pass
71 try:
72 self.project.add_role(self.testnet, 'netadmin')
73 except: pass
74 try:
75 self.project.add_role(self.testsys, 'sysadmin')
76 except: pass
77 self.context = Context()
78 self.context.project = self.project
79 #user is set in each test
80
81 def tearDown(self):
82 um = UserManager.instance()
83 # Delete the test project
84 um.delete_project('testproj')
85 # Delete the test user
86 um.delete_user('testadmin')
87 um.delete_user('testpmsys')
88 um.delete_user('testnet')
89 um.delete_user('testsys')
90 super(AccessTestCase, self).tearDown()
91
92 def test_001_allow_all(self):
93 self.context.user = self.testadmin
94 self.assertTrue(self._allow_all(self.context))
95 self.context.user = self.testpmsys
96 self.assertTrue(self._allow_all(self.context))
97 self.context.user = self.testnet
98 self.assertTrue(self._allow_all(self.context))
99 self.context.user = self.testsys
100 self.assertTrue(self._allow_all(self.context))
101
102 def test_002_allow_none(self):
103 self.context.user = self.testadmin
104 self.assertTrue(self._allow_none(self.context))
105 self.context.user = self.testpmsys
106 self.assertRaises(exception.NotAuthorized, self._allow_none, self.context)
107 self.context.user = self.testnet
108 self.assertRaises(exception.NotAuthorized, self._allow_none, self.context)
109 self.context.user = self.testsys
110 self.assertRaises(exception.NotAuthorized, self._allow_none, self.context)
111
112 def test_003_allow_project_manager(self):
113 self.context.user = self.testadmin
114 self.assertTrue(self._allow_project_manager(self.context))
115 self.context.user = self.testpmsys
116 self.assertTrue(self._allow_project_manager(self.context))
117 self.context.user = self.testnet
118 self.assertRaises(exception.NotAuthorized, self._allow_project_manager, self.context)
119 self.context.user = self.testsys
120 self.assertRaises(exception.NotAuthorized, self._allow_project_manager, self.context)
121
122 def test_004_allow_sys_and_net(self):
123 self.context.user = self.testadmin
124 self.assertTrue(self._allow_sys_and_net(self.context))
125 self.context.user = self.testpmsys # doesn't have the per project sysadmin
126 self.assertRaises(exception.NotAuthorized, self._allow_sys_and_net, self.context)
127 self.context.user = self.testnet
128 self.assertTrue(self._allow_sys_and_net(self.context))
129 self.context.user = self.testsys
130 self.assertTrue(self._allow_sys_and_net(self.context))
131
132 def test_005_allow_sys_no_pm(self):
133 self.context.user = self.testadmin
134 self.assertTrue(self._allow_sys_no_pm(self.context))
135 self.context.user = self.testpmsys
136 self.assertRaises(exception.NotAuthorized, self._allow_sys_no_pm, self.context)
137 self.context.user = self.testnet
138 self.assertRaises(exception.NotAuthorized, self._allow_sys_no_pm, self.context)
139 self.context.user = self.testsys
140 self.assertTrue(self._allow_sys_no_pm(self.context))
141
142 @rbac.allow('all')
143 def _allow_all(self, context):
144 return True
145
146 @rbac.allow('none')
147 def _allow_none(self, context):
148 return True
149
150 @rbac.allow('projectmanager')
151 def _allow_project_manager(self, context):
152 return True
153
154 @rbac.allow('sysadmin', 'netadmin')
155 def _allow_sys_and_net(self, context):
156 return True
157
158 @rbac.allow('sysadmin')
159 @rbac.deny('projectmanager')
160 def _allow_sys_no_pm(self, context):
161 return True
162
163if __name__ == "__main__":
164 # TODO: Implement use_fake as an option
165 unittest.main()
0166
=== added file 'tests/api_integration.py'
--- tests/api_integration.py 1970-01-01 00:00:00 +0000
+++ tests/api_integration.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,54 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19
20import boto
21from boto.ec2.regioninfo import RegionInfo
22import unittest
23
24
25ACCESS_KEY = 'fake'
26SECRET_KEY = 'fake'
27CLC_IP = '127.0.0.1'
28CLC_PORT = 8773
29REGION = 'test'
30
31def get_connection():
32 return boto.connect_ec2 (
33 aws_access_key_id=ACCESS_KEY,
34 aws_secret_access_key=SECRET_KEY,
35 is_secure=False,
36 region=RegionInfo(None, REGION, CLC_IP),
37 port=CLC_PORT,
38 path='/services/Cloud',
39 debug=99
40 )
41
42class APIIntegrationTests(unittest.TestCase):
43 def test_001_get_all_images(self):
44 conn = get_connection()
45 res = conn.get_all_images()
46
47
48if __name__ == '__main__':
49 unittest.main()
50
51#print conn.get_all_key_pairs()
52#print conn.create_key_pair
53#print conn.create_security_group('name', 'description')
54
055
=== added file 'tests/api_unittest.py'
--- tests/api_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/api_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,199 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import boto
20from boto.ec2 import regioninfo
21import httplib
22import random
23import StringIO
24from tornado import httpserver
25from twisted.internet import defer
26
27from nova import flags
28from nova import test
29from nova.auth import users
30from nova.endpoint import api
31from nova.endpoint import cloud
32
33
34FLAGS = flags.FLAGS
35
36
37# NOTE(termie): These are a bunch of helper methods and classes to short
38# circuit boto calls and feed them into our tornado handlers,
39# it's pretty damn circuitous so apologies if you have to fix
40# a bug in it
41def boto_to_tornado(method, path, headers, data, host, connection=None):
42 """ translate boto requests into tornado requests
43
44 connection should be a FakeTornadoHttpConnection instance
45 """
46 headers = httpserver.HTTPHeaders()
47 for k, v in headers.iteritems():
48 headers[k] = v
49
50 req = httpserver.HTTPRequest(method=method,
51 uri=path,
52 headers=headers,
53 body=data,
54 host=host,
55 remote_ip='127.0.0.1',
56 connection=connection)
57 return req
58
59
60def raw_to_httpresponse(s):
61 """ translate a raw tornado http response into an httplib.HTTPResponse """
62 sock = FakeHttplibSocket(s)
63 resp = httplib.HTTPResponse(sock)
64 resp.begin()
65 return resp
66
67
68class FakeHttplibSocket(object):
69 """ a fake socket implementation for httplib.HTTPResponse, trivial """
70 def __init__(self, s):
71 self.fp = StringIO.StringIO(s)
72
73 def makefile(self, mode, other):
74 return self.fp
75
76
77class FakeTornadoStream(object):
78 """ a fake stream to satisfy tornado's assumptions, trivial """
79 def set_close_callback(self, f):
80 pass
81
82
83class FakeTornadoConnection(object):
84 """ a fake connection object for tornado to pass to its handlers
85
86 web requests are expected to write to this as they get data and call
87 finish when they are done with the request, we buffer the writes and
88 kick off a callback when it is done so that we can feed the result back
89 into boto.
90 """
91 def __init__(self, d):
92 self.d = d
93 self._buffer = StringIO.StringIO()
94
95 def write(self, chunk):
96 self._buffer.write(chunk)
97
98 def finish(self):
99 s = self._buffer.getvalue()
100 self.d.callback(s)
101
102 xheaders = None
103
104 @property
105 def stream(self):
106 return FakeTornadoStream()
107
108
109class FakeHttplibConnection(object):
110 """ a fake httplib.HTTPConnection for boto to use
111
112 requests made via this connection actually get translated and routed into
113 our tornado app, we then wait for the response and turn it back into
114 the httplib.HTTPResponse that boto expects.
115 """
116 def __init__(self, app, host, is_secure=False):
117 self.app = app
118 self.host = host
119 self.deferred = defer.Deferred()
120
121 def request(self, method, path, data, headers):
122 req = boto_to_tornado
123 conn = FakeTornadoConnection(self.deferred)
124 request = boto_to_tornado(connection=conn,
125 method=method,
126 path=path,
127 headers=headers,
128 data=data,
129 host=self.host)
130 handler = self.app(request)
131 self.deferred.addCallback(raw_to_httpresponse)
132
133 def getresponse(self):
134 @defer.inlineCallbacks
135 def _waiter():
136 result = yield self.deferred
137 defer.returnValue(result)
138 d = _waiter()
139 # NOTE(termie): defer.returnValue above should ensure that
140 # this deferred has already been called by the time
141 # we get here, we are going to cheat and return
142 # the result of the callback
143 return d.result
144
145 def close(self):
146 pass
147
148
149class ApiEc2TestCase(test.BaseTestCase):
150 def setUp(self):
151 super(ApiEc2TestCase, self).setUp()
152
153 self.users = users.UserManager.instance()
154 self.cloud = cloud.CloudController()
155
156 self.host = '127.0.0.1'
157
158 self.app = api.APIServerApplication({'Cloud': self.cloud})
159 self.ec2 = boto.connect_ec2(
160 aws_access_key_id='fake',
161 aws_secret_access_key='fake',
162 is_secure=False,
163 region=regioninfo.RegionInfo(None, 'test', self.host),
164 port=FLAGS.cc_port,
165 path='/services/Cloud')
166
167 self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
168
169 def expect_http(self, host=None, is_secure=False):
170 http = FakeHttplibConnection(
171 self.app, '%s:%d' % (self.host, FLAGS.cc_port), False)
172 self.ec2.new_http_connection(host, is_secure).AndReturn(http)
173 return http
174
175 def test_describe_instances(self):
176 self.expect_http()
177 self.mox.ReplayAll()
178 try:
179 self.users.create_user('fake', 'fake', 'fake')
180 except Exception, _err:
181 pass # User may already exist
182 self.assertEqual(self.ec2.get_all_instances(), [])
183 self.users.delete_user('fake')
184
185
186 def test_get_all_key_pairs(self):
187 self.expect_http()
188 self.mox.ReplayAll()
189 keyname = "".join(random.choice("sdiuisudfsdcnpaqwertasd") for x in range(random.randint(4, 8)))
190 try:
191 self.users.create_user('fake', 'fake', 'fake')
192 except Exception, _err:
193 pass # User may already exist
194 self.users.generate_key_pair('fake', keyname)
195
196 rv = self.ec2.get_all_key_pairs()
197 self.assertTrue(filter(lambda k: k.name == keyname, rv))
198 self.users.delete_user('fake')
199
0200
=== added directory 'tests/bundle'
=== added file 'tests/bundle/1mb.manifest.xml'
--- tests/bundle/1mb.manifest.xml 1970-01-01 00:00:00 +0000
+++ tests/bundle/1mb.manifest.xml 2010-07-23 03:41:08 +0000
@@ -0,0 +1,1 @@
1<?xml version="1.0" ?><manifest><version>2007-10-10</version><bundler><name>euca-tools</name><version>1.2</version><release>31337</release></bundler><machine_configuration><architecture>x86_64</architecture></machine_configuration><image><name>1mb</name><user>42</user><type>machine</type><digest algorithm="SHA1">da39a3ee5e6b4b0d3255bfef95601890afd80709</digest><size>1048576</size><bundled_size>1136</bundled_size><ec2_encrypted_key algorithm="AES-128-CBC">33a2ea00dc64083dd9a10eb5e233635b42a7beb1670ab75452087d9de74c60aba1cd27c136fda56f62beb581de128fb1f10d072b9e556fd25e903107a57827c21f6ee8a93a4ff55b11311fcef217e3eefb07e81f71e88216f43b4b54029c1f2549f2925a839a73947d2d5aeecec4a62ece4af9156d557ae907978298296d9915</ec2_encrypted_key><user_encrypted_key algorithm="AES-128-CBC">4c11147fd8caf92447e90ce339928933d7579244c2f8ffb07cc0ea35f8738da8b90eff6c7a49671a84500e993e9462e4c36d5c19c0b3a2b397d035b4c0cce742b58e12552175d81d129b0425e9f71ebacb9aeb539fa9dd2ac36749fb82876f6902e5fb24b6ec19f35ec4c20acd50437fd30966e99c4d9a0647577970a8fa3023</user_encrypted_key><ec2_encrypted_iv>14bd082c9715f071160c69bbfb070f51d2ba1076775f1d988ccde150e515088156b248e4b5a64e46c4fe064feeeedfe14511f7fde478a51acb89f9b2f6c84b60593e5c3f792ba6b01fed9bf2158fdac03086374883b39d13a3ca74497eeaaf579fc3f26effc73bfd9446a2a8c4061f0874bfaca058905180e22d3d8881551cb3</ec2_encrypted_iv><user_encrypted_iv>8f7606f19f00e4e19535dd234b66b31b77e9c7bad3885d9c9efa75c863631fd4f82a009e17d789066d9cc6032a436f05384832f6d9a3283d3e63eab04fa0da5c8c87db9b17e854e842c3fb416507d067a266b44538125ce732e486098e8ebd1ca91fa3079f007fce7d14957a9b7e57282407ead3c6eb68fe975df3d83190021b</user_encrypted_iv><parts count="2"><part index="0"><filename>1mb.part.0</filename><digest algorithm="SHA1">c4413423cf7a57e71187e19bfd5cd4b514a64283</digest></part><part index="1"><filename>1mb.part.1</filename><digest algorithm="SHA1">9d4262e6589393d09a11a0332af169887bc2e57d</digest></part></parts></image><signature>4e00b5ba28114dda4a9df7eeae94be847ec46117a09a1cbe41e578660642f0660dda1776b39fb3bf826b6cfec019e2a5e9c566728d186b7400ebc989a30670eb1db26ce01e68bd9d3f31290370077a85b81c66b63c1e0d5499bac115c06c17a21a81b6d3a67ebbce6c17019095af7ab07f3796c708cc843e58efc12ddc788c5e</signature></manifest>
0\ No newline at end of file2\ No newline at end of file
13
=== added file 'tests/bundle/1mb.part.0'
2Binary files tests/bundle/1mb.part.0 1970-01-01 00:00:00 +0000 and tests/bundle/1mb.part.0 2010-07-23 03:41:08 +0000 differ4Binary files tests/bundle/1mb.part.0 1970-01-01 00:00:00 +0000 and tests/bundle/1mb.part.0 2010-07-23 03:41:08 +0000 differ
=== added file 'tests/bundle/1mb.part.1'
--- tests/bundle/1mb.part.1 1970-01-01 00:00:00 +0000
+++ tests/bundle/1mb.part.1 2010-07-23 03:41:08 +0000
@@ -0,0 +1,1 @@
1­´ˆà«€ç‰°Ƴ
0¡ÀiDHW̽×JÈ8ïrV¼³h§X’·@Yj“~Ø2¡ÀiDHW̽×JÈ8ïrV¼³h§X’·@Yj“~Ø
1·Gû5û 3Nt«˜•H6Ñ$§Ëgö™é Lá¢+³æ¤X†pm¬@,øŽ>7ÚÊ×užp¼ aü`¥V2X@£#á¶3·Gû5û 3Nt«˜•H6Ñ$§Ëgö™é Lá¢+³æ¤X†pm¬@,øŽ>7ÚÊ×užp¼ aü`¥V2X@£#á¶
2\ No newline at end of file4\ No newline at end of file
35
=== added file 'tests/cloud_unittest.py'
--- tests/cloud_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/cloud_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,163 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import StringIO
21import time
22from tornado import ioloop
23from twisted.internet import defer
24import unittest
25from xml.etree import ElementTree
26
27from nova import flags
28from nova import rpc
29from nova import test
30from nova.auth import users
31from nova.compute import node
32from nova.endpoint import api
33from nova.endpoint import cloud
34
35
36FLAGS = flags.FLAGS
37
38
39class CloudTestCase(test.BaseTestCase):
40 def setUp(self):
41 super(CloudTestCase, self).setUp()
42 self.flags(fake_libvirt=True,
43 fake_storage=True,
44 fake_users=True)
45
46 self.conn = rpc.Connection.instance()
47 logging.getLogger().setLevel(logging.DEBUG)
48
49 # set up our cloud
50 self.cloud = cloud.CloudController()
51 self.cloud_consumer = rpc.AdapterConsumer(connection=self.conn,
52 topic=FLAGS.cloud_topic,
53 proxy=self.cloud)
54 self.injected.append(self.cloud_consumer.attach_to_tornado(self.ioloop))
55
56 # set up a node
57 self.node = node.Node()
58 self.node_consumer = rpc.AdapterConsumer(connection=self.conn,
59 topic=FLAGS.compute_topic,
60 proxy=self.node)
61 self.injected.append(self.node_consumer.attach_to_tornado(self.ioloop))
62
63 try:
64 users.UserManager.instance().create_user('admin', 'admin', 'admin')
65 except: pass
66 admin = users.UserManager.instance().get_user('admin')
67 project = users.UserManager.instance().create_project('proj', 'admin', 'proj')
68 self.context = api.APIRequestContext(handler=None,project=project,user=admin)
69
70 def tearDown(self):
71 users.UserManager.instance().delete_project('proj')
72 users.UserManager.instance().delete_user('admin')
73
74 def test_console_output(self):
75 if FLAGS.fake_libvirt:
76 logging.debug("Can't test instances without a real virtual env.")
77 return
78 instance_id = 'foo'
79 inst = yield self.node.run_instance(instance_id)
80 output = yield self.cloud.get_console_output(self.context, [instance_id])
81 logging.debug(output)
82 self.assert_(output)
83 rv = yield self.node.terminate_instance(instance_id)
84
85 def test_run_instances(self):
86 if FLAGS.fake_libvirt:
87 logging.debug("Can't test instances without a real virtual env.")
88 return
89 image_id = FLAGS.default_image
90 instance_type = FLAGS.default_instance_type
91 max_count = 1
92 kwargs = {'image_id': image_id,
93 'instance_type': instance_type,
94 'max_count': max_count}
95 rv = yield self.cloud.run_instances(self.context, **kwargs)
96 # TODO: check for proper response
97 instance = rv['reservationSet'][0][rv['reservationSet'][0].keys()[0]][0]
98 logging.debug("Need to watch instance %s until it's running..." % instance['instance_id'])
99 while True:
100 rv = yield defer.succeed(time.sleep(1))
101 info = self.cloud._get_instance(instance['instance_id'])
102 logging.debug(info['state'])
103 if info['state'] == node.Instance.RUNNING:
104 break
105 self.assert_(rv)
106
107 if not FLAGS.fake_libvirt:
108 time.sleep(45) # Should use boto for polling here
109 for reservations in rv['reservationSet']:
110 # for res_id in reservations.keys():
111 # logging.debug(reservations[res_id])
112 # for instance in reservations[res_id]:
113 for instance in reservations[reservations.keys()[0]]:
114 logging.debug("Terminating instance %s" % instance['instance_id'])
115 rv = yield self.node.terminate_instance(instance['instance_id'])
116
117 def test_instance_update_state(self):
118 def instance(num):
119 return {
120 'reservation_id': 'r-1',
121 'instance_id': 'i-%s' % num,
122 'image_id': 'ami-%s' % num,
123 'private_dns_name': '10.0.0.%s' % num,
124 'dns_name': '10.0.0%s' % num,
125 'ami_launch_index': str(num),
126 'instance_type': 'fake',
127 'availability_zone': 'fake',
128 'key_name': None,
129 'kernel_id': 'fake',
130 'ramdisk_id': 'fake',
131 'groups': ['default'],
132 'product_codes': None,
133 'state': 0x01,
134 'user_data': ''
135 }
136 rv = self.cloud._format_instances(self.context)
137 self.assert_(len(rv['reservationSet']) == 0)
138
139 # simulate launch of 5 instances
140 # self.cloud.instances['pending'] = {}
141 #for i in xrange(5):
142 # inst = instance(i)
143 # self.cloud.instances['pending'][inst['instance_id']] = inst
144
145 #rv = self.cloud._format_instances(self.admin)
146 #self.assert_(len(rv['reservationSet']) == 1)
147 #self.assert_(len(rv['reservationSet'][0]['instances_set']) == 5)
148 # report 4 nodes each having 1 of the instances
149 #for i in xrange(4):
150 # self.cloud.update_state('instances', {('node-%s' % i): {('i-%s' % i): instance(i)}})
151
152 # one instance should be pending still
153 #self.assert_(len(self.cloud.instances['pending'].keys()) == 1)
154
155 # check that the reservations collapse
156 #rv = self.cloud._format_instances(self.admin)
157 #self.assert_(len(rv['reservationSet']) == 1)
158 #self.assert_(len(rv['reservationSet'][0]['instances_set']) == 5)
159
160 # check that we can get metadata for each instance
161 #for i in xrange(4):
162 # data = self.cloud.get_metadata(instance(i)['private_dns_name'])
163 # self.assert_(data['meta-data']['ami-id'] == 'ami-%s' % i)
0164
=== added file 'tests/fake_flags.py'
--- tests/fake_flags.py 1970-01-01 00:00:00 +0000
+++ tests/fake_flags.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,28 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19from nova import flags
20
21FLAGS = flags.FLAGS
22
23FLAGS.fake_libvirt = True
24FLAGS.fake_storage = True
25FLAGS.fake_rabbit = True
26FLAGS.fake_network = True
27FLAGS.fake_users = True
28FLAGS.verbose = True
029
=== added file 'tests/future_unittest.py'
--- tests/future_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/future_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,75 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import mox
21import StringIO
22import time
23from tornado import ioloop
24from twisted.internet import defer
25import unittest
26from xml.etree import ElementTree
27
28from nova import cloud
29from nova import exception
30from nova import flags
31from nova import node
32from nova import rpc
33from nova import test
34
35
36FLAGS = flags.FLAGS
37
38
39class AdminTestCase(test.BaseTestCase):
40 def setUp(self):
41 super(AdminTestCase, self).setUp()
42 self.flags(fake_libvirt=True,
43 fake_rabbit=True)
44
45 self.conn = rpc.Connection.instance()
46
47 logging.getLogger().setLevel(logging.INFO)
48
49 # set up our cloud
50 self.cloud = cloud.CloudController()
51 self.cloud_consumer = rpc.AdapterConsumer(connection=self.conn,
52 topic=FLAGS.cloud_topic,
53 proxy=self.cloud)
54 self.injected.append(self.cloud_consumer.attach_to_tornado(self.ioloop))
55
56 # set up a node
57 self.node = node.Node()
58 self.node_consumer = rpc.AdapterConsumer(connection=self.conn,
59 topic=FLAGS.compute_topic,
60 proxy=self.node)
61 self.injected.append(self.node_consumer.attach_to_tornado(self.ioloop))
62
63 def test_flush_terminated(self):
64 # Launch an instance
65
66 # Wait until it's running
67
68 # Terminate it
69
70 # Wait until it's terminated
71
72 # Flush terminated nodes
73
74 # ASSERT that it's gone
75 pass
076
=== added file 'tests/model_unittest.py'
--- tests/model_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/model_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,206 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import time
21from twisted.internet import defer
22
23from nova import exception
24from nova import flags
25from nova import test
26from nova import utils
27from nova.compute import model
28from nova.compute import node
29
30
31FLAGS = flags.FLAGS
32
33
34class ModelTestCase(test.TrialTestCase):
35 def setUp(self):
36 super(ModelTestCase, self).setUp()
37 self.flags(fake_libvirt=True,
38 fake_storage=True,
39 fake_users=True)
40
41 def tearDown(self):
42 model.Instance('i-test').destroy()
43 model.Host('testhost').destroy()
44 model.Daemon('testhost', 'nova-testdaemon').destroy()
45
46 def create_instance(self):
47 inst = model.Instance('i-test')
48 inst['reservation_id'] = 'r-test'
49 inst['launch_time'] = '10'
50 inst['user_id'] = 'fake'
51 inst['project_id'] = 'fake'
52 inst['instance_type'] = 'm1.tiny'
53 inst['node_name'] = FLAGS.node_name
54 inst['mac_address'] = utils.generate_mac()
55 inst['ami_launch_index'] = 0
56 inst.save()
57 return inst
58
59 def create_host(self):
60 host = model.Host('testhost')
61 host.save()
62 return host
63
64 def create_daemon(self):
65 daemon = model.Daemon('testhost', 'nova-testdaemon')
66 daemon.save()
67 return daemon
68
69 @defer.inlineCallbacks
70 def test_create_instance(self):
71 """store with create_instace, then test that a load finds it"""
72 instance = yield self.create_instance()
73 old = yield model.Instance(instance.identifier)
74 self.assertFalse(old.is_new_record())
75
76 @defer.inlineCallbacks
77 def test_delete_instance(self):
78 """create, then destroy, then make sure loads a new record"""
79 instance = yield self.create_instance()
80 yield instance.destroy()
81 newinst = yield model.Instance('i-test')
82 self.assertTrue(newinst.is_new_record())
83
84 @defer.inlineCallbacks
85 def test_instance_added_to_set(self):
86 """create, then check that it is listed for the project"""
87 instance = yield self.create_instance()
88 found = False
89 for x in model.InstanceDirectory().all:
90 if x.identifier == 'i-test':
91 found = True
92 self.assert_(found)
93
94 @defer.inlineCallbacks
95 def test_instance_associates_project(self):
96 """create, then check that it is listed for the project"""
97 instance = yield self.create_instance()
98 found = False
99 for x in model.InstanceDirectory().by_project(instance.project):
100 if x.identifier == 'i-test':
101 found = True
102 self.assert_(found)
103
104 @defer.inlineCallbacks
105 def test_host_class_finds_hosts(self):
106 host = yield self.create_host()
107 self.assertEqual('testhost', model.Host.lookup('testhost').identifier)
108
109 @defer.inlineCallbacks
110 def test_host_class_doesnt_find_missing_hosts(self):
111 rv = yield model.Host.lookup('woahnelly')
112 self.assertEqual(None, rv)
113
114 @defer.inlineCallbacks
115 def test_create_host(self):
116 """store with create_host, then test that a load finds it"""
117 host = yield self.create_host()
118 old = yield model.Host(host.identifier)
119 self.assertFalse(old.is_new_record())
120
121 @defer.inlineCallbacks
122 def test_delete_host(self):
123 """create, then destroy, then make sure loads a new record"""
124 instance = yield self.create_host()
125 yield instance.destroy()
126 newinst = yield model.Host('testhost')
127 self.assertTrue(newinst.is_new_record())
128
129 @defer.inlineCallbacks
130 def test_host_added_to_set(self):
131 """create, then check that it is included in list"""
132 instance = yield self.create_host()
133 found = False
134 for x in model.Host.all():
135 if x.identifier == 'testhost':
136 found = True
137 self.assert_(found)
138
139 @defer.inlineCallbacks
140 def test_create_daemon_two_args(self):
141 """create a daemon with two arguments"""
142 d = yield self.create_daemon()
143 d = model.Daemon('testhost', 'nova-testdaemon')
144 self.assertFalse(d.is_new_record())
145
146 @defer.inlineCallbacks
147 def test_create_daemon_single_arg(self):
148 """Create a daemon using the combined host:bin format"""
149 d = yield model.Daemon("testhost:nova-testdaemon")
150 d.save()
151 d = model.Daemon('testhost:nova-testdaemon')
152 self.assertFalse(d.is_new_record())
153
154 @defer.inlineCallbacks
155 def test_equality_of_daemon_single_and_double_args(self):
156 """Create a daemon using the combined host:bin arg, find with 2"""
157 d = yield model.Daemon("testhost:nova-testdaemon")
158 d.save()
159 d = model.Daemon('testhost', 'nova-testdaemon')
160 self.assertFalse(d.is_new_record())
161
162 @defer.inlineCallbacks
163 def test_equality_daemon_of_double_and_single_args(self):
164 """Create a daemon using the combined host:bin arg, find with 2"""
165 d = yield self.create_daemon()
166 d = model.Daemon('testhost:nova-testdaemon')
167 self.assertFalse(d.is_new_record())
168
169 @defer.inlineCallbacks
170 def test_delete_daemon(self):
171 """create, then destroy, then make sure loads a new record"""
172 instance = yield self.create_daemon()
173 yield instance.destroy()
174 newinst = yield model.Daemon('testhost', 'nova-testdaemon')
175 self.assertTrue(newinst.is_new_record())
176
177 @defer.inlineCallbacks
178 def test_daemon_heartbeat(self):
179 """Create a daemon, sleep, heartbeat, check for update"""
180 d = yield self.create_daemon()
181 ts = d['updated_at']
182 time.sleep(2)
183 d.heartbeat()
184 d2 = model.Daemon('testhost', 'nova-testdaemon')
185 ts2 = d2['updated_at']
186 self.assert_(ts2 > ts)
187
188 @defer.inlineCallbacks
189 def test_daemon_added_to_set(self):
190 """create, then check that it is included in list"""
191 instance = yield self.create_daemon()
192 found = False
193 for x in model.Daemon.all():
194 if x.identifier == 'testhost:nova-testdaemon':
195 found = True
196 self.assert_(found)
197
198 @defer.inlineCallbacks
199 def test_daemon_associates_host(self):
200 """create, then check that it is listed for the host"""
201 instance = yield self.create_daemon()
202 found = False
203 for x in model.Daemon.by_host('testhost'):
204 if x.identifier == 'testhost:nova-testdaemon':
205 found = True
206 self.assertTrue(found)
0207
=== added file 'tests/network_unittest.py'
--- tests/network_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/network_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,219 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import IPy
20import os
21import logging
22
23from nova import flags
24from nova import test
25from nova import utils
26from nova.auth import users
27from nova.compute import network
28from nova.compute.exception import NoMoreAddresses
29
30FLAGS = flags.FLAGS
31
32class NetworkTestCase(test.TrialTestCase):
33 def setUp(self):
34 super(NetworkTestCase, self).setUp()
35 self.flags(fake_libvirt=True,
36 fake_storage=True,
37 fake_network=True,
38 network_size=32)
39 logging.getLogger().setLevel(logging.DEBUG)
40 self.manager = users.UserManager.instance()
41 self.dnsmasq = FakeDNSMasq()
42 try:
43 self.manager.create_user('netuser', 'netuser', 'netuser')
44 except: pass
45 for i in range(0, 6):
46 name = 'project%s' % i
47 if not self.manager.get_project(name):
48 self.manager.create_project(name, 'netuser', name)
49 self.network = network.PublicNetworkController()
50
51 def tearDown(self):
52 super(NetworkTestCase, self).tearDown()
53 for i in range(0, 6):
54 name = 'project%s' % i
55 self.manager.delete_project(name)
56 self.manager.delete_user('netuser')
57
58 def test_public_network_allocation(self):
59 pubnet = IPy.IP(flags.FLAGS.public_range)
60 address = self.network.allocate_ip("netuser", "project0", "public")
61 self.assertTrue(IPy.IP(address) in pubnet)
62 self.assertTrue(IPy.IP(address) in self.network.network)
63
64 def test_allocate_deallocate_ip(self):
65 address = network.allocate_ip(
66 "netuser", "project0", utils.generate_mac())
67 logging.debug("Was allocated %s" % (address))
68 net = network.get_project_network("project0", "default")
69 self.assertEqual(True, is_in_project(address, "project0"))
70 mac = utils.generate_mac()
71 hostname = "test-host"
72 self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name)
73 rv = network.deallocate_ip(address)
74
75 # Doesn't go away until it's dhcp released
76 self.assertEqual(True, is_in_project(address, "project0"))
77
78 self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
79 self.assertEqual(False, is_in_project(address, "project0"))
80
81 def test_range_allocation(self):
82 mac = utils.generate_mac()
83 secondmac = utils.generate_mac()
84 hostname = "test-host"
85 address = network.allocate_ip(
86 "netuser", "project0", mac)
87 secondaddress = network.allocate_ip(
88 "netuser", "project1", secondmac)
89 net = network.get_project_network("project0", "default")
90 secondnet = network.get_project_network("project1", "default")
91
92 self.assertEqual(True, is_in_project(address, "project0"))
93 self.assertEqual(True, is_in_project(secondaddress, "project1"))
94 self.assertEqual(False, is_in_project(address, "project1"))
95
96 # Addresses are allocated before they're issued
97 self.dnsmasq.issue_ip(mac, address, hostname, net.bridge_name)
98 self.dnsmasq.issue_ip(secondmac, secondaddress,
99 hostname, secondnet.bridge_name)
100
101 rv = network.deallocate_ip(address)
102 self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
103 self.assertEqual(False, is_in_project(address, "project0"))
104
105 # First address release shouldn't affect the second
106 self.assertEqual(True, is_in_project(secondaddress, "project1"))
107
108 rv = network.deallocate_ip(secondaddress)
109 self.dnsmasq.release_ip(secondmac, secondaddress,
110 hostname, secondnet.bridge_name)
111 self.assertEqual(False, is_in_project(secondaddress, "project1"))
112
113 def test_subnet_edge(self):
114 secondaddress = network.allocate_ip("netuser", "project0",
115 utils.generate_mac())
116 hostname = "toomany-hosts"
117 for project in range(1,5):
118 project_id = "project%s" % (project)
119 mac = utils.generate_mac()
120 mac2 = utils.generate_mac()
121 mac3 = utils.generate_mac()
122 address = network.allocate_ip(
123 "netuser", project_id, mac)
124 address2 = network.allocate_ip(
125 "netuser", project_id, mac2)
126 address3 = network.allocate_ip(
127 "netuser", project_id, mac3)
128 self.assertEqual(False, is_in_project(address, "project0"))
129 self.assertEqual(False, is_in_project(address2, "project0"))
130 self.assertEqual(False, is_in_project(address3, "project0"))
131 rv = network.deallocate_ip(address)
132 rv = network.deallocate_ip(address2)
133 rv = network.deallocate_ip(address3)
134 net = network.get_project_network(project_id, "default")
135 self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
136 self.dnsmasq.release_ip(mac2, address2, hostname, net.bridge_name)
137 self.dnsmasq.release_ip(mac3, address3, hostname, net.bridge_name)
138 net = network.get_project_network("project0", "default")
139 rv = network.deallocate_ip(secondaddress)
140 self.dnsmasq.release_ip(mac, address, hostname, net.bridge_name)
141
142 def test_release_before_deallocate(self):
143 pass
144
145 def test_deallocate_before_issued(self):
146 pass
147
148 def test_too_many_addresses(self):
149 """
150 Here, we test that a proper NoMoreAddresses exception is raised.
151
152 However, the number of available IP addresses depends on the test
153 environment's setup.
154
155 Network size is set in test fixture's setUp method.
156
157 There are FLAGS.cnt_vpn_clients addresses reserved for VPN (NUM_RESERVED_VPN_IPS)
158
159 And there are NUM_STATIC_IPS that are always reserved by Nova for the necessary
160 services (gateway, CloudPipe, etc)
161
162 So we should get flags.network_size - (NUM_STATIC_IPS +
163 NUM_PREALLOCATED_IPS +
164 NUM_RESERVED_VPN_IPS)
165 usable addresses
166 """
167 net = network.get_project_network("project0", "default")
168
169 # Determine expected number of available IP addresses
170 num_static_ips = net.num_static_ips
171 num_preallocated_ips = len(net.hosts.keys())
172 num_reserved_vpn_ips = flags.FLAGS.cnt_vpn_clients
173 num_available_ips = flags.FLAGS.network_size - (num_static_ips + num_preallocated_ips + num_reserved_vpn_ips)
174
175 hostname = "toomany-hosts"
176 macs = {}
177 addresses = {}
178 for i in range(0, (num_available_ips - 1)):
179 macs[i] = utils.generate_mac()
180 addresses[i] = network.allocate_ip("netuser", "project0", macs[i])
181 self.dnsmasq.issue_ip(macs[i], addresses[i], hostname, net.bridge_name)
182
183 self.assertRaises(NoMoreAddresses, network.allocate_ip, "netuser", "project0", utils.generate_mac())
184
185 for i in range(0, (num_available_ips - 1)):
186 rv = network.deallocate_ip(addresses[i])
187 self.dnsmasq.release_ip(macs[i], addresses[i], hostname, net.bridge_name)
188
189def is_in_project(address, project_id):
190 return address in network.get_project_network(project_id).list_addresses()
191
192def _get_project_addresses(project_id):
193 project_addresses = []
194 for addr in network.get_project_network(project_id).list_addresses():
195 project_addresses.append(addr)
196 return project_addresses
197
198def binpath(script):
199 return os.path.join(utils.abspath("../bin"), script)
200
201class FakeDNSMasq(object):
202 def issue_ip(self, mac, ip, hostname, interface):
203 cmd = "%s add %s %s %s" % (binpath('nova-dhcpbridge'),
204 mac, ip, hostname)
205 env = {'DNSMASQ_INTERFACE': interface,
206 'TESTING' : '1',
207 'FLAGFILE' : FLAGS.dhcpbridge_flagfile}
208 (out, err) = utils.execute(cmd, addl_env=env)
209 logging.debug("ISSUE_IP: %s, %s " % (out, err))
210
211 def release_ip(self, mac, ip, hostname, interface):
212 cmd = "%s del %s %s %s" % (binpath('nova-dhcpbridge'),
213 mac, ip, hostname)
214 env = {'DNSMASQ_INTERFACE': interface,
215 'TESTING' : '1',
216 'FLAGFILE' : FLAGS.dhcpbridge_flagfile}
217 (out, err) = utils.execute(cmd, addl_env=env)
218 logging.debug("RELEASE_IP: %s, %s " % (out, err))
219
0220
=== added file 'tests/node_unittest.py'
--- tests/node_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/node_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,128 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import time
21from twisted.internet import defer
22from xml.etree import ElementTree
23
24from nova import exception
25from nova import flags
26from nova import test
27from nova import utils
28from nova.compute import model
29from nova.compute import node
30
31
32FLAGS = flags.FLAGS
33
34
35class InstanceXmlTestCase(test.TrialTestCase):
36 # @defer.inlineCallbacks
37 def test_serialization(self):
38 # TODO: Reimplement this, it doesn't make sense in redis-land
39 return
40
41 # instance_id = 'foo'
42 # first_node = node.Node()
43 # inst = yield first_node.run_instance(instance_id)
44 #
45 # # force the state so that we can verify that it changes
46 # inst._s['state'] = node.Instance.NOSTATE
47 # xml = inst.toXml()
48 # self.assert_(ElementTree.parse(StringIO.StringIO(xml)))
49 #
50 # second_node = node.Node()
51 # new_inst = node.Instance.fromXml(second_node._conn, pool=second_node._pool, xml=xml)
52 # self.assertEqual(new_inst.state, node.Instance.RUNNING)
53 # rv = yield first_node.terminate_instance(instance_id)
54
55
56class NodeConnectionTestCase(test.TrialTestCase):
57 def setUp(self):
58 logging.getLogger().setLevel(logging.DEBUG)
59 super(NodeConnectionTestCase, self).setUp()
60 self.flags(fake_libvirt=True,
61 fake_storage=True,
62 fake_users=True)
63 self.node = node.Node()
64
65 def create_instance(self):
66 instdir = model.InstanceDirectory()
67 inst = instdir.new()
68 # TODO(ja): add ami, ari, aki, user_data
69 inst['reservation_id'] = 'r-fakeres'
70 inst['launch_time'] = '10'
71 inst['user_id'] = 'fake'
72 inst['project_id'] = 'fake'
73 inst['instance_type'] = 'm1.tiny'
74 inst['node_name'] = FLAGS.node_name
75 inst['mac_address'] = utils.generate_mac()
76 inst['ami_launch_index'] = 0
77 inst.save()
78 return inst['instance_id']
79
80 @defer.inlineCallbacks
81 def test_run_describe_terminate(self):
82 instance_id = self.create_instance()
83
84 rv = yield self.node.run_instance(instance_id)
85
86 rv = yield self.node.describe_instances()
87 logging.info("Running instances: %s", rv)
88 self.assertEqual(rv[instance_id].name, instance_id)
89
90 rv = yield self.node.terminate_instance(instance_id)
91
92 rv = yield self.node.describe_instances()
93 logging.info("After terminating instances: %s", rv)
94 self.assertEqual(rv, {})
95
96 @defer.inlineCallbacks
97 def test_reboot(self):
98 instance_id = self.create_instance()
99 rv = yield self.node.run_instance(instance_id)
100
101 rv = yield self.node.describe_instances()
102 self.assertEqual(rv[instance_id].name, instance_id)
103
104 yield self.node.reboot_instance(instance_id)
105
106 rv = yield self.node.describe_instances()
107 self.assertEqual(rv[instance_id].name, instance_id)
108 rv = yield self.node.terminate_instance(instance_id)
109
110 @defer.inlineCallbacks
111 def test_console_output(self):
112 instance_id = self.create_instance()
113 rv = yield self.node.run_instance(instance_id)
114
115 console = yield self.node.get_console_output(instance_id)
116 self.assert_(console)
117 rv = yield self.node.terminate_instance(instance_id)
118
119 @defer.inlineCallbacks
120 def test_run_instance_existing(self):
121 instance_id = self.create_instance()
122 rv = yield self.node.run_instance(instance_id)
123
124 rv = yield self.node.describe_instances()
125 self.assertEqual(rv[instance_id].name, instance_id)
126
127 self.assertRaises(exception.Error, self.node.run_instance, instance_id)
128 rv = yield self.node.terminate_instance(instance_id)
0129
=== added file 'tests/objectstore_unittest.py'
--- tests/objectstore_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/objectstore_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,203 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import glob
20import hashlib
21import logging
22import os
23import shutil
24import tempfile
25
26from nova import flags
27from nova import objectstore
28from nova import test
29from nova.auth import users
30
31
32FLAGS = flags.FLAGS
33
34oss_tempdir = tempfile.mkdtemp(prefix='test_oss-')
35
36
37# delete tempdirs from previous runs (we don't delete after test to allow
38# checking the contents after running tests)
39# TODO: This fails on the test box with a permission denied error
40# Also, doing these things in a global tempdir means that different runs of
41# the test suite on the same box could clobber each other.
42#for path in glob.glob(os.path.abspath(os.path.join(oss_tempdir, '../test_oss-*'))):
43# if path != oss_tempdir:
44# shutil.rmtree(path)
45
46
47# create bucket/images path
48os.makedirs(os.path.join(oss_tempdir, 'images'))
49os.makedirs(os.path.join(oss_tempdir, 'buckets'))
50
51class ObjectStoreTestCase(test.BaseTestCase):
52 def setUp(self):
53 super(ObjectStoreTestCase, self).setUp()
54 self.flags(fake_users=True,
55 buckets_path=os.path.join(oss_tempdir, 'buckets'),
56 images_path=os.path.join(oss_tempdir, 'images'),
57 ca_path=os.path.join(os.path.dirname(__file__), 'CA'))
58 logging.getLogger().setLevel(logging.DEBUG)
59
60 self.um = users.UserManager.instance()
61 try:
62 self.um.create_user('user1')
63 except: pass
64 try:
65 self.um.create_user('user2')
66 except: pass
67 try:
68 self.um.create_user('admin_user', admin=True)
69 except: pass
70 try:
71 self.um.create_project('proj1', 'user1', 'a proj', ['user1'])
72 except: pass
73 try:
74 self.um.create_project('proj2', 'user2', 'a proj', ['user2'])
75 except: pass
76 class Context(object): pass
77 self.context = Context()
78
79 def tearDown(self):
80 self.um.delete_project('proj1')
81 self.um.delete_project('proj2')
82 self.um.delete_user('user1')
83 self.um.delete_user('user2')
84 self.um.delete_user('admin_user')
85 super(ObjectStoreTestCase, self).tearDown()
86
87 def test_buckets(self):
88 self.context.user = self.um.get_user('user1')
89 self.context.project = self.um.get_project('proj1')
90 objectstore.bucket.Bucket.create('new_bucket', self.context)
91 bucket = objectstore.bucket.Bucket('new_bucket')
92
93 # creator is authorized to use bucket
94 self.assert_(bucket.is_authorized(self.context))
95
96 # another user is not authorized
97 self.context.user = self.um.get_user('user2')
98 self.context.project = self.um.get_project('proj2')
99 self.assert_(bucket.is_authorized(self.context) == False)
100
101 # admin is authorized to use bucket
102 self.context.user = self.um.get_user('admin_user')
103 self.context.project = None
104 self.assert_(bucket.is_authorized(self.context))
105
106 # new buckets are empty
107 self.assert_(bucket.list_keys()['Contents'] == [])
108
109 # storing keys works
110 bucket['foo'] = "bar"
111
112 self.assert_(len(bucket.list_keys()['Contents']) == 1)
113
114 self.assert_(bucket['foo'].read() == 'bar')
115
116 # md5 of key works
117 self.assert_(bucket['foo'].md5 == hashlib.md5('bar').hexdigest())
118
119 # deleting non-empty bucket throws exception
120 exception = False
121 try:
122 bucket.delete()
123 except:
124 exception = True
125
126 self.assert_(exception)
127
128 # deleting key
129 del bucket['foo']
130
131 # deleting empty button
132 bucket.delete()
133
134 # accessing deleted bucket throws exception
135 exception = False
136 try:
137 objectstore.bucket.Bucket('new_bucket')
138 except:
139 exception = True
140
141 self.assert_(exception)
142
143 def test_images(self):
144 self.context.user = self.um.get_user('user1')
145 self.context.project = self.um.get_project('proj1')
146
147 # create a bucket for our bundle
148 objectstore.bucket.Bucket.create('image_bucket', self.context)
149 bucket = objectstore.bucket.Bucket('image_bucket')
150
151 # upload an image manifest/parts
152 bundle_path = os.path.join(os.path.dirname(__file__), 'bundle')
153 for path in glob.glob(bundle_path + '/*'):
154 bucket[os.path.basename(path)] = open(path, 'rb').read()
155
156 # register an image
157 objectstore.image.Image.register_aws_image('i-testing', 'image_bucket/1mb.manifest.xml', self.context)
158
159 # verify image
160 my_img = objectstore.image.Image('i-testing')
161 result_image_file = os.path.join(my_img.path, 'image')
162 self.assertEqual(os.stat(result_image_file).st_size, 1048576)
163
164 sha = hashlib.sha1(open(result_image_file).read()).hexdigest()
165 self.assertEqual(sha, '3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3')
166
167 # verify image permissions
168 self.context.user = self.um.get_user('user2')
169 self.context.project = self.um.get_project('proj2')
170 self.assert_(my_img.is_authorized(self.context) == False)
171
172# class ApiObjectStoreTestCase(test.BaseTestCase):
173# def setUp(self):
174# super(ApiObjectStoreTestCase, self).setUp()
175# FLAGS.fake_users = True
176# FLAGS.buckets_path = os.path.join(tempdir, 'buckets')
177# FLAGS.images_path = os.path.join(tempdir, 'images')
178# FLAGS.ca_path = os.path.join(os.path.dirname(__file__), 'CA')
179#
180# self.users = users.UserManager.instance()
181# self.app = handler.Application(self.users)
182#
183# self.host = '127.0.0.1'
184#
185# self.conn = boto.s3.connection.S3Connection(
186# aws_access_key_id=user.access,
187# aws_secret_access_key=user.secret,
188# is_secure=False,
189# calling_format=boto.s3.connection.OrdinaryCallingFormat(),
190# port=FLAGS.s3_port,
191# host=FLAGS.s3_host)
192#
193# self.mox.StubOutWithMock(self.ec2, 'new_http_connection')
194#
195# def tearDown(self):
196# FLAGS.Reset()
197# super(ApiObjectStoreTestCase, self).tearDown()
198#
199# def test_describe_instances(self):
200# self.expect_http()
201# self.mox.ReplayAll()
202#
203# self.assertEqual(self.ec2.get_all_instances(), [])
0204
=== added file 'tests/process_unittest.py'
--- tests/process_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/process_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,122 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20from twisted.internet import defer
21from twisted.internet import reactor
22from xml.etree import ElementTree
23
24from nova import exception
25from nova import flags
26from nova import process
27from nova import test
28from nova import utils
29
30FLAGS = flags.FLAGS
31
32
33class ProcessTestCase(test.TrialTestCase):
34 def setUp(self):
35 logging.getLogger().setLevel(logging.DEBUG)
36 super(ProcessTestCase, self).setUp()
37
38 def test_execute_stdout(self):
39 pool = process.ProcessPool(2)
40 d = pool.simple_execute('echo test')
41 def _check(rv):
42 self.assertEqual(rv[0], 'test\n')
43 self.assertEqual(rv[1], '')
44
45 d.addCallback(_check)
46 d.addErrback(self.fail)
47 return d
48
49 def test_execute_stderr(self):
50 pool = process.ProcessPool(2)
51 d = pool.simple_execute('cat BAD_FILE', error_ok=1)
52 def _check(rv):
53 self.assertEqual(rv[0], '')
54 self.assert_('No such file' in rv[1])
55
56 d.addCallback(_check)
57 d.addErrback(self.fail)
58 return d
59
60 def test_execute_unexpected_stderr(self):
61 pool = process.ProcessPool(2)
62 d = pool.simple_execute('cat BAD_FILE')
63 d.addCallback(lambda x: self.fail('should have raised an error'))
64 d.addErrback(lambda failure: failure.trap(IOError))
65 return d
66
67 def test_max_processes(self):
68 pool = process.ProcessPool(2)
69 d1 = pool.simple_execute('sleep 0.01')
70 d2 = pool.simple_execute('sleep 0.01')
71 d3 = pool.simple_execute('sleep 0.005')
72 d4 = pool.simple_execute('sleep 0.005')
73
74 called = []
75 def _called(rv, name):
76 called.append(name)
77
78 d1.addCallback(_called, 'd1')
79 d2.addCallback(_called, 'd2')
80 d3.addCallback(_called, 'd3')
81 d4.addCallback(_called, 'd4')
82
83 # Make sure that d3 and d4 had to wait on the other two and were called
84 # in order
85 # NOTE(termie): there may be a race condition in this test if for some
86 # reason one of the sleeps takes longer to complete
87 # than it should
88 d4.addCallback(lambda x: self.assertEqual(called[2], 'd3'))
89 d4.addCallback(lambda x: self.assertEqual(called[3], 'd4'))
90 d4.addErrback(self.fail)
91 return d4
92
93 def test_kill_long_process(self):
94 pool = process.ProcessPool(2)
95
96 d1 = pool.simple_execute('sleep 1')
97 d2 = pool.simple_execute('sleep 0.005')
98
99 timeout = reactor.callLater(0.1, self.fail, 'should have been killed')
100
101 # kill d1 and wait on it to end then cancel the timeout
102 d2.addCallback(lambda _: d1.process.signalProcess('KILL'))
103 d2.addCallback(lambda _: d1)
104 d2.addBoth(lambda _: timeout.active() and timeout.cancel())
105 d2.addErrback(self.fail)
106 return d2
107
108 def test_process_exit_is_contained(self):
109 pool = process.ProcessPool(2)
110
111 d1 = pool.simple_execute('sleep 1')
112 d1.addCallback(lambda x: self.fail('should have errbacked'))
113 d1.addErrback(lambda fail: fail.trap(IOError))
114 reactor.callLater(0.05, d1.process.signalProcess, 'KILL')
115
116 return d1
117
118 def test_shared_pool_is_singleton(self):
119 pool1 = process.SharedPool()
120 pool2 = process.SharedPool()
121 self.assert_(id(pool1) == id(pool2))
122
0123
=== added file 'tests/real_flags.py'
--- tests/real_flags.py 1970-01-01 00:00:00 +0000
+++ tests/real_flags.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,28 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19from nova import flags
20
21FLAGS = flags.FLAGS
22
23FLAGS.fake_libvirt = False
24FLAGS.fake_storage = False
25FLAGS.fake_rabbit = False
26FLAGS.fake_network = False
27FLAGS.fake_users = False
28FLAGS.verbose = False
029
=== added file 'tests/storage_unittest.py'
--- tests/storage_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/storage_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,115 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20
21from nova import exception
22from nova import flags
23from nova import test
24from nova.compute import node
25from nova.volume import storage
26
27
28FLAGS = flags.FLAGS
29
30
31class StorageTestCase(test.TrialTestCase):
32 def setUp(self):
33 logging.getLogger().setLevel(logging.DEBUG)
34 super(StorageTestCase, self).setUp()
35 self.mynode = node.Node()
36 self.mystorage = None
37 self.flags(fake_libvirt=True,
38 fake_storage=True)
39 self.mystorage = storage.BlockStore()
40
41 def test_run_create_volume(self):
42 vol_size = '0'
43 user_id = 'fake'
44 project_id = 'fake'
45 volume_id = self.mystorage.create_volume(vol_size, user_id, project_id)
46 # TODO(termie): get_volume returns differently than create_volume
47 self.assertEqual(volume_id,
48 storage.get_volume(volume_id)['volume_id'])
49
50 rv = self.mystorage.delete_volume(volume_id)
51 self.assertRaises(exception.Error,
52 storage.get_volume,
53 volume_id)
54
55 def test_too_big_volume(self):
56 vol_size = '1001'
57 user_id = 'fake'
58 project_id = 'fake'
59 self.assertRaises(TypeError,
60 self.mystorage.create_volume,
61 vol_size, user_id, project_id)
62
63 def test_too_many_volumes(self):
64 vol_size = '1'
65 user_id = 'fake'
66 project_id = 'fake'
67 num_shelves = FLAGS.last_shelf_id - FLAGS.first_shelf_id + 1
68 total_slots = FLAGS.slots_per_shelf * num_shelves
69 vols = []
70 for i in xrange(total_slots):
71 vid = self.mystorage.create_volume(vol_size, user_id, project_id)
72 vols.append(vid)
73 self.assertRaises(storage.NoMoreVolumes,
74 self.mystorage.create_volume,
75 vol_size, user_id, project_id)
76 for id in vols:
77 self.mystorage.delete_volume(id)
78
79 def test_run_attach_detach_volume(self):
80 # Create one volume and one node to test with
81 instance_id = "storage-test"
82 vol_size = "5"
83 user_id = "fake"
84 project_id = 'fake'
85 mountpoint = "/dev/sdf"
86 volume_id = self.mystorage.create_volume(vol_size, user_id, project_id)
87
88 volume_obj = storage.get_volume(volume_id)
89 volume_obj.start_attach(instance_id, mountpoint)
90 rv = yield self.mynode.attach_volume(volume_id,
91 instance_id,
92 mountpoint)
93 self.assertEqual(volume_obj['status'], "in-use")
94 self.assertEqual(volume_obj['attachStatus'], "attached")
95 self.assertEqual(volume_obj['instance_id'], instance_id)
96 self.assertEqual(volume_obj['mountpoint'], mountpoint)
97
98 self.assertRaises(exception.Error,
99 self.mystorage.delete_volume,
100 volume_id)
101
102 rv = yield self.mystorage.detach_volume(volume_id)
103 volume_obj = storage.get_volume(volume_id)
104 self.assertEqual(volume_obj['status'], "available")
105
106 rv = self.mystorage.delete_volume(volume_id)
107 self.assertRaises(exception.Error,
108 storage.get_volume,
109 volume_id)
110
111 def test_multi_node(self):
112 # TODO(termie): Figure out how to test with two nodes,
113 # each of them having a different FLAG for storage_node
114 # This will allow us to test cross-node interactions
115 pass
0116
=== added file 'tests/users_unittest.py'
--- tests/users_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/users_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,207 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20from M2Crypto import BIO
21from M2Crypto import RSA
22from M2Crypto import X509
23import unittest
24
25from nova import crypto
26from nova import flags
27from nova import test
28from nova.auth import users
29from nova.endpoint import cloud
30
31FLAGS = flags.FLAGS
32
33
34class UserTestCase(test.BaseTestCase):
35 flush_db = False
36 def setUp(self):
37 super(UserTestCase, self).setUp()
38 self.flags(fake_libvirt=True,
39 fake_storage=True)
40 self.users = users.UserManager.instance()
41
42 def test_001_can_create_users(self):
43 self.users.create_user('test1', 'access', 'secret')
44 self.users.create_user('test2')
45
46 def test_002_can_get_user(self):
47 user = self.users.get_user('test1')
48
49 def test_003_can_retreive_properties(self):
50 user = self.users.get_user('test1')
51 self.assertEqual('test1', user.id)
52 self.assertEqual('access', user.access)
53 self.assertEqual('secret', user.secret)
54
55 def test_004_signature_is_valid(self):
56 #self.assertTrue(self.users.authenticate( **boto.generate_url ... ? ? ? ))
57 pass
58 #raise NotImplementedError
59
60 def test_005_can_get_credentials(self):
61 return
62 credentials = self.users.get_user('test1').get_credentials()
63 self.assertEqual(credentials,
64 'export EC2_ACCESS_KEY="access"\n' +
65 'export EC2_SECRET_KEY="secret"\n' +
66 'export EC2_URL="http://127.0.0.1:8773/services/Cloud"\n' +
67 'export S3_URL="http://127.0.0.1:3333/"\n' +
68 'export EC2_USER_ID="test1"\n')
69
70 def test_006_test_key_storage(self):
71 user = self.users.get_user('test1')
72 user.create_key_pair('public', 'key', 'fingerprint')
73 key = user.get_key_pair('public')
74 self.assertEqual('key', key.public_key)
75 self.assertEqual('fingerprint', key.fingerprint)
76
77 def test_007_test_key_generation(self):
78 user = self.users.get_user('test1')
79 private_key, fingerprint = user.generate_key_pair('public2')
80 key = RSA.load_key_string(private_key, callback=lambda: None)
81 bio = BIO.MemoryBuffer()
82 public_key = user.get_key_pair('public2').public_key
83 key.save_pub_key_bio(bio)
84 converted = crypto.ssl_pub_to_ssh_pub(bio.read())
85 # assert key fields are equal
86 self.assertEqual(public_key.split(" ")[1].strip(),
87 converted.split(" ")[1].strip())
88
89 def test_008_can_list_key_pairs(self):
90 keys = self.users.get_user('test1').get_key_pairs()
91 self.assertTrue(filter(lambda k: k.name == 'public', keys))
92 self.assertTrue(filter(lambda k: k.name == 'public2', keys))
93
94 def test_009_can_delete_key_pair(self):
95 self.users.get_user('test1').delete_key_pair('public')
96 keys = self.users.get_user('test1').get_key_pairs()
97 self.assertFalse(filter(lambda k: k.name == 'public', keys))
98
99 def test_010_can_list_users(self):
100 users = self.users.get_users()
101 logging.warn(users)
102 self.assertTrue(filter(lambda u: u.id == 'test1', users))
103
104 def test_101_can_add_user_role(self):
105 self.assertFalse(self.users.has_role('test1', 'itsec'))
106 self.users.add_role('test1', 'itsec')
107 self.assertTrue(self.users.has_role('test1', 'itsec'))
108
109 def test_199_can_remove_user_role(self):
110 self.assertTrue(self.users.has_role('test1', 'itsec'))
111 self.users.remove_role('test1', 'itsec')
112 self.assertFalse(self.users.has_role('test1', 'itsec'))
113
114 def test_201_can_create_project(self):
115 project = self.users.create_project('testproj', 'test1', 'A test project', ['test1'])
116 self.assertTrue(filter(lambda p: p.name == 'testproj', self.users.get_projects()))
117 self.assertEqual(project.name, 'testproj')
118 self.assertEqual(project.description, 'A test project')
119 self.assertEqual(project.project_manager_id, 'test1')
120 self.assertTrue(project.has_member('test1'))
121
122 def test_202_user1_is_project_member(self):
123 self.assertTrue(self.users.get_user('test1').is_project_member('testproj'))
124
125 def test_203_user2_is_not_project_member(self):
126 self.assertFalse(self.users.get_user('test2').is_project_member('testproj'))
127
128 def test_204_user1_is_project_manager(self):
129 self.assertTrue(self.users.get_user('test1').is_project_manager('testproj'))
130
131 def test_205_user2_is_not_project_manager(self):
132 self.assertFalse(self.users.get_user('test2').is_project_manager('testproj'))
133
134 def test_206_can_add_user_to_project(self):
135 self.users.add_to_project('test2', 'testproj')
136 self.assertTrue(self.users.get_project('testproj').has_member('test2'))
137
138 def test_208_can_remove_user_from_project(self):
139 self.users.remove_from_project('test2', 'testproj')
140 self.assertFalse(self.users.get_project('testproj').has_member('test2'))
141
142 def test_209_can_generate_x509(self):
143 # MUST HAVE RUN CLOUD SETUP BY NOW
144 self.cloud = cloud.CloudController()
145 self.cloud.setup()
146 private_key, signed_cert_string = self.users.get_project('testproj').generate_x509_cert('test1')
147 logging.debug(signed_cert_string)
148
149 # Need to verify that it's signed by the right intermediate CA
150 full_chain = crypto.fetch_ca(project_id='testproj', chain=True)
151 int_cert = crypto.fetch_ca(project_id='testproj', chain=False)
152 cloud_cert = crypto.fetch_ca()
153 logging.debug("CA chain:\n\n =====\n%s\n\n=====" % full_chain)
154 signed_cert = X509.load_cert_string(signed_cert_string)
155 chain_cert = X509.load_cert_string(full_chain)
156 int_cert = X509.load_cert_string(int_cert)
157 cloud_cert = X509.load_cert_string(cloud_cert)
158 self.assertTrue(signed_cert.verify(chain_cert.get_pubkey()))
159 self.assertTrue(signed_cert.verify(int_cert.get_pubkey()))
160
161 if not FLAGS.use_intermediate_ca:
162 self.assertTrue(signed_cert.verify(cloud_cert.get_pubkey()))
163 else:
164 self.assertFalse(signed_cert.verify(cloud_cert.get_pubkey()))
165
166 def test_210_can_add_project_role(self):
167 project = self.users.get_project('testproj')
168 self.assertFalse(project.has_role('test1', 'sysadmin'))
169 self.users.add_role('test1', 'sysadmin')
170 self.assertFalse(project.has_role('test1', 'sysadmin'))
171 project.add_role('test1', 'sysadmin')
172 self.assertTrue(project.has_role('test1', 'sysadmin'))
173
174 def test_211_can_remove_project_role(self):
175 project = self.users.get_project('testproj')
176 self.assertTrue(project.has_role('test1', 'sysadmin'))
177 project.remove_role('test1', 'sysadmin')
178 self.assertFalse(project.has_role('test1', 'sysadmin'))
179 self.users.remove_role('test1', 'sysadmin')
180 self.assertFalse(project.has_role('test1', 'sysadmin'))
181
182 def test_212_vpn_ip_and_port_looks_valid(self):
183 project = self.users.get_project('testproj')
184 self.assert_(project.vpn_ip)
185 self.assert_(project.vpn_port >= FLAGS.vpn_start_port)
186 self.assert_(project.vpn_port <= FLAGS.vpn_end_port)
187
188 def test_213_too_many_vpns(self):
189 for i in xrange(users.Vpn.num_ports_for_ip(FLAGS.vpn_ip)):
190 users.Vpn.create("vpnuser%s" % i)
191 self.assertRaises(users.NoMorePorts, users.Vpn.create, "boom")
192
193 def test_299_can_delete_project(self):
194 self.users.delete_project('testproj')
195 self.assertFalse(filter(lambda p: p.name == 'testproj', self.users.get_projects()))
196
197 def test_999_can_delete_users(self):
198 self.users.delete_user('test1')
199 users = self.users.get_users()
200 self.assertFalse(filter(lambda u: u.id == 'test1', users))
201 self.users.delete_user('test2')
202 self.assertEqual(self.users.get_user('test2'), None)
203
204
205if __name__ == "__main__":
206 # TODO: Implement use_fake as an option
207 unittest.main()
0208
=== added file 'tests/validator_unittest.py'
--- tests/validator_unittest.py 1970-01-01 00:00:00 +0000
+++ tests/validator_unittest.py 2010-07-23 03:41:08 +0000
@@ -0,0 +1,41 @@
1# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
3# Copyright 2010 United States Government as represented by the
4# Administrator of the National Aeronautics and Space Administration.
5# All Rights Reserved.
6#
7# Licensed under the Apache License, Version 2.0 (the "License"); you may
8# not use this file except in compliance with the License. You may obtain
9# a copy of the License at
10#
11# http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing, software
14# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16# License for the specific language governing permissions and limitations
17# under the License.
18
19import logging
20import unittest
21
22from nova import flags
23from nova import test
24from nova import validate
25
26
27class ValidationTestCase(test.TrialTestCase):
28 def setUp(self):
29 super(ValidationTestCase, self).setUp()
30
31 def tearDown(self):
32 super(ValidationTestCase, self).tearDown()
33
34 def test_type_validation(self):
35 self.assertTrue(type_case("foo", 5, 1))
36 self.assertRaises(TypeError, type_case, "bar", "5", 1)
37 self.assertRaises(TypeError, type_case, None, 5, 1)
38
39@validate.typetest(instanceid=str, size=int, number_of_instances=int)
40def type_case(instanceid, size, number_of_instances):
41 return True