Merge lp:~mhall119/awstrial/fixes-873066 into lp:awstrial

Proposed by Michael Hall
Status: Merged
Approved by: Michael Hall
Approved revision: 261
Merged at revision: 261
Proposed branch: lp:~mhall119/awstrial/fixes-873066
Merge into: lp:awstrial
Diff against target: 134 lines (+76/-14)
2 files modified
awstrial/trial/tests.py (+75/-13)
awstrial/trial/views.py (+1/-1)
To merge this branch: bzr merge lp:~mhall119/awstrial/fixes-873066
Reviewer Review Type Date Requested Status
Matthew Nuzum (community) Approve
Review via email: mp+79180@code.launchpad.net

Commit message

Get instance by user *and* campaign, not just by user, so that we can run multiple campaigns

Description of the change

Overview
========
Trying to start a new instance on a new campaign fails if the user has an old instance on an old campaign

Details
=======
Because the view was not filtering Instances by user *and* campaign, it would raise a MultipleObjectsReturned exception when the user had an instance on more than one campaign.

To post a comment you must log in.
Revision history for this message
Māris Fogels (mars) wrote :

Nice fix. Complex test setup, but that's boto for you. A few questions:

In your test, do you need to call the first campaign before calling the second campaign? I can't tell if the first campaign call is part of the test setup, action, or verification.

Do you need to check the number of campaigns twice, once in the test setup, then at the end of the test?

Maybe not part of this review, but what happens if you set both campaigns to active?

Revision history for this message
Michael Hall (mhall119) wrote :

Calling call_run_instance on the first campaign is part of the setup, since we are testing what happens when a user tries to start a second instance on a different campaign.

Checking the number in the test setup is just to let us know that the setup was done properly. If there was some kind of test isolation problem, this would let us know before we got to the assertions that the test was made to check.

Whether a campaign is active or not doesn't matter, it was just written this way to directly imitate the problem we encountered.

Revision history for this message
Matthew Nuzum (newz) :
review: Approve
Revision history for this message
ISD Branch Mangler (isd-branches-mangler) wrote :

Attempt to merge into lp:awstrial failed due to conflicts:

text conflict in awstrial/trial/tests.py

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'awstrial/trial/tests.py'
2--- awstrial/trial/tests.py 2011-09-29 13:50:26 +0000
3+++ awstrial/trial/tests.py 2011-10-12 20:58:24 +0000
4@@ -104,6 +104,14 @@
5 settings.AWS_SECRET_ACCESS_KEY = self.old_secret_key
6 settings.ALTERNATE_CLOUD = self.old_alternate_cloud
7
8+ def call_run_instance(self, campaign):
9+ post_data = {
10+ 'config': 'default',
11+ 'a': 1,
12+ 'launchbtn': 'Launch',
13+ }
14+ return self.client.post('/%s/run/' % campaign.name, post_data)
15+
16 @patch('boto.ec2.EC2Connection')
17 def test_disallow_multiple_instances(self, mock_connection):
18 """
19@@ -123,11 +131,18 @@
20 def __init__(self, instance_ids):
21 self.instances = [MockInstance(i) for i in instance_ids]
22
23+ campaign = Campaign.objects.create(
24+ name='test-campaign',
25+ verbose_name='Test Campaign',
26+ max_instances=5,
27+ active=True,
28+ )
29+
30 def mock_run_instances(conn, *args, **kwargs):
31 self.call_count += 1
32 if self.call_count == 1:
33 # call again before returning to create the race condition
34- response = call_run_instance()
35+ response = self.call_run_instance(campaign)
36
37 args, kargs = mock_connection.call_args
38 self.assertEquals('TestAccessKey', kargs['aws_access_key_id'])
39@@ -138,23 +153,70 @@
40 return MockReservation(['i-test-two'])
41 mock_connection.return_value.run_instances.side_effect = mock_run_instances
42
43- def call_run_instance():
44- post_data = {
45- 'config': 'default',
46- 'a': 1,
47- 'launchbtn': 'Launch',
48- }
49- return self.client.post('/test-campaign/run/', post_data)
50-
51- campaign = Campaign.objects.create(
52- name='test-campaign',
53- verbose_name='Test Campaign',
54+ user = User.objects.create_user('testuser', 'test@example.com', 'testpasswd')
55+ self.client.login(username='testuser', password='testpasswd')
56+
57+ response = self.call_run_instance(campaign)
58+ self.assertEquals(1, Instances.objects.all().count())
59+
60+ @patch('boto.ec2.EC2Connection')
61+ def test_allow_multiple_instances_on_multiple_campaigns(self, mock_connection):
62+ """
63+ Checks that a user can create multiple instances as long as they are on
64+ different campaigns
65+ """
66+
67+ settings.ALTERNATE_CLOUD = None
68+ self.call_count=0
69+ class MockInstance(object):
70+
71+ def __init__(self, instance_id):
72+ self.id = instance_id
73+
74+ class MockReservation(object):
75+
76+ def __init__(self, instance_ids):
77+ self.instances = [MockInstance(i) for i in instance_ids]
78+
79+ def mock_run_instances(conn, *args, **kwargs):
80+ self.call_count += 1
81+ if self.call_count == 1:
82+ return MockReservation(['i-test-one'])
83+ else:
84+ return MockReservation(['i-test-two'])
85+ mock_connection.return_value.run_instances.side_effect = mock_run_instances
86+
87+ campaign1 = Campaign.objects.create(
88+ name='test-campaign-1',
89+ verbose_name='Test Campaign 1',
90 max_instances=5,
91 active=True,
92 )
93+ campaign2 = Campaign.objects.create(
94+ name='test-campaign-2',
95+ verbose_name='Test Campaign-2',
96+ max_instances=5,
97+ active=False,
98+ )
99
100 user = User.objects.create_user('testuser', 'test@example.com', 'testpasswd')
101 self.client.login(username='testuser', password='testpasswd')
102
103- response = call_run_instance()
104+ response = self.call_run_instance(campaign1)
105+ self.assertRedirects(response, '/test-campaign-1/instance_info/')
106+ response = self.client.get('/test-campaign-1/instance_info/')
107+ self.assertEquals(200, response.status_code)
108 self.assertEquals(1, Instances.objects.all().count())
109+
110+ campaign1.active=False
111+ campaign1.save()
112+
113+ campaign2.active=True
114+ campaign2.save()
115+
116+ response = self.call_run_instance(campaign2)
117+ self.assertRedirects(response, '/test-campaign-2/instance_info/')
118+ response = self.client.get('/test-campaign-2/instance_info/')
119+ self.assertEquals(200, response.status_code)
120+ self.assertEquals(2, Instances.objects.all().count())
121+
122
123=== modified file 'awstrial/trial/views.py'
124--- awstrial/trial/views.py 2011-09-13 20:47:35 +0000
125+++ awstrial/trial/views.py 2011-10-12 20:58:24 +0000
126@@ -127,7 +127,7 @@
127 @safe_user_required
128 def info_instance(request,campaign):
129 """ Return details about Instance """
130- instance = Instances.objects.get(owner=request.user)
131+ instance = Instances.objects.get(owner=request.user, campaign__name=campaign)
132 instcfg = util.find_config(instance.config,settings.CONFIGS)
133 context = {
134 'instance': instance,

Subscribers

People subscribed via source and target branches