launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #01282
Re: [Merge] lp:~mbp/launchpad/flags-gui into lp:launchpad/devel
Hi Martin,
Following up in two parts. This is part one. I, too, will skip the parts I agree with and which seem to require no further action.
> > 1 === added directory 'lib/lp/services/features/browser'
> > 2 === added file 'lib/lp/services/features/browser/__init__.py'
> > 3 --- lib/lp/services/features/browser/__init__.py 1970-01-01
> 00:00:00 +0000
> > 4 +++ lib/lp/services/features/browser/__init__.py 2010-09-27
> 08:17:44 +0000
> > 5 @@ -0,0 +1,45 @@
> > 6 +# Copyright 2010 Canonical Ltd. This software is licensed under the
> > 7 +# GNU Affero General Public License version 3 (see the file
> LICENSE).
> >
> > I don't much care for putting code in __init__.py. I can see that it keeps
> the imports shorter, but it's unusual enough that it may be easy to miss.
>
> OK. Can I make it just browser.py, or should I have a submodule with
> a named file within it?
If a nontrivial __init__.py is already a normal thing to write, then there's no reason to worry about it here after all. So it's fine to leave it as it is.
> > 91 === added file
> 'lib/lp/services/features/browser/tests/test_feature_editor.py'
> > 92 --- lib/lp/services/features/browser/tests/test_feature_editor.py
> 1970-01-01 00:00:00 +0000
> > 93 +++ lib/lp/services/features/browser/tests/test_feature_editor.py
> 2010-09-27 08:17:44 +0000
> >
> > 130 +class TestFeatureControlPage(BrowserTestCase):
> > 131 +
> > 132 + layer = DatabaseFunctionalLayer
> > 133 +
> > 134 + def getUserBrowserAsTeamMember(self, url, teams):
> > 135 + """Make a TestBrowser authenticated as a team member.
> > 136 +
> > 137 + :param teams: List of teams to add the new user to.
> > 138 + """
> >
> > This method dithers between being a test setup helper and a test
> verification helper. Things end up muddled: when you expect
> getUserBrowserAsTeamMember to raise an authorization error, you're making an
> assertion about the "open the page" part but the code makes it look as if
> you're talking about the "add user to teams" part instead.
>
> Hm, so perhaps (if it's possible) it would be clearer to write something like:
>
> browser = getUserBrowserAsTeamMember(teams)
> self.assertRaises(Unauthorized, browser.open(url))
Yes, exactly. And AFAICS that should work.
> > 152 + def getFeaturePageBrowserAsAdmin(self):
> > 153 + url = self.getFeatureRulesURL()
> > 154 + admin_team = getUtility(ILaunchpadCelebrities).admin
> > 155 + return self.getUserBrowserAsTeamMember(url, [admin_team])
> >
> > It looks to me as if BrowserTestCase ought to have a "getAdminBrowser."
> Have you considered creating one?
>
> Right, that's bug 646563, but this branch is getting big enough already.
Very well.
> > 165 + def test_feature_page_from_database(self):
> > 166 + addFeatureFlagRules([
> > 167 + ('default', 'ui.icing', u'3.0', 100),
> > 168 + ('beta_user', 'ui.icing', u'4.0', 300),
> > 169 + ])
> > 170 + browser = self.getFeaturePageBrowserAsAdmin()
> > 171 + textarea = browser.getControl(name="feature_rules")
> > 172 + self.assertThat(textarea.value.replace('\r', ''),
> Equals("""\
> > 173 +ui.icing\tbeta_user\t300\t4.0
> > 174 +ui.icing\tdefault\t100\t3.0
> > 175 +"""))
> >
> > Try BrowserTestCase.assertTextMatchesExpressionIgnoreWhitespace instead.
> It's not great, so feel free to improve it and help everyone. (Also, if you
> find yourself dedenting manually like this in the future, consider using
> textwrap.dedent).
>
> Are we actually better off ignoring whitespace? Perhaps so. If I was
> going to change it, I'd change it into a testtools Matcher.
I think ignoring whitespace would be a fine thing to do, assuming that a separate test verifies that the whitespace conforms to expectations.
A Matcher would be very nice here.
> > If you do activate the commented-out code, please use one of the accepted
> line-breaking styles for the assertion. If not, remove this test altogether
> and file a separate bug.
>
> iow with the first line break immediately after the opening parenthesis.
Precisely.
> > 322 === modified file 'lib/lp/services/features/model.py'
> > 323 --- lib/lp/services/features/model.py 2010-08-20 20:31:18 +0000
> > 324 +++ lib/lp/services/features/model.py 2010-09-27 08:17:44 +0000
> >
> > 347 +def addFeatureFlagRules(rule_list):
> >
> > A standalone function should follow the lower_case_with_underscores naming
> convention.
>
> stand_alone_function vs objectMethod? omg.
Indeed. Since PEP8 prescribes lower_case_with_underscores, we may start accepting that in both cases. But dromedaryCase for stand-alone functions is not OK either way.
> > 348 + """Add rules in to the database; intended for use in testing.
> >
> > Then shouldn't it live in lp.testing? Call it makeFeatureFlagRule and it'd
> fit perfectly in the LaunchpadObjectFactory.
>
> Actually I think for most testing, we want to just change the
> featurecontroller, not actually change the database. And perhaps it
> should be a test fixture not on that monolith class?
I could imagine a need for both "create a rule in the database" and "create a rule in whatever rules source I'm currently using." Which you want this function for is up to you, and I defer to your judgment.
> > 360 === added file 'lib/lp/services/features/rulesource.py'
> > 361 --- lib/lp/services/features/rulesource.py 1970-01-01 00:00:00
> +0000
> > 362 +++ lib/lp/services/features/rulesource.py 2010-09-27 08:17:44
> +0000
> > 363 @@ -0,0 +1,90 @@
> > 364 +# Copyright 2010 Canonical Ltd. This software is licensed under
> the
> > 365 +# GNU Affero General Public License version 3 (see the file
> LICENSE).
> > 366 +
> > 367 +"""Returns rules defining which features are active"""
> >
> > This looks like a function docstring. Could you make it applicable to the
> module as a whole?
>
> Do you mean, rephrase it so it talks about what kind of thing the
> module contains, rather than what the class does.
Right.
> > I'm not sure about the design of this module. Separating out the storage
> layer is obviously very useful, and it looks as if you could do with a
> setAllRules in NullFeatureRuleSource as well. But the testing code and
> production-usable code live very close together here. Wouldn't it be more
> appropriate (and consistent with our existing codebase) to have a functional
> FeatureRuleSource for production, plus a FakeRuleSource in lp.testing that
> overrides the two storage methods?
>
> If the consistent pattern is that implementations only for testing use
> go into lp.testing then I'll move it there.
I think it is, yes. A right little fakes library is forming there. Before that, we usually put most such things in the individual tests. (And, as you're probably about to say, repeated them a lot).
More to follow in part two!
--
https://code.launchpad.net/~mbp/launchpad/flags-gui/+merge/36415
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~mbp/launchpad/flags-gui into lp:launchpad/devel.
Follow ups