Merge lp:~mvo/launchpad/support-timeframe-fix-660433 into lp:launchpad/db-devel

Proposed by Michael Vogt
Status: Merged
Merge reported by: Gavin Panella
Merged at revision: not available
Proposed branch: lp:~mvo/launchpad/support-timeframe-fix-660433
Merge into: lp:launchpad/db-devel
Diff against target: 767 lines (+399/-67)
6 files modified
cronscripts/publishing/cron.germinate (+25/-9)
cronscripts/publishing/maintenance-check.py (+104/-58)
lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/germinate (+5/-0)
lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile (+8/-0)
lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py (+27/-0)
lib/lp/soyuz/scripts/tests/test_cron_germinate.py (+230/-0)
To merge this branch: bzr merge lp:~mvo/launchpad/support-timeframe-fix-660433
Reviewer Review Type Date Requested Status
Michael Vogt (community) Needs Resubmitting
Jeroen T. Vermeulen (community) code Approve
Colin Watson Pending
Review via email: mp+38503@code.launchpad.net

Commit message

Update support-timeframe info for NEW packages.

Description of the change

Hello,

this branch fixes the soyuz bug #660433. It will re-generate the support-timeframe information (Supported tag in more-extras.overrides) for all supported distros to update it for packages like new kernels that get added as NEW packages after the final release.

I added a simple test for the functionality. I'm not sure it follows the guidelines, there was no tests/ directory under cronscripts/publishing (and the test is done with sh).

Its also prepares mock-data (./mock-data/ubuntu-archive/ubuntu) for testing germinate integration. This is not used (yet?), so that part of the tree could be removed (this would make the diff less cluttered).

Someone with soyuz experience (and knowledge about e.g. the content of "crontab -l") needs to review this carefully as it will affect the extra-overrides file from stable distros and therefore modify stuff in $distro-updates.

Cheers,
 Michael

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) wrote :

It also modifies maintenance-check.py to put information only for lucid and later. While the script will work for hardy as well it does not make sense to generate "Supported" info in hardy-updates for it when there is none for the main archive.

Revision history for this message
Robert Collins (lifeless) wrote :

That sample data will add to the tree size and isn't necessary or
desirable - could you please uncommit back to before you added it and
resubmit? Thanks.

Binary files in bzr is a bad idea, and anytime it seems like a good
one... its not :)

-Rob

Revision history for this message
Michael Vogt (mvo) wrote :

Hey Robert, thanks for your review. I'm happy to remove the data. Please note that its empty gz files currently, so the data added to bzr should be small. But I'm fine with removing it as its currently not required (something small binray (one or two stanzas will be required when we test the germinate output though, so advise is welcome how to handle this).

Revision history for this message
Robert Collins (lifeless) wrote :

On Fri, Oct 15, 2010 at 8:57 PM, Michael Vogt <email address hidden> wrote:
> Hey Robert, thanks for your review. I'm happy to remove the data. Please note that its empty gz files currently, so the data added to bzr should be small. But I'm fine with removing it as its currently not required (something small binray (one or two stanzas will be required when we test the germinate output though, so advise is welcome how to handle this).

We already have such data elsewhere in the tree, or we can generate it
on demand.

We're currently working on parallel testing too, which means that
tests *cannot* depend on mutating data in the tree.

(and yes, you'll need to have it be a python unittest).

-Rob

9888. By Michael Vogt

remove all binary data from the tree and generate it on the fly

9889. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py: convert test to python

9890. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate: remove shell script test

Revision history for this message
Michael Vogt (mvo) wrote :

I generate the data on the fly now and converted the shell to proper unittest. Please have another look.

9891. By Michael Vogt

clear mock ubuntu/dists data too

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :
Download full text (14.5 KiB)

Hi Michael,

Thanks for the branch. I'm ecstatic to see someone work on these scripts, especially with tests attached; but a bit uncomfortable reviewing the changes. Most of the existing code seems absolutely ancient and ill-matched to today's source tree. I'll resist the temptation to say "while you're here, could you also clean up this bit of other code" a lot. :-)

Julian is still looking at the testing and design sides, but I'll review the code on the assumption that that will come out okay. Lots of notes though. I hope you won't be put off by them!

=== modified file 'cronscripts/publishing/cron.germinate'
--- cronscripts/publishing/cron.germinate 2010-09-06 09:46:01 +0000
+++ cronscripts/publishing/cron.germinate 2010-10-15 12:12:43 +0000

@@ -126,10 +125,19 @@
 done
 echo " done."

-# now generate the Supported extra overrides
-$MAINTAINCE_CHECK $suite > "$MISCROOT/more-extra.override.$suite.main.supported" 2> _maintenance-check.stderr
-if [ $? -eq 0 ]; then
- cat "$MISCROOT/more-extra.override.$suite.main.supported" >> "$MISCROOT/more-extra.override.$suite.main.new"
-fi
-
 mv -f "$MISCROOT/more-extra.override.$suite.main.new" "$MISCROOT/more-extra.override.$suite.main"
+
+# now generate the Supported extra overrides for all supported distros
+for supported_suite in `$LAUNCHPADROOT/scripts/ftpmaster-tools/lp-query-distro.py supported`; do

The lines in this script get pretty long. Could you place the "do" on a separate line?

for supported_suite in `$LAUNCHPADROOT/scripts/ftpmaster-tools/lp-query-distro.py supported`
do
    # ...
done

+ echo -n "Running maintenance-check for $supported_suite... "
+ if $MAINTAINCE_CHECK $supported_suite > "$MISCROOT/more-extra.override.$supported_suite.main.supported" 2> _maintenance-check.$supported_suite.stderr; then

And this one is now definitely too long! It'd help if these enormous filenames were in sensibly-named variables. Makes it easier to get an overview of what's happening.

+ # make sure the more-extra.override file exists
+ touch "$MISCROOT/more-extra.override.$supported_suite.main"

This comment just re-words the code. Instead, could you make it say very briefly _why_ it does this?

(Also, contrary to what you see in these scripts, please start your sentences with capital letters and punctuate them!).

+ # remove old "Supporte" info from extra overrides

Typo: missing "d." Also, please capitalize & punctuate.

+ sed /"^.* Supported"/d "$MISCROOT/more-extra.override.$supported_suite.main" > "$MISCROOT/more-extra.override.$supported_suite.main.new"
+ cat "$MISCROOT/more-extra.override.$supported_suite.main.supported" >> "$MISCROOT/more-extra.override.$supported_suite.main.new"
+ mv "$MISCROOT/more-extra.override.$supported_suite.main.new" "$MISCROOT/more-extra.override.$supported_suite.main"
+ fi
+ echo " done"
+done

Does this piece of the script want to live in its own function?

=== modified file 'cronscripts/publishing/maintenance-check.py'
--- cronscripts/publishing/maintenance-check.py 2010-05-28 16:17:51 +0000
+++ cronscripts/publishing/maintenance-check.py 2010-10-15 12:12:43 +0000

@@ -297,7 +297,11 @@
    ...

review: Needs Fixing
9892. By Michael Vogt

cronscripts/publishing/cron.germinate: address merge review issues raised by jtv

9893. By Michael Vogt

cronscripts/publishing/maintenance-check.py: fix missing capitalization and punctation and kill off whitespace

9894. By Michael Vogt

cronscripts/publishing/tests/mock-data/mock-bin/germinate: add comment in the script header

9895. By Michael Vogt

cronscripts/publishing/tests/mock-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py: update to include comment and error checking and a else claue

9896. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py: address a lot of the review points, punctation, test template, variable naming, comments and docstrings (more to come)

Revision history for this message
Martin Pool (mbp) wrote :

Thanks for reviewing it, Jeroen. I want to contribute a meta-review.

First off, thanks for reviewing this quickly and expressing enthusiasm for what mvo did. Those two things make a big difference to the speed at which anyone can contribute and they're especially important for new contributors.

> + gz = gzip.GzipFile(os.path.join(d, "Sources.gz"), "w")
> + gz.close()
>
> Here too it would be nice to have a helper: "create gzip file."
>
>
> + # binaries
>
> Cap & Punct.
>
>
> + for arch in self.ARCHES:
> + for p in ["", "debian-installer"]:
>
> Please replace "p" with a full variable name.
>
>
> + d = os.path.join(
>
> Same for "d."

This kind of review comment I think is not so good, for a couple of reasons.

It's bad scaling behaviour to manually comment on all N instances of a problem, when a single comment would cover all of them. It seems to me that, like in my recent contribution, the problem is not that mvo made some particular mistakes, but that he just didn't know of some Launchpad conventions. I think it would be better to have a shorter review with the coding standard URL and pointing out the particular bits that are relevant. It will be quicker for you too.

I don't know how much mvo has participated in lp development before but I'm guessing not that much. So he probably won't know he ought to run 'make lint', or the quirk that it only covers currently uncommitted code.
However when somebody is putting up an early patch that violates these pretty minor rules, I wonder how much it is worth getting them to go back and eg remove whitespace. istm it is better to build up more knowledge of conventions in their head, and more enthusiasm for the project. Again, probably better scaling behaviour.

Saying "I don't understand this, please add a comment" or "you don't need this" is of course fine.

my 2c.

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Martin, you make a good point. I was actually just trying to be helpful: since I'm "proof-reading" the entire diff anyway, there's no need for Michael to go over the whole thing to find each individual instance that needs changing. I just noted them consistently, as is common practice in Launchpad reviews.

I'm used to this practice and don't feel in any way accused when a reviewer does it for me (or accusatory when I do it for someone else). But now that you mention it, I suppose it does need an explanation for new contributors.

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

The starting point for the ins and outs of writing Launchpad branches, by the way, is here: https://dev.launchpad.net/LaunchpadHackingFAQ

Unfortunately there's rather a lot of it. The actual coding rules is in pages linked from there, notably the Python style guide.

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks for the review Jeroen and thanks for the meta-review from Martin as well!

I update the code to adress a lot of the points, but there is more to be done. I'm happy
about the detailed review as it means I can just go over it point by point. The result
is that the code is now better and more readable. Martin is right, I don't usually do LP
development and I'm not familiar with the processes. I just want to fix this bug as it
affects the distro (badly) :)

I do not nessecarily agree with all of the points in the review (e.g. I think short variable
like "d" are fine if they are just used in a two lines or a short function). But that is fine, its more important that its consistent with the rest of the codebase.

The only "grief" I have is the testing template. To test a small part of LP like this
that does not need the database or other fancy part using the template drags in a huge
set of python dependencies, including psycopg2, storm, transactions, windmill
(that appears to be not packaged in ubuntu maverick) and more. It would be great to be
able to use the test template without all this if its not actually needed for the test
at hand.

Revision history for this message
Martin Pool (mbp) wrote :

On 21 October 2010 15:28, Jeroen T. Vermeulen <email address hidden> wrote:
> Martin, you make a good point.  I was actually just trying to be helpful: since I'm "proof-reading" the entire diff anyway, there's no need for Michael to go over the whole thing to find each individual instance that needs changing.  I just noted them consistently, as is common practice in Launchpad reviews.
>
> I'm used to this practice and don't feel in any way accused when a reviewer does it for me (or accusatory when I do it for someone else).  But now that you mention it, I suppose it does need an explanation for new contributors.

I don't take it as accusatory at all. There are probably some things
we could do in lp reviews to help with this - it would be neat if your
editor could jump through a list of review comments with the lines
they correspond to, or perhaps if a reviewer could more easily get in
and edit the branch...

--
Martin

9897. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py: refactor to create fake ubuntu archive root as a tempdir and add new helper create_directory_if_missing

9898. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py: move creating the germinate process environment into its own function, add gzip helper, add directory lists helper

9899. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py: add helper create_file()

Revision history for this message
Michael Vogt (mvo) wrote :

Beside the following two open issues I think I fixed all of the things mentioned.
Open is:

I don't use from lp.testing import TestCase because I could not make it work on my machine.
Adding the launchpad PPA and installing the launchpad-dependencies did not help.

I either get:
 ImportError: No module named windmill.bin.admin_lib (when importing canonical.testing.layers)
or
 ImportError: No module named fixtures (when importing from lp.testing import TestCase only)
I guess I do something wrong but I don't know what.

The other one is that I did not change the directory layout yet (where the tests lives).

Revision history for this message
Colin Watson (cjwatson) wrote :

I don't expect problems here from a deployment point of view; obviously (say) dists/lucid/ won't be changed, as opposed to dists/lucid-updates/, but that's OK. I trust you're aware that this means that it's only possible to generate updated Supported fields for packages that have been changed or added in lucid-updates.

One thing that jumped out at me, although I realise it was in the pre-existing code too:

- if distro[0] < 'h':
- print "ERROR: only hardy or later is supported"
+ if distro[0] < 'l':
+ logging.error("only lucid or later is supported")

We're only six years or so away from wrapping around the end of the alphabet. Perhaps this needs to be more explicit somehow? Of course, having to list all historical release names here isn't particularly great either ...

Revision history for this message
Michael Vogt (mvo) wrote :

Hello Colin, thanks for this feedback. The generated Suported fields will indeed be only be updated for changed or added Packages. But that is ok, before lucid-final we reviewed the data to made sure that it is sane. The open issue is that newly published kernels to not get the right Supported field currently and that makes ubuntu-support-status print out wrong data for those.

The wrapping is a good point, I just added the relevant historic names to make it explicit.

9900. By Michael Vogt

cronscripts/publishing/tests/mock-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py: return more supported distros to test filter in maintenance-check.py

9901. By Michael Vogt

cronscripts/publishing/maintenance-check.py: make unsupported release names explicit to avoid future problems when the codenames wrap around (thanks to Colin!)

Revision history for this message
Julian Edwards (julian-edwards) wrote :

167 +# mvo: I would love to use this, but it appears doing this import
168 +# requires python-psycopg2, python-storm, python-transaction,
169 +# python-lazr.restful and now "windmill" that is not packaged
170 +# at this point I give up and let someone else with a proper
171 +# LP environment fix this
172 +#from canonical.testing.layers import DatabaseFunctionalLayer

In an ideal world every test would not use any layers because it's massively quicker to run the tests. However, I can't see any reason that your tests need layers so I think it's fine to remove this commented block entirely.

9902. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py: remove (commented out) import for canonical.testing.layers, use abspath() for BASEPATH to ensure it works correctly when run from different dirs

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks Julian, I removed that part of the diff now. I still can not use from lp.testing import TestCase for some reason.

Revision history for this message
Julian Edwards (julian-edwards) wrote :

I'd personally be happy with you using the unittest one if it means you can run your own tests.

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

With apologies for the delays—holiday and crisis, yin and yang—I'm just coming back to this branch. I hope I can help with this problem:

> Beside the following two open issues I think I fixed all of the things
> mentioned.
> Open is:
>
> I don't use from lp.testing import TestCase because I could not make it work
> on my machine.
> Adding the launchpad PPA and installing the launchpad-dependencies did not
> help.
>
> I either get:
> ImportError: No module named windmill.bin.admin_lib (when importing
> canonical.testing.layers)
> or
> ImportError: No module named fixtures (when importing from lp.testing import
> TestCase only)
> I guess I do something wrong but I don't know what.

These are external modules that have recently been updated. Try running rocketfuel-get (or if that doesn't do the trick, rocketfuel-setup). Then, in your branch, run
{{{
. ~/.rocketfuel-env.sh
utilities/link-external-sourcecode "$LP_TRUNK_NAME"
make
}}}

That should update your branch to use the latest external modules. You need to re-run rocketfuel-get from time to time to keep them updated. Sometimes you also need to merge in newer versions of your parent branch.

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :
Download full text (13.6 KiB)

Thanks for all the work you did on this! Is it just me or does the diff look a lot shorter now, despite having the new bits code? It certainly seems easier to read.

=== modified file 'cronscripts/publishing/cron.germinate'
--- cronscripts/publishing/cron.germinate 2010-09-06 09:46:01 +0000
+++ cronscripts/publishing/cron.germinate 2010-10-21 19:06:53 +0000

+# Now generate the Supported extra overrides for all supported distros.
+SUITES=`$LAUNCHPADROOT/scripts/ftpmaster-tools/lp-query-distro.py supported`
+for supported_suite in $SUITES; do
+ echo -n "Running maintenance-check for $supported_suite... "
+ # The support timeframe information is stored here
+ SUPPORTED="$MISCROOT/more-extra.override.$supported_suite.main.supported"
+ # This is the target override file that contains germinate plus support info
+ TARGET="$MISCROOT/more-extra.override.$supported_suite.main"
+ # Debug/Log information
+ LOG="_maintenance-check.$supported_suite.stderr"
+ if $MAINTAINCE_CHECK $supported_suite > $SUPPORTED 2> $LOG; then
+ # The target file may be missing on the server and the script should
+ # not fail if that is the case.
+ touch $TARGET
+ # Remove old "Supported" info from extra-overrides as it may be
+ # stale now and we replace it with fresh content below.
+ sed /"^.* Supported"/d $TARGET > ${TARGET}.new
+ cat $SUPPORTED >> ${TARGET}.new
+ mv ${TARGET}.new $TARGET
+ fi
+ echo " done"
+done

This looks nice and clear.

=== modified file 'cronscripts/publishing/maintenance-check.py'
--- cronscripts/publishing/maintenance-check.py 2010-05-28 16:17:51 +0000
+++ cronscripts/publishing/maintenance-check.py 2010-10-21 19:06:53 +0000

+# Names of the distribution releases that are not supported by this
+# tool. All later versions are supported.
+UNSUPPORTED_DISTRO_RELEASED = ["dapper", "edgy", "feisty", "gutsy", "hardy",
+ "intrepid", "jaunty", "karmic"]

A small thing: our coding standards say this should be formatted as

UNSUPPORTED_DISTRO_RELEASED = [
    "dapper",
    "edgy",
    "feisty",
    "gutsy",
    "hardy",
    "intrepid",
    "jaunty",
    "karmic",
    ]

(Notice the trailing comma even on the last line.)

@@ -275,8 +282,8 @@

- if distro[0] < 'h':
- print "ERROR: only hardy or later is supported"
+ if distro in UNSUPPORTED_DISTRO_RELEASED:
+ logging.error("only lucid or later is supported")

Much nicer, yes!

=== added directory 'cronscripts/publishing/tests'
=== added directory 'cronscripts/publishing/tests/mock-data'
=== added directory 'cronscripts/publishing/tests/mock-data/mock-bin'
=== added file 'cronscripts/publishing/tests/mock-data/mock-bin/germinate'
--- cronscripts/publishing/tests/mock-data/mock-bin/germinate 1970-01-01 00:00:00 +0000
+++ cronscripts/publishing/tests/mock-data/mock-bin/germinate 2010-10-21 19:06:53 +0000
@@ -0,0 +1,5 @@
+#!/bin/sh
+#
+# This is a mock germinate script that just produces enough (empty)
+# files so that the cron.germinate shell script can run.
+touch structure all all.sources minimal standard

Perfect. This tells me exactly what I'm looki...

review: Approve
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

(Setting review type to "code," because the ec2 landing script requires an Approved vote of that type.)

review: Approve (code)
9903. By Michael Vogt

cronscripts/publishing/tests/mock-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py: fix pocketlint errors (indent, spacing)

9904. By Michael Vogt

cronscripts/publishing/maintenance-check.py: fix pocketlint errors (spacing, indent, linewrap)

9905. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py: fix pocketlint errors (spacing, indent, linewrap)

9906. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py: updated to follow LP coding standards

9907. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py, cronscripts/publishing/maintenance-check.py: add SPACE around "=" to follow LP coding standard

9908. By Michael Vogt

cronscripts/publishing/tests/test_cron.germinate.py: adress formating issues and assert messages

Revision history for this message
Michael Vogt (mvo) wrote :
Download full text (8.9 KiB)

On Wed, Oct 27, 2010 at 10:46:02AM -0000, Jeroen T. Vermeulen wrote:

> Thanks for all the work you did on this! Is it just me or does the
> diff look a lot shorter now, despite having the new bits code? It
> certainly seems easier to read.

Thanks for the detailed review and sorry for the slow reply, the UDS
was taking all my attention. Its indeed much nicer now.

[..]
> === modified file 'cronscripts/publishing/maintenance-check.py'
> --- cronscripts/publishing/maintenance-check.py 2010-05-28 16:17:51 +0000
> +++ cronscripts/publishing/maintenance-check.py 2010-10-21 19:06:53 +0000
>
> +# Names of the distribution releases that are not supported by this
> +# tool. All later versions are supported.
> +UNSUPPORTED_DISTRO_RELEASED = ["dapper", "edgy", "feisty", "gutsy", "hardy",
> + "intrepid", "jaunty", "karmic"]
>
> A small thing: our coding standards say this should be formatted as
>
> UNSUPPORTED_DISTRO_RELEASED = [
> "dapper",
> "edgy",
> "feisty",
> "gutsy",
> "hardy",
> "intrepid",
> "jaunty",
> "karmic",
> ]

> (Notice the trailing comma even on the last line.)

Thanks, updated in my branch.

[..]
> --- cronscripts/publishing/tests/mock-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py 1970-01-01 00:00:00 +0000
> +++ cronscripts/publishing/tests/mock-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py 2010-10-21 19:06:53 +0000
> @@ -0,0 +1,24 @@
> +#!/usr/bin/python
> +#
> +# This is a mock version of the lp-query-distro.py script that
> +# returns static data so that the cron.germinate shell script
> +# can be tested.
> +
> +import sys
> +
> +def error_and_exit():
>
> Another small thing from our coding standards: each top-level (i.e. unindented) class or function definition in a file should have two blank lines above it.
>
> Running "make lint" should tell you about these things. With such old code though, it's possible that your changes drown among warnings for code you didn't even touch.
[..]

Thanks, I fixed that in my branch now as well. I can not run make lint
apparently without setting up a proper LP dev environment. It
complains about missing external dependencies, if I run the suggested
script it will fails with a non-obvious error. But checking lint.sh.in
shows that pocketlint is used and that makes it trivial to run it.

I went over the pocketlint errors and fixed all of them (except for
one in line 88 that I'm not sure what the correct style to use is).

[..]
> +# mvo: I would love to use this, but it complains about a missing
> +# import for "fixtures" and I can not find a package that
> +# provides this module
> +#from lp.testing import TestCase # or TestCaseWithFactory
>
> The disadvantage of having a very active hands-on architect is that things change so fast. :-) When in doubt, I generally go through these steps:
[..]

Thanks for these tips. For this particular piece of code I do not need
a full launchpad environment so I haven't setup one. But I will keep
this in my tomboy notes for when I need it :)

> + self.ubuntu_misc_dir = os.path.join(self.archive_dir, "ubuntu-misc")
> + self.ubuntu_ger...

Read more...

Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Hi Michael,

This sure isn't an easy review. My compliments on your tenacity—it'll be really good to have this landed. The code as such is good as far as I'm concerned.

To be honest, developing a branch without a full LP environment set up is probably not a good idea. It messes with your system setup and drops any postgres clusters you may have, but on the bright side, it is fully automated (including easy updates and faster bzr interaction with future branches) and gives you access to "make lint" and the test runner. It may be worth setting up a virtual machine for.

I set up a copy of your branch locally. It turns out that on the one hand, the test suite does run your script test. On the other, it's not run in the right way somehow and it breaks. As it turns out, moving the test and the mock-data directory into lib/lp/soyuz/scripts/tests/ fixes that. You can see my changes at lp:~jtv/launchpad/mvo

Unfortunately it's still not quite working. The cron.germinate script seems to run a command "lockfile" that it can't find. If this is from a package that needs to be installed on the system, it should be included in either the dependencies for Launchpad or the zc.buildout packages. Otherwise the test suite will not pass on the EC2 and buildbot machines, which start out with clean base systems.

Jeroen

9909. By Michael Vogt

merged with db-devel

9910. By Michael Vogt

merged from jtv (many thanks)

9911. By Michael Vogt

lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile: add mock lockfile command to ensure cron.germinate finds this command when it needs it

9912. By Michael Vogt

lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile: return 1 instead of 0 (this is what cron.germinate expects)

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks for your branch. I merged it into my branch and I have a LP setup now (that took a while to setup). I created a mock lockfile command, however the test is still failing in my lucid VM. Probably some problem with the path shuffling. I look into this tomorrow.

9913. By Michael Vogt

lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/publishing/maintenance-check.py: fix symlink target now that the tests moved to a different directory

Revision history for this message
Michael Vogt (mvo) wrote :

The branch should be ready now, the tests pass in a LP dev environment for me now.

review: Needs Resubmitting
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Argh! The test gets stuck when I run it:

Running germinate... ........................ done.
Running maintenance-check for hardy... done
Running maintenance-check for jaunty... done
Running maintenance-check for karmic... done
Running maintenance-check for lucid...

At that point maintenance-check.py sits effectively idle forever.

What I suspect happens is that the script tries to access the URLs that it has hard-coded into it:

{{{
# germinate output base directory
BASE_URL = "http://people.canonical.com/~ubuntu-archive/germinate-output/"

# hints dir url, hints file is "$distro.hints" by default
# (e.g. lucid.hints)
HINTS_DIR_URL = "http://people.canonical.com/~ubuntu-archive/seeds/platform.%s/SUPPORTED_HINTS"

# we need the archive root to parse the Sources file to support
# by-source hints
ARCHIVE_ROOT = "http://archive.ubuntu.com/ubuntu"
}}}

The test suite should not make any network connections outside of the test system. I'm afraid that to get this working, we may have to inject test doubles for these URLs as well.

(Also, on a very minor note, the current branch still adds cronscripts/publishing/tests although of course it's now empty.)

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks Jeroen for running this inside the test evnironment. I look into adding test doubles next, that is going to be a bit of work. And I removed the empty dir now :)

9914. By Michael Vogt

cronscripts/publishing/tests: removed, empty now

9915. By Michael Vogt

cronscripts/publishing/maintenance-check.py: support url overrides in the environment for {MAINTENANCE_CHECK_BASE_URL, MAINTENANCE_CHECK_HINTS_DIR_URL, MAINTENANCE_CHECK_ARCHIVE_ROOT}

Revision history for this message
Gavin Panella (allenap) wrote :

Michael, this is a long-lived branch into which you and the reviewers have put a lot of work. Is there something I can do to help you get this landed?

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks Gavin! I did look into this one again yesterday. I need to create the test dummies, that is tedious work. But the bugfix is important, so I will give it another go.

9916. By Michael Vogt

lib/lp/soyuz/scripts/tests/test_cron_germinate.py: create mock environment for get-maintenance-check.py because it can not use the network to fetch the real data when the testsuite runs

Revision history for this message
Michael Vogt (mvo) wrote :

This update should create all the needed files locally now without the need to touch the network. Please note that I added a "class PoorMvosTestCase(unittest.TestCase)" that is used as a fallback if the full lp.testing import TestCase can not be imported. Feel free to remove it in the final merge (or I can remove it too once the rest looks ok). I added it because I only have a full LP environment in a VM and that is a bit of a hassle to work with. But this script really only needs the makeTemporaryFile feature. The test passes now for me without network and the data looks sane too.

Revision history for this message
Gavin Panella (allenap) wrote :

Michael, I've merged devel into your branch, cleaned up your last revision and put it in lp:~allenap/launchpad/support-timeframe-fix-660433. Please can you merge my branch into yours and push back to Launchpad?

Revision history for this message
Gavin Panella (allenap) wrote :

Don't worry, I'll land this directly from my branch.

Revision history for this message
Gavin Panella (allenap) wrote :

I've merged this into *devel* via lp:~allenap/launchpad/support-timeframe-fix-660433.

Revision history for this message
Michael Vogt (mvo) wrote :

On Thu, Jan 20, 2011 at 07:01:55PM -0000, Gavin Panella wrote:
> Michael, I've merged devel into your branch, cleaned up your last revision and put it in lp:~allenap/launchpad/support-timeframe-fix-660433. Please can you merge my branch into yours and push back to Launchpad?

Thanks a lot for this! And sorry for my late reply, I was away for a
cross distro meeting a couple of days and just returned. Merged and
pushed.

I just read that you will land it from your branch, thats great. I
hope you did not had too much trouble with merge conflicts and all?

Cheers,
 Michael

Revision history for this message
Gavin Panella (allenap) wrote :

Michael, it landed without a hitch, perfect. Thank you for all the work you've done on this :)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cronscripts/publishing/cron.germinate'
2--- cronscripts/publishing/cron.germinate 2010-11-02 15:54:52 +0000
3+++ cronscripts/publishing/cron.germinate 2011-01-07 13:50:46 +0000
4@@ -6,12 +6,12 @@
5 set -e
6 set -u
7
8-ARCHIVEROOT=/srv/launchpad.net/ubuntu-archive/ubuntu
9+ARCHIVEROOT=${TEST_ARCHIVEROOT:-/srv/launchpad.net/ubuntu-archive/ubuntu}
10 MISCROOT=$ARCHIVEROOT/../ubuntu-misc
11 LOCKROOT=$ARCHIVEROOT/..
12 GERMINATEROOT=$ARCHIVEROOT/../ubuntu-germinate
13
14-LAUNCHPADROOT=/srv/launchpad.net/codelines/current
15+LAUNCHPADROOT=${TEST_LAUNCHPADROOT:-/srv/launchpad.net/codelines/current}
16 MAINTAINCE_CHECK=$LAUNCHPADROOT/cronscripts/publishing/maintenance-check.py
17
18 ## Check to see if another germinate run is in progress
19@@ -28,7 +28,6 @@
20
21 trap cleanup EXIT
22
23-LAUNCHPADROOT=/srv/launchpad.net/codelines/current
24 suite=`$LAUNCHPADROOT/scripts/ftpmaster-tools/lp-query-distro.py development`
25
26 echo -n "Running germinate... "
27@@ -131,10 +130,27 @@
28 done
29 echo " done."
30
31-# now generate the Supported extra overrides
32-$MAINTAINCE_CHECK $suite > "$MISCROOT/more-extra.override.$suite.main.supported" 2> _maintenance-check.stderr
33-if [ $? -eq 0 ]; then
34- cat "$MISCROOT/more-extra.override.$suite.main.supported" >> "$MISCROOT/more-extra.override.$suite.main.new"
35-fi
36-
37 mv -f "$MISCROOT/more-extra.override.$suite.main.new" "$MISCROOT/more-extra.override.$suite.main"
38+
39+# Now generate the Supported extra overrides for all supported distros.
40+SUITES=`$LAUNCHPADROOT/scripts/ftpmaster-tools/lp-query-distro.py supported`
41+for supported_suite in $SUITES; do
42+ echo -n "Running maintenance-check for $supported_suite... "
43+ # The support timeframe information is stored here
44+ SUPPORTED="$MISCROOT/more-extra.override.$supported_suite.main.supported"
45+ # This is the target override file that contains germinate plus support info
46+ TARGET="$MISCROOT/more-extra.override.$supported_suite.main"
47+ # Debug/Log information
48+ LOG="_maintenance-check.$supported_suite.stderr"
49+ if $MAINTAINCE_CHECK $supported_suite > $SUPPORTED 2> $LOG; then
50+ # The target file may be missing on the server and the script should
51+ # not fail if that is the case.
52+ touch $TARGET
53+ # Remove old "Supported" info from extra-overrides as it may be
54+ # stale now and we replace it with fresh content below.
55+ sed /"^.* Supported"/d $TARGET > ${TARGET}.new
56+ cat $SUPPORTED >> ${TARGET}.new
57+ mv ${TARGET}.new $TARGET
58+ fi
59+ echo " done"
60+done
61
62=== modified file 'cronscripts/publishing/maintenance-check.py'
63--- cronscripts/publishing/maintenance-check.py 2010-05-28 16:17:51 +0000
64+++ cronscripts/publishing/maintenance-check.py 2011-01-07 13:50:46 +0000
65@@ -1,7 +1,7 @@
66 #!/usr/bin/python
67 #
68 # python port of the nice maintainace-check script by Nick Barcet
69-#
70+#
71 # taken from:
72 # https://code.edge.launchpad.net/~mvo/ubuntu-maintenance-check/python-port
73 # (where it will vanish once taken here)
74@@ -9,7 +9,7 @@
75 # this warning filter is only needed on older versions of python-apt,
76 # once the machine runs lucid it can be removed
77 import warnings
78-warnings.filterwarnings("ignore","apt API not stable yet")
79+warnings.filterwarnings("ignore", "apt API not stable yet")
80 import apt
81 warnings.resetwarnings()
82
83@@ -29,21 +29,21 @@
84 # - distros "kubuntu", "edubuntu" and "netbook" need to be
85 # considered *but* only follow SUPPORT_TIMEFRAME
86 # - anything that is in armel follows SUPPORT_TIMEFRAME
87-#
88+#
89
90 # codename of the lts releases
91-LTS_RELEASES = [ "dapper", "hardy", "lucid" ]
92+LTS_RELEASES = ["dapper", "hardy", "lucid"]
93
94 # architectures that are full supported (including LTS time)
95-PRIMARY_ARCHES = ["i386", "amd64"]
96+PRIMARY_ARCHES = ["i386", "amd64"]
97
98 # architectures we support (but not for LTS time)
99 SUPPORTED_ARCHES = PRIMARY_ARCHES + ["armel"]
100
101 # what defines the seeds is documented in wiki.ubuntu.com/SeedManagement
102-SERVER_SEEDS = [ "supported-server", "server-ship"]
103+SERVER_SEEDS = ["supported-server", "server-ship"]
104 DESKTOP_SEEDS = ["ship", "supported-desktop", "supported-desktop-extra"]
105-SUPPORTED_SEEDS = [ "all" ]
106+SUPPORTED_SEEDS = ["all"]
107
108 # normal support timeframe
109 # time, seeds, arches
110@@ -60,25 +60,46 @@
111 ]
112
113 # distro names and if they get LTS support (order is important)
114-DISTRO_NAMES_AND_LTS_SUPPORT = [ ("ubuntu", True),
115- ("kubuntu", True),
116- ("netbook", False),
117- ]
118+DISTRO_NAMES_AND_LTS_SUPPORT = [
119+ ("ubuntu", True),
120+ ("kubuntu", True),
121+ ("netbook", False),
122+ ]
123+
124+# Names of the distribution releases that are not supported by this
125+# tool. All later versions are supported.
126+UNSUPPORTED_DISTRO_RELEASED = [
127+ "dapper",
128+ "edgy",
129+ "feisty",
130+ "gutsy",
131+ "hardy",
132+ "intrepid",
133+ "jaunty",
134+ "karmic",
135+ ]
136+
137
138 # germinate output base directory
139-BASE_URL = "http://people.canonical.com/~ubuntu-archive/germinate-output/"
140+BASE_URL = os.environ.get(
141+ "MAINTENANCE_CHECK_BASE_URL",
142+ "http://people.canonical.com/~ubuntu-archive/germinate-output/")
143
144 # hints dir url, hints file is "$distro.hints" by default
145 # (e.g. lucid.hints)
146-HINTS_DIR_URL = "http://people.canonical.com/~ubuntu-archive/seeds/platform.%s/SUPPORTED_HINTS"
147+HINTS_DIR_URL = os.environ.get(
148+ "MAINTENANCE_CHECK_HINTS_DIR_URL",
149+ "http://people.canonical.com/~ubuntu-archive/seeds/platform.%s/SUPPORTED_HINTS")
150
151 # we need the archive root to parse the Sources file to support
152 # by-source hints
153-ARCHIVE_ROOT = "http://archive.ubuntu.com/ubuntu"
154+ARCHIVE_ROOT = os.environ.get(
155+ "MAINTENANCE_CHECK_ARCHIVE_ROOT", "http://archive.ubuntu.com/ubuntu")
156
157 # support timeframe tag used in the Packages file
158 SUPPORT_TAG = "Supported"
159
160+
161 def get_binaries_for_source_pkg(srcname):
162 """ Return all binary package names for the given source package name.
163
164@@ -92,38 +113,41 @@
165 pkgnames.add(binary)
166 return pkgnames
167
168+
169 def expand_src_pkgname(pkgname):
170 """ Expand a package name if it is prefixed with src.
171
172 If the package name is prefixed with src it will be expanded
173 to a list of binary package names. Otherwise the original
174 package name will be returned.
175-
176+
177 :param pkgname: The package name (that may include src:prefix).
178- :return: A list of binary package names (the list may be one element long).
179+ :return: A list of binary package names (the list may be one element
180+ long).
181 """
182 if not pkgname.startswith("src:"):
183 return [pkgname]
184 return get_binaries_for_source_pkg(pkgname.split("src:")[1])
185
186+
187 def create_and_update_deb_src_source_list(distroseries):
188 """ Create sources.list and update cache.
189
190- This creates a sources.list file with deb-src entries for a given
191+ This creates a sources.list file with deb-src entries for a given
192 distroseries and apt.Cache.update() to make sure the data is up-to-date.
193 :param distro: The code name of the distribution series (e.g. lucid).
194 :return: None
195 :raises: IOError: When cache update fails.
196 """
197 # apt root dir
198- rootdir="./aptroot.%s" % distroseries
199- sources_list_dir = os.path.join(rootdir, "etc","apt")
200+ rootdir = "./aptroot.%s" % distroseries
201+ sources_list_dir = os.path.join(rootdir, "etc", "apt")
202 if not os.path.exists(sources_list_dir):
203 os.makedirs(sources_list_dir)
204- sources_list = open(os.path.join(sources_list_dir, "sources.list"),"w")
205+ sources_list = open(os.path.join(sources_list_dir, "sources.list"), "w")
206 for pocket in [
207- "%s" % distroseries,
208- "%s-updates" % distroseries,
209+ "%s" % distroseries,
210+ "%s-updates" % distroseries,
211 "%s-security" % distroseries]:
212 sources_list.write(
213 "deb-src %s %s main restricted\n" % (
214@@ -134,13 +158,13 @@
215 sources_list.close()
216 # create required dirs/files for apt.Cache(rootdir) to work on older
217 # versions of python-apt. once lucid is used it can be removed
218- for d in ["var/lib/dpkg",
219- "var/cache/apt/archives/partial",
220- "var/lib/apt/lists/partial"]:
221- if not os.path.exists(os.path.join(rootdir,d)):
222- os.makedirs(os.path.join(rootdir,d))
223- if not os.path.exists(os.path.join(rootdir,"var/lib/dpkg/status")):
224- open(os.path.join(rootdir,"var/lib/dpkg/status"),"w")
225+ for d in ["var/lib/dpkg",
226+ "var/cache/apt/archives/partial",
227+ "var/lib/apt/lists/partial"]:
228+ if not os.path.exists(os.path.join(rootdir, d)):
229+ os.makedirs(os.path.join(rootdir, d))
230+ if not os.path.exists(os.path.join(rootdir, "var/lib/dpkg/status")):
231+ open(os.path.join(rootdir, "var/lib/dpkg/status"), "w")
232 # open cache with our just prepared rootdir
233 cache = apt.Cache(rootdir=rootdir)
234 try:
235@@ -148,24 +172,28 @@
236 except SystemError:
237 logging.exception("cache.update() failed")
238
239+
240 def get_structure(distroname, version):
241 """ Get structure file conent for named distro and distro version.
242-
243+
244 :param name: Name of the distribution (e.g. kubuntu, ubuntu, xubuntu).
245 :param version: Code name of the distribution version (e.g. lucid).
246 :return: List of strings with the structure file content
247 """
248- f = urllib2.urlopen("%s/%s.%s/structure" % (BASE_URL, distroname, version))
249+ f = urllib2.urlopen("%s/%s.%s/structure" % (
250+ BASE_URL, distroname, version))
251 structure = f.readlines()
252 f.close()
253 return structure
254
255+
256 def expand_seeds(structure, seedname):
257 """ Expand seed by its dependencies using the strucure file.
258
259 :param structure: The content of the STRUCTURE file as string list.
260 :param seedname: The name of the seed as string that needs to be expanded.
261- :return: a set() for the seed dependencies (excluding the original seedname)
262+ :return: a set() for the seed dependencies (excluding the original
263+ seedname)
264 """
265 seeds = []
266 for line in structure:
267@@ -175,9 +203,10 @@
268 seeds += expand_seeds(structure, seed)
269 return set(seeds)
270
271+
272 def get_packages_for_seeds(name, distro, seeds):
273 """
274- get packages for the given name (e.g. ubuntu) and distro release
275+ get packages for the given name (e.g. ubuntu) and distro release
276 (e.g. lucid) that are in the given list of seeds
277 returns a set() of package names
278 """
279@@ -185,7 +214,7 @@
280 for bseed in seeds:
281 for seed in [bseed]: #, bseed+".build-depends", bseed+".seed"]:
282 pkgs_in_seeds[seed] = set()
283- seedurl = "%s/%s.%s/%s" % (BASE_URL,name, distro, seed)
284+ seedurl = "%s/%s.%s/%s" % (BASE_URL, name, distro, seed)
285 logging.debug("looking for '%s'" % seedurl)
286 try:
287 f = urllib2.urlopen(seedurl)
288@@ -204,6 +233,7 @@
289 logging.error("seed %s failed (%s)" % (seedurl, e))
290 return pkgs_in_seeds
291
292+
293 def what_seeds(pkgname, seeds):
294 in_seeds = set()
295 for s in seeds:
296@@ -211,6 +241,7 @@
297 in_seeds.add(s)
298 return in_seeds
299
300+
301 def compare_support_level(x, y):
302 """
303 compare two support level strings of the form 18m, 3y etc
304@@ -218,9 +249,10 @@
305 :parm y: the second support level
306 :return: negative if x < y, zero if x==y, positive if x > y
307 """
308+
309 def support_to_int(support_time):
310 """
311- helper that takes a support time string and converts it to
312+ helper that takes a support time string and converts it to
313 a integer for cmp()
314 """
315 # allow strings like "5y (kubuntu-common)
316@@ -233,7 +265,9 @@
317 raise ValueError("support time '%s' has to end with y or m" % x)
318 return cmp(support_to_int(x), support_to_int(y))
319
320-def get_packages_support_time(structure, name, pkg_support_time, support_timeframe_list):
321+
322+def get_packages_support_time(structure, name, pkg_support_time,
323+ support_timeframe_list):
324 """
325 input a structure file and a list of pair<timeframe, seedlist>
326 return a dict of pkgnames -> support timeframe string
327@@ -255,18 +289,21 @@
328 pkg, old_timeframe, timeframe))
329 pkg_support_time[pkg] = timeframe
330 if options.with_seeds:
331- pkg_support_time[pkg] += " (%s)" % ", ".join(what_seeds(pkg, pkgs_in_seeds))
332+ pkg_support_time[pkg] += " (%s)" % ", ".join(
333+ what_seeds(pkg, pkgs_in_seeds))
334
335
336 return pkg_support_time
337
338+
339 if __name__ == "__main__":
340 parser = OptionParser()
341 parser.add_option("--with-seeds", "", default=False,
342- action="store_true",
343- help="add seed(s) of the package that are responsible for the maintaince time")
344+ action="store_true",
345+ help="add seed(s) of the package that are responsible "
346+ "for the maintaince time")
347 parser.add_option("--source-packages", "", default=False,
348- action="store_true",
349+ action="store_true",
350 help="show as source pkgs")
351 parser.add_option("--hints-file", "", default=None,
352 help="use diffenrt use hints file location")
353@@ -275,8 +312,8 @@
354 # init
355 if len(args) > 0:
356 distro = args[0]
357- if distro[0] < 'h':
358- print "ERROR: only hardy or later is supported"
359+ if distro in UNSUPPORTED_DISTRO_RELEASED:
360+ logging.error("only lucid or later is supported")
361 sys.exit(1)
362 else:
363 distro = "lucid"
364@@ -286,26 +323,32 @@
365
366 if options.hints_file:
367 hints_file = options.hints_file
368- (schema, netloc, path, query, fragment) = urlparse.urlsplit(hints_file)
369+ (schema, netloc, path, query, fragment) = urlparse.urlsplit(
370+ hints_file)
371 if not schema:
372 hints_file = "file:%s" % path
373 else:
374 hints_file = HINTS_DIR_URL % distro
375-
376+
377 # go over the distros we need to check
378 pkg_support_time = {}
379 for (name, lts_supported) in DISTRO_NAMES_AND_LTS_SUPPORT:
380
381 # get basic structure file
382- structure = get_structure(name, distro)
383-
384+ try:
385+ structure = get_structure(name, distro)
386+ except urllib2.HTTPError:
387+ logging.error("Can not get structure for '%s'." % name)
388+ continue
389+
390 # get dicts of pkgname -> support timeframe string
391 support_timeframe = SUPPORT_TIMEFRAME
392 if lts_supported and distro in LTS_RELEASES:
393- support_timeframe = SUPPORT_TIMEFRAME_LTS
394+ support_timeframe = SUPPORT_TIMEFRAME_LTS
395 else:
396 support_timeframe = SUPPORT_TIMEFRAME
397- get_packages_support_time(structure, name, pkg_support_time, support_timeframe)
398+ get_packages_support_time(
399+ structure, name, pkg_support_time, support_timeframe)
400
401 # now go over the bits in main that we have not seen (because
402 # they are not in any seed and got added manually into "main"
403@@ -321,10 +364,11 @@
404 for pkg in cache:
405 if not pkg.name in pkg_support_time:
406 pkg_support_time[pkg.name] = support_timeframe[-1][0]
407- logging.warn("add package in main but not in seeds %s with %s" %
408- (pkg.name, pkg_support_time[pkg.name]))
409+ logging.warn(
410+ "add package in main but not in seeds %s with %s" % (
411+ pkg.name, pkg_support_time[pkg.name]))
412
413- # now check the hints file that is used to overwrite
414+ # now check the hints file that is used to overwrite
415 # the default seeds
416 try:
417 for line in urllib2.urlopen(hints_file):
418@@ -337,14 +381,15 @@
419 if support_time == 'unsupported':
420 try:
421 del pkg_support_time[pkgname]
422- sys.stderr.write("hints-file: marking %s unsupported\n" % pkgname)
423+ sys.stderr.write("hints-file: marking %s "
424+ "unsupported\n" % pkgname)
425 except KeyError:
426 pass
427 else:
428 if pkg_support_time.get(pkgname) != support_time:
429 sys.stderr.write(
430 "hints-file: changing %s from %s to %s\n" % (
431- pkgname, pkg_support_time.get(pkgname),
432+ pkgname, pkg_support_time.get(pkgname),
433 support_time))
434 pkg_support_time[pkgname] = support_time
435 except:
436@@ -353,7 +398,7 @@
437 if e.code != 404:
438 raise
439 sys.stderr.write("hints-file: %s gave 404 error\n" % hints_file)
440-
441+
442 # output suitable for the extra-override file
443 for pkgname in sorted(pkg_support_time.keys()):
444 # special case, the hints file may contain overrides that
445@@ -362,7 +407,7 @@
446 print "%s %s %s" % (
447 pkgname, SUPPORT_TAG, pkg_support_time[pkgname])
448 else:
449- # go over the supported arches, they are divided in
450+ # go over the supported arches, they are divided in
451 # first-class (PRIMARY) and second-class with different
452 # support levels
453 for arch in SUPPORTED_ARCHES:
454@@ -373,10 +418,11 @@
455 if arch in PRIMARY_ARCHES:
456 # arch with full LTS support
457 print "%s %s %s" % (
458- pkgname_and_arch, SUPPORT_TAG, pkg_support_time[pkgname])
459+ pkgname_and_arch, SUPPORT_TAG,
460+ pkg_support_time[pkgname])
461 else:
462 # not a LTS supported architecture, gets only regular
463 # support_timeframe
464 print "%s %s %s" % (
465- pkgname_and_arch, SUPPORT_TAG, SUPPORT_TIMEFRAME[0][0])
466-
467+ pkgname_and_arch, SUPPORT_TAG,
468+ SUPPORT_TIMEFRAME[0][0])
469
470=== added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data'
471=== added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin'
472=== added file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/germinate'
473--- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/germinate 1970-01-01 00:00:00 +0000
474+++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/germinate 2011-01-07 13:50:46 +0000
475@@ -0,0 +1,5 @@
476+#!/bin/sh
477+#
478+# This is a mock germinate script that just produces enough (empty)
479+# files so that the cron.germinate shell script can run.
480+touch structure all all.sources minimal standard
481
482=== added file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile'
483--- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile 1970-01-01 00:00:00 +0000
484+++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile 2011-01-07 13:50:46 +0000
485@@ -0,0 +1,8 @@
486+#!/bin/sh
487+
488+# This is a mock "lockfile" command that is used during the test
489+# There is no need to have the real lockfile installed (its part
490+# of procmail) because there can be no multiple germinate instances
491+# while we run the tests
492+
493+exit 1
494
495=== added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root'
496=== added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts'
497=== added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/publishing'
498=== added symlink 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/publishing/maintenance-check.py'
499=== target is u'../../../../../../../../../cronscripts/publishing/maintenance-check.py'
500=== added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts'
501=== added directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools'
502=== added file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py'
503--- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py 1970-01-01 00:00:00 +0000
504+++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py 2011-01-07 13:50:46 +0000
505@@ -0,0 +1,27 @@
506+#!/usr/bin/python
507+#
508+# This is a mock version of the lp-query-distro.py script that
509+# returns static data so that the cron.germinate shell script
510+# can be tested.
511+
512+import sys
513+
514+
515+def error_and_exit():
516+ sys.stderr.write("ERROR: I'm a mock, I only support 'development' "
517+ "and 'supported' as argument\n")
518+ sys.exit(1)
519+
520+
521+if __name__ == "__main__":
522+ # There is only a very limited subset of arguments that we support,
523+ # test for it and error if it looks wrong
524+ if len(sys.argv) != 2:
525+ error_and_exit()
526+ distro = sys.argv[1]
527+ if distro == "development":
528+ print "natty"
529+ elif distro == "supported":
530+ print "hardy jaunty karmic lucid maverick"
531+ else:
532+ error_and_exit()
533
534=== added file 'lib/lp/soyuz/scripts/tests/test_cron_germinate.py'
535--- lib/lp/soyuz/scripts/tests/test_cron_germinate.py 1970-01-01 00:00:00 +0000
536+++ lib/lp/soyuz/scripts/tests/test_cron_germinate.py 2011-01-07 13:50:46 +0000
537@@ -0,0 +1,230 @@
538+#!/usr/bin/python
539+# Copyright 2010 Canonical Ltd. This software is licensed under the
540+# GNU Affero General Public License version 3 (see the file LICENSE).
541+
542+"""This is a test for the soyuz cron.germinate script."""
543+
544+__metaclass__ = type
545+
546+import copy
547+import gzip
548+import os
549+import subprocess
550+import unittest
551+
552+try:
553+ from lp.testing import TestCase
554+except ImportError:
555+ # mvo: *cough* poor mans version if no full LP environment is installed
556+ class PoorMvosTestCase(unittest.TestCase):
557+ def makeTemporaryDirectory(self):
558+ import tempfile
559+ return tempfile.mkdtemp(prefix="test_cron_germinate_")
560+ TestCase = PoorMvosTestCase
561+
562+class TestCronGerminate(TestCase):
563+
564+ DISTRO_NAMES = [ "platform", "ubuntu", "kubuntu", "netbook" ]
565+ DISTS = ["hardy", "lucid", "maverick"]
566+ DEVELOPMENT_DIST = "natty"
567+ COMPONENTS = ["main", "restricted", "universe", "multiverse"]
568+ ARCHES = ["i386", "amd64", "armel", "powerpc"]
569+ BASEPATH = os.path.abspath(os.path.dirname(__file__))
570+ source_root = os.path.normpath(
571+ os.path.join(BASEPATH, "..", "..", "..", "..", ".."))
572+
573+ def setUp(self):
574+ super(TestCronGerminate, self).setUp()
575+
576+ # Setup a temp archive directory and populate it with the right
577+ # sub-directories.
578+ self.tmpdir = self.makeTemporaryDirectory()
579+ self.archive_dir = self.setup_mock_archive_environment()
580+ self.ubuntu_misc_dir = os.path.join(self.archive_dir, "ubuntu-misc")
581+ self.ubuntu_germinate_dir = os.path.join(
582+ self.archive_dir, "ubuntu-germinate")
583+ # create a mock archive environment for all the distros we
584+ # support and also include "updates" and "security"
585+ for dist in self.DISTS + [self.DEVELOPMENT_DIST]:
586+ self.populate_mock_archive_environment(
587+ self.archive_dir, self.COMPONENTS, self.ARCHES, dist)
588+ for component in ["security", "updates"]:
589+ self.populate_mock_archive_environment(
590+ self.archive_dir, self.COMPONENTS, self.ARCHES,
591+ "%s-%s" % (dist, component))
592+ # generate test dummies for maintenance-time.py, if this is
593+ # set to "None" instead it will use the network to test against
594+ # the real data
595+ self.germinate_output_dir = self.setup_mock_germinate_output()
596+
597+ def create_directory_if_missing(self, directory):
598+ """Create the given directory if it does not exist."""
599+ if not os.path.exists(directory):
600+ os.makedirs(directory)
601+
602+ def create_directory_list_if_missing(self, directory_list):
603+ """Create the given directories from the list if they don't exist."""
604+ for directory in directory_list:
605+ self.create_directory_if_missing(directory)
606+
607+ def create_gzip_file(self, filepath, content=""):
608+ """Create a gziped file in the given path with the given content.
609+ If not content is given a empty file is created.
610+ """
611+ gz = gzip.GzipFile(filepath, "w")
612+ gz.write(content)
613+ gz.close()
614+
615+ def create_file(self, filepath, content=""):
616+ """Create a file in the given path with the given content.
617+ If not content is given a empty file is created.
618+ """
619+ f = open(filepath, "w")
620+ f.write(content)
621+ f.close()
622+
623+ def setup_mock_germinate_output(self):
624+ # empty structure files
625+ germinate_output_dir = os.path.join(
626+ self.tmpdir, "germinate-test-data", "germinate-output")
627+ dirs = []
628+ for distro_name in self.DISTRO_NAMES:
629+ for distro_series in self.DISTS:
630+ dirs.append(os.path.join(germinate_output_dir, "%s.%s" % (distro_name, distro_series)))
631+ self.create_directory_list_if_missing(dirs)
632+ for dir in dirs:
633+ self.create_file(os.path.join(dir, "structure"))
634+ return germinate_output_dir
635+
636+ def setup_mock_archive_environment(self):
637+ """Creates a mock archive environment and populate
638+ it with the subdirectories that germinate will expect.
639+ """
640+ archive_dir = os.path.join(
641+ self.tmpdir, "germinate-test-data", "ubuntu-archive")
642+ ubuntu_misc_dir = os.path.join(archive_dir, "ubuntu-misc")
643+ ubuntu_germinate_dir = os.path.join(archive_dir, "ubuntu-germinate")
644+ ubuntu_dists_dir = os.path.join(archive_dir, "ubuntu", "dists")
645+ self.create_directory_list_if_missing([
646+ archive_dir,
647+ ubuntu_misc_dir,
648+ ubuntu_germinate_dir,
649+ ubuntu_dists_dir])
650+ return archive_dir
651+
652+ def populate_mock_archive_environment(self, archive_dir, components_list,
653+ arches_list, current_devel_distro):
654+ """Populates a mock archive environment with empty source packages
655+ and empty binary packages.
656+ """
657+ for component in components_list:
658+ # Create the environment for the source packages.
659+ targetdir = os.path.join(
660+ archive_dir,
661+ "ubuntu/dists/%s/%s/source" % (
662+ current_devel_distro, component))
663+ self.create_directory_if_missing(targetdir)
664+ self.create_gzip_file(os.path.join(targetdir, "Sources.gz"))
665+
666+ # Create the environment for the binary packages.
667+ for arch in arches_list:
668+ for subpath in ["", "debian-installer"]:
669+ targetdir = os.path.join(
670+ self.archive_dir,
671+ "ubuntu/dists/%s/%s/%s/binary-%s" % (
672+ current_devel_distro, component, subpath, arch))
673+ self.create_directory_if_missing(targetdir)
674+ self.create_gzip_file(os.path.join(
675+ targetdir, "Packages.gz"))
676+
677+ def create_fake_environment(self, basepath, archive_dir,
678+ germinate_output_dir):
679+ """Create a fake process envirionment based on os.environ that
680+ sets TEST_ARCHIVEROOT, TEST_LAUNCHPADROOT and modifies PATH
681+ to point to the mock lp-bin directory.
682+ """
683+ fake_environ = copy.copy(os.environ)
684+ fake_environ["TEST_ARCHIVEROOT"] = os.path.abspath(
685+ os.path.join(archive_dir, "ubuntu"))
686+ fake_environ["TEST_LAUNCHPADROOT"] = os.path.abspath(
687+ os.path.join(basepath, "germinate-test-data/mock-lp-root"))
688+ # Set the PATH in the fake environment so that our mock germinate
689+ # is used. We could use the real germinate as well, but that will
690+ # slow down the tests a lot and its also not interessting for this
691+ # test as we do not use any of the germinate information.
692+ fake_environ["PATH"] = "%s:%s" % (
693+ os.path.abspath(os.path.join(
694+ basepath, "germinate-test-data/mock-bin")),
695+ os.environ["PATH"])
696+ # test dummies for get-support-timeframe.py, they need to be
697+ # in URI format
698+ if germinate_output_dir:
699+ # redirect base url to the mock environment
700+ fake_environ["MAINTENANCE_CHECK_BASE_URL"] = "file://%s" % \
701+ germinate_output_dir
702+ # point to mock archive root
703+ archive_root_url = "file://%s" % os.path.abspath(
704+ os.path.join(archive_dir, "ubuntu"))
705+ fake_environ["MAINTENANCE_CHECK_ARCHIVE_ROOT"] = archive_root_url
706+ # maintenance-check.py expects a format string
707+ hints_file_url = germinate_output_dir + "/platform.%s/SUPPORTED_HINTS"
708+ for distro in self.DISTS:
709+ open(hints_file_url % distro, "w")
710+ fake_environ["MAINTENANCE_CHECK_HINTS_DIR_URL"] = "file://%s" % \
711+ os.path.abspath(hints_file_url)
712+ # add hints override to test that feature
713+ f=open(hints_file_url % "lucid", "a")
714+ f.write("linux-image-2.6.32-25-server 5y\n")
715+ f.close()
716+ return fake_environ
717+
718+ def test_maintenance_update(self):
719+ """Test the maintenance-check.py porition of the soyuz cron.germinate
720+ shell script by running it inside a fake environment and ensure
721+ that it did update the "Support" override information for
722+ apt-ftparchive without destroying/modifying the information
723+ that the "germinate" script added to it earlier.
724+ """
725+ # Write into more-extras.overrides to ensure it is alive after we
726+ # mucked around.
727+ canary = "abrowser Task mock\n"
728+ # Build fake environment based on the real one.
729+ fake_environ = self.create_fake_environment(
730+ self.BASEPATH, self.archive_dir, self.germinate_output_dir)
731+ # Create mock override data files that include the canary string
732+ # so that we can test later if it is still there.
733+ for dist in self.DISTS:
734+ self.create_file(
735+ os.path.join(self.ubuntu_misc_dir,
736+ "more-extra.override.%s.main" % dist),
737+ canary)
738+
739+ # Run cron.germinate in the fake environment.
740+ cron_germinate_path = os.path.join(
741+ self.source_root, "cronscripts", "publishing", "cron.germinate")
742+ subprocess.call(
743+ [cron_germinate_path], env=fake_environ, cwd=self.BASEPATH)
744+
745+ # And check the output it generated for correctness.
746+ for dist in self.DISTS:
747+ supported_override_file = os.path.join(
748+ self.ubuntu_misc_dir,
749+ "more-extra.override.%s.main.supported" % dist)
750+ self.assertTrue(os.path.exists(supported_override_file),
751+ "no override file created for '%s'" % dist)
752+ main_override_file = os.path.join(
753+ self.ubuntu_misc_dir,
754+ "more-extra.override.%s.main" % dist)
755+ self.assertIn(canary, open(main_override_file).read(),
756+ "canary no longer there for '%s'" % dist)
757+
758+ # Check here if we got the data from maintenance-check.py that
759+ # we expected. This is a kernel name from lucid-updates and it
760+ # will be valid for 5 years.
761+ needle = "linux-image-2.6.32-25-server/i386 Supported 5y"
762+ lucid_supported_override_file = os.path.join(
763+ self.ubuntu_misc_dir, "more-extra.override.lucid.main")
764+ self.assertIn(needle, open(lucid_supported_override_file).read())
765+
766+if __name__ == "__main__":
767+ unittest.main()

Subscribers

People subscribed via source and target branches

to status/vote changes: