Merge lp:~frankban/juju-quickstart/jujubundlelib into lp:juju-quickstart

Proposed by Francesco Banconi
Status: Merged
Merged at revision: 125
Proposed branch: lp:~frankban/juju-quickstart/jujubundlelib
Merge into: lp:juju-quickstart
Diff against target: 908 lines (+27/-639)
13 files modified
quickstart/app.py (+1/-1)
quickstart/charmstore.py (+3/-3)
quickstart/jujutools.py (+5/-4)
quickstart/manage.py (+2/-1)
quickstart/models/bundles.py (+4/-3)
quickstart/models/references.py (+0/-215)
quickstart/tests/models/test_bundles.py (+2/-4)
quickstart/tests/models/test_references.py (+0/-400)
quickstart/tests/test_app.py (+2/-4)
quickstart/tests/test_charmstore.py (+2/-2)
quickstart/tests/test_jujutools.py (+1/-1)
quickstart/tests/test_manage.py (+1/-1)
tox.ini (+4/-0)
To merge this branch: bzr merge lp:~frankban/juju-quickstart/jujubundlelib
Reviewer Review Type Date Requested Status
Juju GUI Hackers Pending
Review via email: mp+256906@code.launchpad.net

Description of the change

Introduce jujubundlelib dependency.

Use the Reference model defined there.

https://codereview.appspot.com/228460043/

To post a comment you must log in.
Revision history for this message
Francesco Banconi (frankban) wrote :

Reviewers: mp+256906_code.launchpad.net,

Message:
Please take a look.

Description:
Introduce jujubundlelib dependency.

Use the Reference model defined there.

https://code.launchpad.net/~frankban/juju-quickstart/jujubundlelib/+merge/256906

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/228460043/

Affected files (+29, -639 lines):
   A [revision details]
   M quickstart/app.py
   M quickstart/charmstore.py
   M quickstart/jujutools.py
   M quickstart/manage.py
   M quickstart/models/bundles.py
   D quickstart/models/references.py
   M quickstart/tests/models/test_bundles.py
   D quickstart/tests/models/test_references.py
   M quickstart/tests/test_app.py
   M quickstart/tests/test_charmstore.py
   M quickstart/tests/test_jujutools.py
   M quickstart/tests/test_manage.py
   M tox.ini

Revision history for this message
Madison Scott-Clary (makyo) wrote :

LGTM, thanks for the work - we'll need to update tox.ini with versions
as tasks shake out from jujubundlelib, but that's fine.

https://codereview.appspot.com/228460043/

Revision history for this message
Francesco Banconi (frankban) wrote :

On 2015/04/22 15:34:12, matthew.scott wrote:
> LGTM, thanks for the work - we'll need to update tox.ini with versions
as tasks
> shake out from jujubundlelib, but that's fine.

Indeed, I'll update the bundlelib version in follow up branches.
Thanks for the review Madison!

https://codereview.appspot.com/228460043/

Revision history for this message
Francesco Banconi (frankban) wrote :

*** Submitted:

Introduce jujubundlelib dependency.

Use the Reference model defined there.

R=matthew.scott
CC=
https://codereview.appspot.com/228460043

https://codereview.appspot.com/228460043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'quickstart/app.py'
2--- quickstart/app.py 2015-03-09 17:50:28 +0000
3+++ quickstart/app.py 2015-04-21 10:32:19 +0000
4@@ -411,7 +411,7 @@
5 Return a tuple including the following values:
6 - charm_ref: the entity reference of the charm that will be used to
7 deploy the service, as an instance of
8- "quickstart.models.references.Reference";
9+ "jujubundlelib.references.Reference";
10 - machine: the machine where to deploy to (e.g. "0") or None if a new
11 machine must be created;
12 - service_data: the service info as returned by the mega-watcher for
13
14=== modified file 'quickstart/charmstore.py'
15--- quickstart/charmstore.py 2015-03-10 10:18:58 +0000
16+++ quickstart/charmstore.py 2015-04-21 10:32:19 +0000
17@@ -59,7 +59,7 @@
18 """Retrieve the charm store contents for the given reference and path.
19
20 The reference argument identifies a charm or bundle entity and must be an
21- instance of "quickstart.models.references.Reference".
22+ instance of "jujubundlelib.references.Reference".
23
24 For instance, to retrieve the hash of a charm reference, use the following:
25
26@@ -101,7 +101,7 @@
27
28 The bundle data is returned as a YAML decoded value.
29 The reference argument identifies a bundle entity and must be an instance
30- of "quickstart.models.references.Reference".
31+ of "jujubundlelib.references.Reference".
32
33 Raise a ValueError if the returned content is not a valid YAML, or if the
34 given reference does not represent a bundle.
35@@ -119,7 +119,7 @@
36 The bundle data is returned as a YAML decoded value and represents the
37 legacy bundle with a top level bundle name node.
38 The reference argument identifies a bundle entity and must be an instance
39- of "quickstart.models.references.Reference".
40+ of "jujubundlelib.references.Reference".
41
42 Raise a ValueError if the returned content is not a valid YAML, or if the
43 given reference does not represent a bundle.
44
45=== modified file 'quickstart/jujutools.py'
46--- quickstart/jujutools.py 2015-02-26 11:02:57 +0000
47+++ quickstart/jujutools.py 2015-04-21 10:32:19 +0000
48@@ -23,11 +23,12 @@
49
50 import logging
51
52+from jujubundlelib import references
53+
54 from quickstart import (
55 serializers,
56 settings,
57 )
58-from quickstart.models import references
59
60
61 def get_api_url(
62@@ -40,8 +41,8 @@
63 Optionally receive a prefix to be used in the path.
64
65 Optionally also receive the Juju GUI charm reference as an instance of
66- "quickstart.models.references.Reference". If provided, the function checks
67- that the corresponding Juju GUI charm supports the new Juju API endpoint.
68+ "jujubundlelib.references.Reference". If provided, the function checks that
69+ the corresponding Juju GUI charm supports the new Juju API endpoint.
70 If not supported, the old endpoint is returned.
71
72 The environment UUID can be None, in which case the old-style API URL
73@@ -104,7 +105,7 @@
74 Print (to stdout or to logs) info and warnings about the charm URL.
75
76 Return the parsed charm reference object as an instance of
77- "quickstart.models.references.Reference".
78+ "jujubundlelib.references.Reference".
79 """
80 print('charm URL: {}'.format(charm_url))
81 ref = references.Reference.from_fully_qualified_url(charm_url)
82
83=== modified file 'quickstart/manage.py'
84--- quickstart/manage.py 2015-03-09 18:53:52 +0000
85+++ quickstart/manage.py 2015-04-21 10:32:19 +0000
86@@ -28,6 +28,8 @@
87 import sys
88 import webbrowser
89
90+from jujubundlelib import references
91+
92 import quickstart
93 from quickstart import (
94 app,
95@@ -45,7 +47,6 @@
96 bundles,
97 envs,
98 jenv,
99- references,
100 )
101
102
103
104=== modified file 'quickstart/models/bundles.py'
105--- quickstart/models/bundles.py 2015-03-10 13:13:42 +0000
106+++ quickstart/models/bundles.py 2015-04-21 10:32:19 +0000
107@@ -22,7 +22,7 @@
108
109 Published bundles are identified by a charm store id and by the corresponding
110 URL in jujucharms.com, just like regular charms. The reference object in
111-"quickstart.models.references.Reference" can be used to identify a bundle.
112+"jujubundlelib.references.Reference" can be used to identify a bundle.
113
114 In this module, the Bundle class represents a bundle that may or may not have
115 a specific reference id. For instance, a reference is not set on a bundle if
116@@ -46,13 +46,14 @@
117 import os
118 import re
119
120+from jujubundlelib import references
121+
122 from quickstart import (
123 charmstore,
124 netutils,
125 serializers,
126 settings,
127 )
128-from quickstart.models import references
129
130
131 class Bundle(object):
132@@ -63,7 +64,7 @@
133
134 The data argument is the bundle YAML decoded content.
135 An optional entity reference can be provided as an instance of
136- "quickstart.models.references.Reference".
137+ "jujubundlelib.references.Reference".
138 """
139 self.data = data
140 self.reference = reference
141
142=== removed file 'quickstart/models/references.py'
143--- quickstart/models/references.py 2015-03-06 17:55:40 +0000
144+++ quickstart/models/references.py 1970-01-01 00:00:00 +0000
145@@ -1,215 +0,0 @@
146-# This file is part of the Juju Quickstart Plugin, which lets users set up a
147-# Juju environment in very few steps (https://launchpad.net/juju-quickstart).
148-# Copyright (C) 2013 Canonical Ltd.
149-#
150-# This program is free software: you can redistribute it and/or modify it under
151-# the terms of the GNU Affero General Public License version 3, as published by
152-# the Free Software Foundation.
153-#
154-# This program is distributed in the hope that it will be useful, but WITHOUT
155-# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
156-# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
157-# Affero General Public License for more details.
158-#
159-# You should have received a copy of the GNU Affero General Public License
160-# along with this program. If not, see <http://www.gnu.org/licenses/>.
161-
162-"""Juju Quickstart charm and bundle references management."""
163-
164-from __future__ import unicode_literals
165-
166-import re
167-
168-from quickstart import settings
169-
170-
171-# The following regular expressions are the same used in juju-core: see
172-# http://bazaar.launchpad.net/~go-bot/juju-core/trunk/view/head:/charm/url.go.
173-USER_PATTERN = r'[a-z0-9][a-zA-Z0-9+.-]+'
174-SERIES_PATTERN = r'[a-z]+(?:[a-z-]+[a-z])?'
175-NAME_PATTERN = r'[a-z][a-z0-9]*(?:-[a-z0-9]*[a-z][a-z0-9]*)*'
176-
177-# Define the callables used to check if entity reference components are valid.
178-_valid_user = re.compile(r'^{}$'.format(USER_PATTERN)).match
179-_valid_series = re.compile(r'^{}$'.format(SERIES_PATTERN)).match
180-_valid_name = re.compile(r'^{}$'.format(NAME_PATTERN)).match
181-
182-# Compile the regular expression used to parse new jujucharms entity URLs.
183-_jujucharms_url_expression = re.compile(r"""
184- ^ # Beginning of the line.
185- (?:
186- (?:{jujucharms})? # Optional jujucharms.com URL.
187- |
188- /? # Optional leading slash.
189- )?
190- (?:u/({user_pattern})/)? # Optional user name.
191- ({name_pattern}) # Bundle name.
192- (?:/({series_pattern}))? # Optional series.
193- (?:/(\d+))? # Optional bundle revision number.
194- /? # Optional trailing slash.
195- $ # End of the line.
196-""".format(
197- jujucharms=settings.JUJUCHARMS_URL,
198- name_pattern=NAME_PATTERN,
199- series_pattern=SERIES_PATTERN,
200- user_pattern=USER_PATTERN,
201-), re.VERBOSE)
202-
203-
204-class Reference(object):
205- """Represent a charm or bundle URL reference."""
206-
207- def __init__(self, schema, user, series, name, revision):
208- """Initialize the reference. Receives the URL fragments."""
209- self.schema = schema
210- self.user = user
211- self.series = series
212- self.name = name
213- if revision is not None:
214- revision = int(revision)
215- self.revision = revision
216- # XXX frankban 2015-02-26: remove the following attribute when
217- # switching to the new bundle format, and when we have a better way
218- # to increase bundle deployments count.
219- self.charmworld_id = None
220-
221- @classmethod
222- def from_fully_qualified_url(cls, url):
223- """Given an entity URL as a string, create and return a Reference.
224-
225- Fully qualified URLs represent the regular entity reference
226- representation in Juju, e.g.: "cs:`~who/vivid/django-42" or
227- "local:bundle/wordpress-0".
228-
229- Raise a ValueError if the provided value is not a valid and fully
230- qualified URL, also including the schema and the revision.
231- """
232- return cls(*_parse_fully_qualified_url(url))
233-
234- @classmethod
235- def from_jujucharms_url(cls, url):
236- """Create and return a Reference from the given jujucharms.com URL.
237-
238- These are the preferred way to refer to a charm or bundle in Juju
239- Quickstart. They basically look like the URL paths in jujucharms.com,
240- e.g. "u/who/django", "mediawiki/42" or just "mediawiki". The full HTTP
241- URL can be also provided, for instance "https://jujucharms.com/django".
242-
243- Raise a ValueError if the provided URL is not valid.
244- """
245- match = _jujucharms_url_expression.match(url)
246- if match is None:
247- msg = 'invalid bundle URL: {}'.format(url)
248- raise ValueError(msg.encode('utf-8'))
249- user, name, series, revision = match.groups()
250- return cls('cs', user, series or 'bundle', name, revision)
251-
252- def __str__(self):
253- """The string representation of a reference is its URL string."""
254- return self.__unicode__().encode('utf-8')
255-
256- def __unicode__(self):
257- """The unicode representation of a reference is its URL string."""
258- return self.id()
259-
260- def __repr__(self):
261- return b'<Reference: {}>'.format(bytes(self))
262-
263- def __eq__(self, other):
264- """Two refs are equal if they have the same string representation."""
265- return isinstance(other, self.__class__) and self.id() == other.id()
266-
267- def path(self):
268- """Return the reference as a string without the schema."""
269- user_part = '~{}/'.format(self.user) if self.user else ''
270- revision_part = ''
271- if self.revision is not None:
272- revision_part = '-{}'.format(self.revision)
273- return '{}{}/{}{}'.format(
274- user_part, self.series, self.name, revision_part)
275-
276- def id(self):
277- """Return the reference URL as a string."""
278- return '{}:{}'.format(self.schema, self.path())
279-
280- def jujucharms_id(self):
281- """Return the identifier of this reference in jujucharms.com."""
282- user_part = 'u/{}/'.format(self.user) if self.user else ''
283- series_part = '' if self.is_bundle() else '/{}'.format(self.series)
284- revision_part = ''
285- if self.revision is not None:
286- revision_part = '/{}'.format(self.revision)
287- return '{}{}{}{}'.format(
288- user_part, self.name, series_part, revision_part)
289-
290- def jujucharms_url(self):
291- """Return the URL where this entity lives in jujucharms.com."""
292- return settings.JUJUCHARMS_URL + self.jujucharms_id()
293-
294- def is_bundle(self):
295- """Report whether this reference refers to a bundle entity."""
296- return self.series == 'bundle'
297-
298- def is_local(self):
299- """Return True if this refers to a local entity, False otherwise."""
300- return self.schema == 'local'
301-
302-
303-def _parse_fully_qualified_url(url):
304- """Parse the given charm or bundle URL, provided as a string.
305-
306- Return a tuple containing the entity reference fragments: schema, user,
307- series, name and revision. Each fragment is a string except revision (int).
308-
309- Raise a ValueError with a descriptive message if the given URL is not a
310- valid and fully qualified entity URL.
311- """
312- # Retrieve the schema.
313- try:
314- schema, remaining = url.split(':', 1)
315- except ValueError:
316- msg = 'URL has no schema: {}'.format(url)
317- raise ValueError(msg.encode('utf-8'))
318- if schema not in ('cs', 'local'):
319- msg = 'URL has invalid schema: {}'.format(schema)
320- raise ValueError(msg.encode('utf-8'))
321- # Retrieve the optional user, the series, name and revision.
322- parts = remaining.split('/')
323- parts_length = len(parts)
324- if parts_length == 3:
325- user, series, name_revision = parts
326- if not user.startswith('~'):
327- msg = 'URL has invalid user name form: {}'.format(user)
328- raise ValueError(msg.encode('utf-8'))
329- user = user[1:]
330- if not _valid_user(user):
331- msg = 'URL has invalid user name: {}'.format(user)
332- raise ValueError(msg.encode('utf-8'))
333- if schema == 'local':
334- msg = 'local entity URL with user name: {}'.format(url)
335- raise ValueError(msg.encode('utf-8'))
336- elif parts_length == 2:
337- user = ''
338- series, name_revision = parts
339- else:
340- msg = 'URL has invalid form: {}'.format(url)
341- raise ValueError(msg.encode('utf-8'))
342- # Validate the series.
343- if not _valid_series(series):
344- msg = 'URL has invalid series: {}'.format(series)
345- raise ValueError(msg.encode('utf-8'))
346- # Validate name and revision.
347- try:
348- name, revision = name_revision.rsplit('-', 1)
349- except ValueError:
350- msg = 'URL has no revision: {}'.format(url)
351- raise ValueError(msg.encode('utf-8'))
352- if not _valid_name(name):
353- msg = 'URL has invalid name: {}'.format(name)
354- raise ValueError(msg.encode('utf-8'))
355- try:
356- revision = int(revision)
357- except ValueError:
358- msg = 'URL has invalid revision: {}'.format(revision)
359- raise ValueError(msg.encode('utf-8'))
360- return schema, user, series, name, revision
361
362=== modified file 'quickstart/tests/models/test_bundles.py'
363--- quickstart/tests/models/test_bundles.py 2015-03-10 13:13:42 +0000
364+++ quickstart/tests/models/test_bundles.py 2015-04-21 10:32:19 +0000
365@@ -21,6 +21,7 @@
366 import json
367 import unittest
368
369+from jujubundlelib import references
370 import mock
371 import yaml
372
373@@ -28,10 +29,7 @@
374 netutils,
375 settings,
376 )
377-from quickstart.models import (
378- bundles,
379- references,
380-)
381+from quickstart.models import bundles
382 from quickstart.tests import helpers
383
384
385
386=== removed file 'quickstart/tests/models/test_references.py'
387--- quickstart/tests/models/test_references.py 2015-03-09 17:50:28 +0000
388+++ quickstart/tests/models/test_references.py 1970-01-01 00:00:00 +0000
389@@ -1,400 +0,0 @@
390-# This file is part of the Juju Quickstart Plugin, which lets users set up a
391-# Juju environment in very few steps (https://launchpad.net/juju-quickstart).
392-# Copyright (C) 2013 Canonical Ltd.
393-#
394-# This program is free software: you can redistribute it and/or modify it under
395-# the terms of the GNU Affero General Public License version 3, as published by
396-# the Free Software Foundation.
397-#
398-# This program is distributed in the hope that it will be useful, but WITHOUT
399-# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
400-# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
401-# Affero General Public License for more details.
402-#
403-# You should have received a copy of the GNU Affero General Public License
404-# along with this program. If not, see <http://www.gnu.org/licenses/>.
405-
406-"""Tests for the Juju Quickstart charm and bundle references management."""
407-
408-from __future__ import unicode_literals
409-
410-import unittest
411-
412-from quickstart import settings
413-from quickstart.models import references
414-from quickstart.tests import helpers
415-
416-
417-def make_reference(
418- schema='cs', user='myuser', series='precise', name='juju-gui',
419- revision=42):
420- """Create and return a Reference instance."""
421- return references.Reference(schema, user, series, name, revision)
422-
423-
424-class TestReference(unittest.TestCase):
425-
426- def test_attributes(self):
427- # All reference attributes are correctly stored.
428- ref = make_reference()
429- self.assertEqual('cs', ref.schema)
430- self.assertEqual('myuser', ref.user)
431- self.assertEqual('precise', ref.series)
432- self.assertEqual('juju-gui', ref.name)
433- self.assertEqual(42, ref.revision)
434-
435- def test_revision_as_string(self):
436- # The reference revision is converted to an int.
437- ref = make_reference(revision='47')
438- self.assertEqual(47, ref.revision)
439-
440- def test_string(self):
441- # The string representation of a reference is its URL.
442- tests = (
443- (make_reference(),
444- 'cs:~myuser/precise/juju-gui-42'),
445- (make_reference(schema='local'),
446- 'local:~myuser/precise/juju-gui-42'),
447- (make_reference(user=''),
448- 'cs:precise/juju-gui-42'),
449- (make_reference(user='dalek', revision=None, series='bundle'),
450- 'cs:~dalek/bundle/juju-gui'),
451- (make_reference(name='django', series='vivid', revision=0),
452- 'cs:~myuser/vivid/django-0'),
453- (make_reference(user='', revision=None),
454- 'cs:precise/juju-gui'),
455- )
456- for ref, expected_value in tests:
457- self.assertEqual(expected_value, bytes(ref))
458-
459- def test_repr(self):
460- # A reference is correctly represented.
461- tests = (
462- (make_reference(),
463- '<Reference: cs:~myuser/precise/juju-gui-42>'),
464- (make_reference(schema='local'),
465- '<Reference: local:~myuser/precise/juju-gui-42>'),
466- (make_reference(user=''),
467- '<Reference: cs:precise/juju-gui-42>'),
468- (make_reference(user='dalek', revision=None, series='bundle'),
469- '<Reference: cs:~dalek/bundle/juju-gui>'),
470- (make_reference(name='django', series='vivid', revision=0),
471- '<Reference: cs:~myuser/vivid/django-0>'),
472- (make_reference(user='', revision=None),
473- '<Reference: cs:precise/juju-gui>'),
474- )
475- for ref, expected_value in tests:
476- self.assertEqual(expected_value, repr(ref))
477-
478- def test_path(self):
479- # The reference path is properly returned as a URL string without the
480- # schema.
481- tests = (
482- (make_reference(),
483- '~myuser/precise/juju-gui-42'),
484- (make_reference(schema='local'),
485- '~myuser/precise/juju-gui-42'),
486- (make_reference(user=''),
487- 'precise/juju-gui-42'),
488- (make_reference(user='dalek', revision=None, series='bundle'),
489- '~dalek/bundle/juju-gui'),
490- (make_reference(name='django', series='vivid', revision=0),
491- '~myuser/vivid/django-0'),
492- (make_reference(user='', revision=None),
493- 'precise/juju-gui'),
494- )
495- for ref, expected_value in tests:
496- self.assertEqual(expected_value, ref.path())
497-
498- def test_id(self):
499- # The reference id is correctly returned.
500- tests = (
501- (make_reference(),
502- 'cs:~myuser/precise/juju-gui-42'),
503- (make_reference(schema='local'),
504- 'local:~myuser/precise/juju-gui-42'),
505- (make_reference(user=''),
506- 'cs:precise/juju-gui-42'),
507- (make_reference(user='dalek', revision=None, series='bundle'),
508- 'cs:~dalek/bundle/juju-gui'),
509- (make_reference(name='django', series='vivid', revision=0),
510- 'cs:~myuser/vivid/django-0'),
511- (make_reference(user='', revision=None),
512- 'cs:precise/juju-gui'),
513- )
514- for ref, expected_value in tests:
515- self.assertEqual(expected_value, ref.id())
516-
517- def test_jujucharms_id(self):
518- # It is possible to return the reference identifier in jujucharms.com.
519- tests = (
520- (make_reference(),
521- 'u/myuser/juju-gui/precise/42'),
522- (make_reference(schema='local'),
523- 'u/myuser/juju-gui/precise/42'),
524- (make_reference(user=''),
525- 'juju-gui/precise/42'),
526- (make_reference(user='dalek', revision=None, series='bundle'),
527- 'u/dalek/juju-gui'),
528- (make_reference(name='django', series='vivid', revision=0),
529- 'u/myuser/django/vivid/0'),
530- (make_reference(user='', revision=None),
531- 'juju-gui/precise'),
532- (make_reference(user='', series='bundle', revision=None),
533- 'juju-gui'),
534- )
535- for ref, expected_value in tests:
536- self.assertEqual(expected_value, ref.jujucharms_id())
537-
538- def test_jujucharms_url(self):
539- # The corresponding charm or bundle page in jujucharms.com is correctly
540- # returned.
541- tests = (
542- (make_reference(),
543- 'u/myuser/juju-gui/precise/42'),
544- (make_reference(schema='local'),
545- 'u/myuser/juju-gui/precise/42'),
546- (make_reference(user=''),
547- 'juju-gui/precise/42'),
548- (make_reference(user='dalek', revision=None, series='bundle'),
549- 'u/dalek/juju-gui'),
550- (make_reference(name='django', series='vivid', revision=0),
551- 'u/myuser/django/vivid/0'),
552- (make_reference(user='', revision=None),
553- 'juju-gui/precise'),
554- (make_reference(user='', series='bundle', revision=None),
555- 'juju-gui'),
556- )
557- for ref, expected_value in tests:
558- expected_url = settings.JUJUCHARMS_URL + expected_value
559- self.assertEqual(expected_url, ref.jujucharms_url())
560-
561- def test_charm_entity(self):
562- # The is_bundle method returns False for charm references.
563- ref = make_reference(series='vivid')
564- self.assertFalse(ref.is_bundle())
565-
566- def test_bundle_entity(self):
567- # The is_bundle method returns True for bundle references.
568- ref = make_reference(series='bundle')
569- self.assertTrue(ref.is_bundle())
570-
571- def test_charm_store_entity(self):
572- # The is_local method returns False for charm store references.
573- ref = make_reference(schema='cs')
574- self.assertFalse(ref.is_local())
575-
576- def test_local_entity(self):
577- # The is_local method returns True for local references.
578- ref = make_reference(schema='local')
579- self.assertTrue(ref.is_local())
580-
581- def test_equality(self):
582- # Two references are equal if they have the same URL.
583- self.assertEqual(make_reference(), make_reference())
584- self.assertEqual(make_reference(user=''), make_reference(user=''))
585- self.assertEqual(
586- make_reference(revision=None), make_reference(revision=None))
587-
588- def test_equality_different_references(self):
589- # Two references with different attributes are not equal.
590- tests = (
591- (make_reference(schema='cs'),
592- make_reference(schema='local')),
593- (make_reference(user=''),
594- make_reference(user='who')),
595- (make_reference(series='trusty'),
596- make_reference(series='vivid')),
597- (make_reference(name='django'),
598- make_reference(name='rails')),
599- (make_reference(revision=0),
600- make_reference(revision=1)),
601- (make_reference(revision=None),
602- make_reference(revision=42)),
603- )
604- for ref1, ref2 in tests:
605- self.assertNotEqual(ref1, ref2)
606-
607- def test_equality_different_types(self):
608- # A reference never equals a non-reference object.
609- self.assertNotEqual(make_reference(), 42)
610- self.assertNotEqual(make_reference(), True)
611- self.assertNotEqual(make_reference(), 'oranges')
612-
613- def test_charmworld_id(self):
614- # By default, the reference id in charmworld is set to None.
615- # XXX frankban 2015-02-26: remove this test once we get rid of the
616- # charmworld id concept.
617- ref = make_reference()
618- self.assertIsNone(ref.charmworld_id)
619-
620-
621-class TestReferenceFromFullyQualifiedUrl(
622- helpers.ValueErrorTestsMixin, unittest.TestCase):
623-
624- def test_no_schema_error(self):
625- # A ValueError is raised if the URL schema is missing.
626- expected_error = 'URL has no schema: precise/juju-gui'
627- with self.assert_value_error(expected_error):
628- references.Reference.from_fully_qualified_url('precise/juju-gui')
629-
630- def test_invalid_schema_error(self):
631- # A ValueError is raised if the URL schema is not valid.
632- expected_error = 'URL has invalid schema: http'
633- with self.assert_value_error(expected_error):
634- references.Reference.from_fully_qualified_url(
635- 'http:precise/juju-gui')
636-
637- def test_invalid_user_form_error(self):
638- # A ValueError is raised if the user form is not valid.
639- expected_error = 'URL has invalid user name form: jean-luc'
640- with self.assert_value_error(expected_error):
641- references.Reference.from_fully_qualified_url(
642- 'cs:jean-luc/precise/juju-gui')
643-
644- def test_invalid_user_name_error(self):
645- # A ValueError is raised if the user name is not valid.
646- expected_error = 'URL has invalid user name: jean:luc'
647- with self.assert_value_error(expected_error):
648- references.Reference.from_fully_qualified_url(
649- 'cs:~jean:luc/precise/juju-gui')
650-
651- def test_local_user_name_error(self):
652- # A ValueError is raised if a user is specified on a local entity.
653- expected_error = (
654- 'local entity URL with user name: '
655- 'local:~jean-luc/precise/juju-gui')
656- with self.assert_value_error(expected_error):
657- references.Reference.from_fully_qualified_url(
658- 'local:~jean-luc/precise/juju-gui')
659-
660- def test_invalid_form_error(self):
661- # A ValueError is raised if the URL is not valid.
662- expected_error = 'URL has invalid form: cs:~user/series/name/what-?'
663- with self.assert_value_error(expected_error):
664- references.Reference.from_fully_qualified_url(
665- 'cs:~user/series/name/what-?')
666-
667- def test_invalid_series_error(self):
668- # A ValueError is raised if the series is not valid.
669- expected_error = 'URL has invalid series: boo!'
670- with self.assert_value_error(expected_error):
671- references.Reference.from_fully_qualified_url(
672- 'cs:boo!/juju-gui-42')
673-
674- def test_no_revision_error(self):
675- # A ValueError is raised if the entity revision is missing.
676- expected_error = 'URL has no revision: cs:series/name'
677- with self.assert_value_error(expected_error):
678- references.Reference.from_fully_qualified_url('cs:series/name')
679-
680- def test_invalid_revision_error(self):
681- # A ValueError is raised if the charm or bundle revision is not valid.
682- expected_error = 'URL has invalid revision: revision'
683- with self.assert_value_error(expected_error):
684- references.Reference.from_fully_qualified_url(
685- 'cs:series/name-revision')
686-
687- def test_invalid_name_error(self):
688- # A ValueError is raised if the entity name is not valid.
689- expected_error = 'URL has invalid name: not:valid'
690- with self.assert_value_error(expected_error):
691- references.Reference.from_fully_qualified_url(
692- 'cs:precise/not:valid-42')
693-
694- def test_success(self):
695- # References are correctly instantiated by parsing the fully qualified
696- # URL.
697- tests = (
698- ('cs:~myuser/precise/juju-gui-42',
699- make_reference()),
700- ('cs:trusty/juju-gui-42',
701- make_reference(user='', series='trusty')),
702- ('local:precise/juju-gui-42',
703- make_reference(schema='local', user='')),
704- )
705- for url, expected_ref in tests:
706- ref = references.Reference.from_fully_qualified_url(url)
707- self.assertEqual(expected_ref, ref)
708-
709-
710-class TestReferenceFromJujucharmsUrl(
711- helpers.ValueErrorTestsMixin, unittest.TestCase):
712-
713- def test_invalid_form(self):
714- # A ValueError is raised if the URL is not valid.
715- expected_error = 'invalid bundle URL: bad wolf'
716- with self.assert_value_error(expected_error):
717- references.Reference.from_jujucharms_url('bad wolf')
718-
719- def test_success(self):
720- # A reference is correctly created from a jujucharms.com identifier or
721- # complete URL.
722- tests = (
723- # Check with both user and revision.
724- ('u/myuser/mediawiki/42',
725- make_reference(series='bundle', name='mediawiki')),
726- ('/u/myuser/mediawiki/42',
727- make_reference(series='bundle', name='mediawiki')),
728- ('u/myuser/django-scalable/42/',
729- make_reference(series='bundle', name='django-scalable')),
730- ('{}u/myuser/mediawiki/42'.format(settings.JUJUCHARMS_URL),
731- make_reference(series='bundle', name='mediawiki')),
732- ('{}u/myuser/mediawiki/42/'.format(settings.JUJUCHARMS_URL),
733- make_reference(series='bundle', name='mediawiki')),
734-
735- # Check without revision.
736- ('u/myuser/mediawiki',
737- make_reference(series='bundle', name='mediawiki', revision=None)),
738- ('/u/myuser/wordpress',
739- make_reference(series='bundle', name='wordpress', revision=None)),
740- ('u/myuser/mediawiki/',
741- make_reference(series='bundle', name='mediawiki', revision=None)),
742- ('{}u/myuser/django'.format(settings.JUJUCHARMS_URL),
743- make_reference(series='bundle', name='django', revision=None)),
744- ('{}u/myuser/mediawiki/'.format(settings.JUJUCHARMS_URL),
745- make_reference(series='bundle', name='mediawiki', revision=None)),
746-
747- # Check without the user.
748- ('rails-single/42',
749- make_reference(user='', series='bundle', name='rails-single')),
750- ('/mediawiki/42',
751- make_reference(user='', series='bundle', name='mediawiki')),
752- ('rails-scalable/42/',
753- make_reference(user='', series='bundle', name='rails-scalable')),
754- ('{}mediawiki/42'.format(settings.JUJUCHARMS_URL),
755- make_reference(user='', series='bundle', name='mediawiki')),
756- ('{}django/42/'.format(settings.JUJUCHARMS_URL),
757- make_reference(user='', series='bundle', name='django')),
758-
759- # Check without user and revision.
760- ('mediawiki',
761- make_reference(user='', series='bundle', name='mediawiki',
762- revision=None)),
763- ('/wordpress',
764- make_reference(user='', series='bundle', name='wordpress',
765- revision=None)),
766- ('mediawiki/',
767- make_reference(user='', series='bundle', name='mediawiki',
768- revision=None)),
769- ('{}django'.format(settings.JUJUCHARMS_URL),
770- make_reference(user='', series='bundle', name='django',
771- revision=None)),
772- ('{}mediawiki/'.format(settings.JUJUCHARMS_URL),
773- make_reference(user='', series='bundle', name='mediawiki',
774- revision=None)),
775-
776- # Check charm entities.
777- ('mediawiki/trusty/0',
778- make_reference(user='', series='trusty', name='mediawiki',
779- revision=0)),
780- ('/wordpress/precise',
781- make_reference(user='', series='precise', name='wordpress',
782- revision=None)),
783- ('u/who/rails/vivid',
784- make_reference(user='who', series='vivid', name='rails',
785- revision=None)),
786- )
787- for url, expected_ref in tests:
788- ref = references.Reference.from_jujucharms_url(url)
789- self.assertEqual(expected_ref, ref)
790
791=== modified file 'quickstart/tests/test_app.py'
792--- quickstart/tests/test_app.py 2015-03-10 11:08:00 +0000
793+++ quickstart/tests/test_app.py 2015-04-21 10:32:19 +0000
794@@ -23,6 +23,7 @@
795 import os
796 import unittest
797
798+from jujubundlelib import references
799 import jujuclient
800 import mock
801 import yaml
802@@ -32,10 +33,7 @@
803 platform_support,
804 settings,
805 )
806-from quickstart.models import (
807- bundles,
808- references,
809-)
810+from quickstart.models import bundles
811 from quickstart.tests import helpers
812
813
814
815=== modified file 'quickstart/tests/test_charmstore.py'
816--- quickstart/tests/test_charmstore.py 2015-03-10 10:18:58 +0000
817+++ quickstart/tests/test_charmstore.py 2015-04-21 10:32:19 +0000
818@@ -18,16 +18,16 @@
819
820 from __future__ import unicode_literals
821
822+import json
823 import unittest
824
825-import json
826+from jujubundlelib import references
827
828 from quickstart import (
829 charmstore,
830 netutils,
831 settings,
832 )
833-from quickstart.models import references
834 from quickstart.tests import helpers
835
836
837
838=== modified file 'quickstart/tests/test_jujutools.py'
839--- quickstart/tests/test_jujutools.py 2015-02-26 18:57:25 +0000
840+++ quickstart/tests/test_jujutools.py 2015-04-21 10:32:19 +0000
841@@ -20,11 +20,11 @@
842
843 import unittest
844
845+from jujubundlelib import references
846 import mock
847 import yaml
848
849 from quickstart import jujutools
850-from quickstart.models import references
851 from quickstart.tests import helpers
852
853
854
855=== modified file 'quickstart/tests/test_manage.py'
856--- quickstart/tests/test_manage.py 2015-02-26 19:12:17 +0000
857+++ quickstart/tests/test_manage.py 2015-04-21 10:32:19 +0000
858@@ -26,6 +26,7 @@
859 import StringIO as io
860 import unittest
861
862+from jujubundlelib import references
863 import mock
864 import yaml
865
866@@ -42,7 +43,6 @@
867 bundles,
868 envs,
869 jenv,
870- references,
871 )
872 from quickstart.tests import helpers
873
874
875=== modified file 'tox.ini'
876--- tox.ini 2015-02-27 10:30:20 +0000
877+++ tox.ini 2015-04-21 10:32:19 +0000
878@@ -72,6 +72,7 @@
879 # See https://launchpad.net/~juju/+archive/ubuntu/stable.
880 websocket-client==0.18.0
881 jujuclient==0.50.1
882+ jujubundlelib==0.1.1
883 urwid==1.2.1
884 # The distribution PyYAML requirement is used in this case.
885
886@@ -81,6 +82,7 @@
887 # Ubuntu 14.04 (trusty) distro dependencies.
888 websocket-client==0.12.0
889 jujuclient==0.17.5
890+ jujubundlelib==0.1.1
891 PyYAML==3.10
892 urwid==1.1.1
893
894@@ -90,6 +92,7 @@
895 # Ubuntu 14.10 (utopic) distro dependencies.
896 websocket-client==0.12.0
897 jujuclient==0.17.5
898+ jujubundlelib==0.1.1
899 PyYAML==3.11
900 urwid==1.2.1
901
902@@ -99,6 +102,7 @@
903 # Ubuntu 15.04 (vivid) distro dependencies.
904 websocket-client==0.18.0
905 jujuclient==0.18.5
906+ jujubundlelib==0.1.1
907 PyYAML==3.11
908 urwid==1.2.1
909

Subscribers

People subscribed via source and target branches