Bug 68991 - watchlist: Add a way to load the watchlist from config.
Summary: watchlist: Add a way to load the watchlist from config.
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Tools / Tests (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: David Levin
URL:
Keywords:
Depends on:
Blocks: 68822
  Show dependency treegraph
 
Reported: 2011-09-28 03:33 PDT by David Levin
Modified: 2011-09-28 15:00 PDT (History)
2 users (show)

See Also:


Attachments
Patch (7.21 KB, patch)
2011-09-28 03:37 PDT, David Levin
no flags Details | Formatted Diff | Diff
Patch (11.07 KB, patch)
2011-09-28 12:06 PDT, David Levin
no flags Details | Formatted Diff | Diff
Patch (11.09 KB, patch)
2011-09-28 12:10 PDT, David Levin
no flags Details | Formatted Diff | Diff
Patch (10.78 KB, patch)
2011-09-28 13:46 PDT, David Levin
eric: review+
eric: commit-queue-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description David Levin 2011-09-28 03:33:24 PDT
See summary.
Comment 1 David Levin 2011-09-28 03:37:08 PDT
Created attachment 108996 [details]
Patch
Comment 2 Adam Barth 2011-09-28 09:53:42 PDT
Comment on attachment 108996 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=108996&action=review

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:31
> +from webkitpy.common.watchlist.watchlistparser import WatchListParser

We usually put a blank line between the system imports and the webkitpy imports.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:39
> +    def _attempt_file_load(self, path, watchlist_filename):
> +        try:
> +            return open(os.path.join(path, watchlist_filename), 'r').read()
> +        except:
> +            return None

Rather than talking directly to the file system, we use the filesystem abstraction.  That lets us test this sort of code without talking to the real filesystem via dependency injection.  This class should take a filesystem object as a parameter, which we'll eventually get from the tool (aka host) object given to the command.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader_unittest.py:37
> +def _return_none(*args):
> +    return None

You can write this inline using  lambda.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader_unittest.py:46
> +    def _verifyException(self, regex_message, callable, *args):

Rather than copy/pasting this code, can we create a subclass of unittest.TestCase that adds this functionality and then derive our test classes from it?

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader_unittest.py:58
> +    def test_watch_list_not_found(self):
> +        loader = WatchListLoader()
> +        loader._attempt_file_load = _return_none
> +        self.assertRaisesRegexp(r'Watch list file \(webkitpy/common/config/watchlist\) not found in the python search path\.',
> +                                loader.load)

Here you'll want to use a MockFilesystem, which you can populate with test data.
Comment 3 David Levin 2011-09-28 12:06:17 PDT
Created attachment 109049 [details]
Patch
Comment 4 David Levin 2011-09-28 12:10:58 PDT
Created attachment 109051 [details]
Patch
Comment 5 David Levin 2011-09-28 12:11:31 PDT
All fixed.
Comment 6 Eric Seidel (no email) 2011-09-28 12:58:46 PDT
Comment on attachment 109051 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=109051&action=review

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:30
> +import os
> +import sys

You should rarely, if ever need eithe rof these.  FielSystem, Executive and User modules should provide this all in a cross-platform, mockable way.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:40
> +        current_filename = os.path.join(path, watchlist_filename)

self._filesystem.join

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:42
> +            return self._filesystem.read_text_file(current_filename)

You could also pair this with an exists() instead, if you're just tryign to catch the "does not exist" case.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:47
> +        watchlist_filename = os.path.join('webkitpy', 'common', 'config', 'watchlist')

You're assuming we're being run from Scripts... which isn't always true.  You probably want to use filesystem.path_to_module(self)

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:48
> +        for path in sys.path:

I see.  We don't have this abstracted anywhere, so you have to use sys for sys.path.  But I'm confused why you'd look in sys.path?  That's the python lookup path for modules?

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:51
> +            contents = self._attempt_file_load(path, watchlist_filename)
> +            if contents is not None:
> +                return contents

Seems you just want to pair exists with the read here, and remove _attempt_file_load.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader_unittest.py:40
> +        loader = WatchListLoader(filesystem_mock.MockFileSystem())
> +        self.assertRaisesRegexp(r'Watch list file \(webkitpy/common/config/watchlist\) not found in the python search path\.',

You can test that it's not found, and then test what happens when it is found, both with a MockFileSystem.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader_unittest.py:45
> +        WatchListLoader(filesystem.FileSystem()).load()

It's rare that you want to use a real filesystem in a unittest.
Comment 7 Adam Barth 2011-09-28 13:03:13 PDT
Comment on attachment 109051 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=109051&action=review

This is looking good.  Let do one more iteration.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:40
> +        current_filename = os.path.join(path, watchlist_filename)

self._filesystem.join <-- makes unit testing easier on Mac and Windows.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:47
> +        watchlist_filename = os.path.join('webkitpy', 'common', 'config', 'watchlist')

Does this assume something about the current working directory?

You probably want something relative to the current source directory, which is something the Checkout class knows about.  Another alternative is to find the file relative to the currently executing python.  These are different, for example, if you run the webkit-patch script from one webkit checkout while the current working directory is in another.

I'd expect this to work like commiters.py, which is to say relative to the executing python (as if loaded as a module).  You can use:

self._filesystem.path_to_module(WatchListLoader)

Going through self._filesystem makes this easy to mock during testing.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:52
> +        raise Exception('Watch list file (%s) not found in the python search path.' % watchlist_filename)

I'm not sure "python search path" is what you mean here.  Why not just say that a given path was not found?
Comment 8 Adam Barth 2011-09-28 13:04:16 PDT
I enjoy that Eric said the same things I did, plus he caught a bunch more.  :)
Comment 9 David Levin 2011-09-28 13:08:55 PDT
(In reply to comment #6)
> (From update of attachment 109051 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=109051&action=review
> > Tools/Scripts/webkitpy/common/watchlist/watchlistloader_unittest.py:45
> > +        WatchListLoader(filesystem.FileSystem()).load()
> 
> It's rare that you want to use a real filesystem in a unittest.

I wanted to load the actual checked in watchlist to verify that there are no mistakes in it.

Because it is bad news, if there are. The watchlist bot will completely break.
Comment 10 David Levin 2011-09-28 13:46:09 PDT
Created attachment 109067 [details]
Patch
Comment 11 David Levin 2011-09-28 13:47:39 PDT
I fixed everything except I still access the real filesystem to load the checked in watchlist as a test.

I not only want to verify that I can actually load it but I want the integrity checks that will happen as a part of that load, so that any mistakes made in that file are caught quickly (by the bots running python tests if nothing else).
Comment 12 Eric Seidel (no email) 2011-09-28 14:38:14 PDT
Comment on attachment 109067 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=109067&action=review

Seems OK.  Please look at the nits I posted.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:36
> +    def _get_watch_list_contents(self):

We don't normally use _get_ in WebKit method names.  You could use _read_watch_list_contents.  Except I still don't think you want this method.  You don't need it for unittesting anymore, now that you're using Filesystem.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:42
> +        except:
> +            raise Exception('Watch list file (%s) not found.' % watch_list_full_path)

This isn't true.  You're converting any exception into a "not found" custom exception.  I think you should instead remove the exception handling and guard your read in self._filesystem.exists() instead, returning None if it doesn't exist.  Then if there si some real read problem you'll see that as a real exception, instead of mutated to your custom one.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader_unittest.py:41
> +        self.assertRaisesRegexp(r'Watch list file \(.*/watchlist\) not found\.',
> +                                loader.load)

We don't match PEP8 wrapping.  You're welcome to wrap wherever you feel is most readable.

> Tools/Scripts/webkitpy/common/watchlist/watchlistloader_unittest.py:45
> +    def test_watch_list_load(self):
> +        # Just verifying that loading the checked in watch list works.
> +        WatchListLoader(filesystem.FileSystem()).load()

Ok, so it wasn't immediately clear to me.  This is a parsing test for the checked-in watch list.

> Tools/Scripts/webkitpy/common/webkitunittest.py:41
> +    def _verifyException(self, regex_message, callable, *args):

I might name this _assertRaisesRegexp. :)  I guess one might worry that could conflict with some other TestCase method...
Comment 13 David Levin 2011-09-28 14:41:25 PDT
(In reply to comment #12)
> (From update of attachment 109067 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=109067&action=review
> 
> Seems OK.  Please look at the nits I posted.
> 
> > Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:36
> > +    def _get_watch_list_contents(self):
> 
> We don't normally use _get_ in WebKit method names.  You could use _read_watch_list_contents.  Except I still don't think you want this method.  You don't need it for unittesting anymore, now that you're using Filesystem.

I'll get rid of it :)

> 
> > Tools/Scripts/webkitpy/common/watchlist/watchlistloader.py:42
> > +        except:
> > +            raise Exception('Watch list file (%s) not found.' % watch_list_full_path)
> 
> This isn't true.  You're converting any exception into a "not found" custom exception.  I think you should instead remove the exception handling and guard your read in self._filesystem.exists() instead, returning None if it doesn't exist.  Then if there si some real read problem you'll see that as a real exception, instead of mutated to your custom one.

You said this before and I messed up on the follow through. Thanks for pointing it out again.


I'll address everything you said and check in.

Thanks again!
Comment 14 David Levin 2011-09-28 15:00:45 PDT
Committed as http://trac.webkit.org/changeset/96263