class UpdateVerifyConfigCreator(BaseScript):
    config_options = [
        [["--product"], {
            "dest": "product",
            "help": "Product being tested, as used in the update URL and filenames. Eg: firefox",
        }],
        [["--stage-product"], {
            "dest": "stage_product",
            "help": "Product being tested, as used in stage directories and ship it"
                    "If not passed this is assumed to be the same as product."
        }],
        [["--app-name"], {
            "dest": "app_name",
            "help": "App name being tested. Eg: browser",
        }],
        [["--branch-prefix"], {
            "dest": "branch_prefix",
            "help": "Prefix of release branch names. Eg: mozilla, comm",
        }],
        [["--channel"], {
            "dest": "channel",
            "help": "Channel to run update verify against",
        }],
        [["--aus-server"], {
            "dest": "aus_server",
            "default": "https://aus5.mozilla.org",
            "help": "AUS server to run update verify against",
        }],
        [["--to-version"], {
            "dest": "to_version",
            "help": "The version of the release being updated to. Eg: 59.0b5",
        }],
        [["--to-app-version"], {
            "dest": "to_app_version",
            "help": "The in-app version of the release being updated to. Eg: 59.0",
        }],
        [["--to-display-version"], {
            "dest": "to_display_version",
            "help": "The human-readable version of the release being updated to. Eg: 59.0 Beta 9",
        }],
        [["--to-build-number"], {
            "dest": "to_build_number",
            "help": "The build number of the release being updated to",
        }],
        [["--to-buildid"], {
            "dest": "to_buildid",
            "help": "The buildid of the release being updated to",
        }],
        [["--to-revision"], {
            "dest": "to_revision",
            "help": "The revision that the release being updated to was built against",
        }],
        [["--partial-version"], {
            "dest": "partial_versions",
            "default": [],
            "action": "append",
            "help": "A previous release version that is expected to receive a partial update. "
                    "Eg: 59.0b4. May be specified multiple times."
        }],
        [["--last-watershed"], {
            "dest": "last_watershed",
            "help": "The earliest version to include in the update verify config. Eg: 57.0b10",
        }],
        [["--include-version"], {
            "dest": "include_versions",
            "default": [],
            "action": "append",
            "help": "Only include versions that match one of these regexes. "
                    "May be passed multiple times",
        }],
        [["--mar-channel-id-override"], {
            "dest": "mar_channel_id_options",
            "default": [],
            "action": "append",
            "help": "A version regex and channel id string to override those versions with."
                    "Eg: ^\\d+\\.\\d+(\\.\\d+)?$,firefox-mozilla-beta,firefox-mozilla-release "
                    "will set accepted mar channel ids to 'firefox-mozilla-beta' and "
                    "'firefox-mozilla-release for x.y and x.y.z versions. "
                    "May be passed multiple times"
        }],
        [["--override-certs"], {
            "dest": "override_certs",
            "default": None,
            "help": "Certs to override the updater with prior to running update verify."
                    "If passed, should be one of: dep, nightly, release"
                    "If not passed, no certificate overriding will be configured"
        }],
        [["--platform"], {
            "dest": "platform",
            "help": "The platform to generate the update verify config for, in FTP-style",
        }],
        [["--updater-platform"], {
            "dest": "updater_platform",
            "help": "The platform to run the updater on, in FTP-style."
                    "If not specified, this is assumed to be the same as platform",
        }],
        [["--archive-prefix"], {
            "dest": "archive_prefix",
            "help": "The server/path to pull the current release from. "
                    "Eg: https://archive.mozilla.org/pub",
        }],
        [["--previous-archive-prefix"], {
            "dest": "previous_archive_prefix",
            "help": "The server/path to pull the previous releases from"
                    "If not specified, this is assumed to be the same as --archive-prefix"
        }],
        [["--repo-path"], {
            "dest": "repo_path",
            "help": "The repository (relative to the hg server root) that the current release was "
                    "built from Eg: releases/mozilla-beta"
        }],
        [["--output-file"], {
            "dest": "output_file",
            "help": "Where to write the update verify config to",
        }],
        [["--product-details-server"], {
            "dest": "product_details_server",
            "default": "https://product-details.mozilla.org",
            "help": "Product Details server to pull previous release info from. "
                    "Using anything other than the production server is likely to "
                    "cause issues with update verify."
        }],
        [["--hg-server"], {
            "dest": "hg_server",
            "default": "https://hg.mozilla.org",
            "help": "Mercurial server to pull various previous and current version info from",
        }],
        [["--full-check-locale"], {
            "dest": "full_check_locales",
            "default": ["de", "en-US", "ru"],
            "action": "append",
            "help": "A list of locales to generate full update verify checks for",
        }],
    ]

    def __init__(self):
        BaseScript.__init__(
            self,
            config_options=self.config_options,
            config={},
            all_actions=[
                "gather-info",
                "create-config",
                "write-config",
            ],
            default_actions=[
                "gather-info",
                "create-config",
                "write-config",
            ],
        )

    def _pre_config_lock(self, rw_config):
        super(UpdateVerifyConfigCreator, self)._pre_config_lock(rw_config)

        if "updater_platform" not in self.config:
            self.config["updater_platform"] = self.config["platform"]
        if "stage_product" not in self.config:
            self.config["stage_product"] = self.config["product"]
        if "previous_archive_prefix" not in self.config:
            self.config["previous_archive_prefix"] = self.config["archive_prefix"]
        self.config["archive_prefix"].rstrip("/")
        self.config["previous_archive_prefix"].rstrip("/")
        self.config["mar_channel_id_overrides"] = {}
        for override in self.config["mar_channel_id_options"]:
            pattern, override_str = override.split(",", 1)
            self.config["mar_channel_id_overrides"][pattern] = override_str

    def _get_update_paths(self):
        from mozrelease.l10n import getPlatformLocales
        from mozrelease.paths import getCandidatesDir
        from mozrelease.platforms import ftp2infoFile
        from mozrelease.versions import MozillaVersion

        self.update_paths = {}

        ret = self._retry_download(
            "{}/1.0/{}.json".format(
                self.config["product_details_server"],
                self.config["stage_product"],
            ),
            "WARNING",
        )
        releases = json.load(ret)["releases"]
        for release_name, release_info in reversed(sorted(releases.items())):
            product, version = release_name.split("-", 1)
            tag = "{}_{}_RELEASE".format(product.upper(), version.replace(".", "_"))
            # Product details has a "category" for releases that we can use to
            # determine the repo path. This will fail if any previous releases
            # were built from a project branch - but that's not something we do
            # at the time of writing.
            branch = None
            if release_info["category"] == "dev":
                branch = "releases/{}-beta".format(self.config['branch_prefix'])
            elif release_info["category"] == "esr":
                branch = "releases/{}-esr{}".format(self.config['branch_prefix'], version[:2])
            elif release_info["category"] in ("major", "stability"):
                branch = "releases/{}-release".format(self.config['branch_prefix'])
            if not branch:
                raise Exception("Cannot determine branch, cannot continue!")

            # Exclude any releases that don't match one of our include version
            # regexes. This is generally to avoid including versions from other
            # channels. Eg: including betas when testing releases
            for v in self.config["include_versions"]:
                if re.match(v, version):
                    break
            else:
                self.log("Skipping release whose version doesn't match any "
                         "include_version pattern: %s" % release_name,
                         level=INFO)
                continue

            # We also have to trim out previous releases that aren't in the same
            # product line, too old, etc.
            if self.config["stage_product"] != product:
                self.log("Skipping release that doesn't match product name: %s" % release_name,
                         level=INFO)
                continue
            if MozillaVersion(version) < MozillaVersion(self.config["last_watershed"]):
                self.log("Skipping release that's behind the last watershed: %s" % release_name,
                         level=INFO)
                continue
            if version == self.config["to_version"]:
                self.log("Skipping release that is the same as to version: %s" % release_name,
                         level=INFO)
                continue
            if MozillaVersion(version) > MozillaVersion(self.config["to_version"]):
                self.log("Skipping release that's newer than to version: %s" % release_name,
                         level=INFO)
                continue

            if version in self.update_paths:
                raise Exception("Found duplicate release for version: %s", version)

            # This is a crappy place to get buildids from, but we don't have a better one.
            # This will start to fail if old info files are deleted.
            info_file_url = "{}{}/{}_info.txt".format(
                self.config["previous_archive_prefix"],
                getCandidatesDir(
                    self.config["stage_product"],
                    version,
                    release_info["build_number"],
                ),
                ftp2infoFile(self.config["platform"])
            )
            self.log("Retrieving buildid from info file: %s" % info_file_url, level=DEBUG)
            ret = self._retry_download(info_file_url, "WARNING")
            buildID = ret.read().split("=")[1].strip()

            shipped_locales_url = urljoin(
                self.config["hg_server"],
                "{}/raw-file/{}/{}/locales/shipped-locales".format(
                    branch,
                    tag,
                    self.config["app_name"],
                ),
            )
            ret = self._retry_download(shipped_locales_url, "WARNING")
            shipped_locales = ret.read().strip()

            app_version_url = urljoin(
                self.config["hg_server"],
                "{}/raw-file/{}/{}/config/version.txt".format(
                    branch,
                    tag,
                    self.config["app_name"],
                ),
            )
            app_version = self._retry_download(app_version_url, "WARNING").read().strip()

            self.log("Adding {} to update paths".format(version), level=INFO)
            self.update_paths[version] = {
                "appVersion": app_version,
                "locales": getPlatformLocales(shipped_locales, self.config["platform"]),
                "buildID": buildID,
            }
            for pattern, mar_channel_ids in self.config["mar_channel_id_overrides"].items():
                if re.match(pattern, version):
                    self.update_paths[version]["marChannelIds"] = mar_channel_ids

    def gather_info(self):
        self._get_update_paths()
        if self.update_paths:
            self.log("Found update paths:", level=DEBUG)
            self.log(pprint.pformat(self.update_paths), level=DEBUG)
        else:
            self.log("Didn't find any update paths, cannot continue", level=FATAL)

    def create_config(self):
        from mozrelease.l10n import getPlatformLocales
        from mozrelease.platforms import ftp2updatePlatforms
        from mozrelease.update_verify import UpdateVerifyConfig
        from mozrelease.paths import getCandidatesDir, getReleasesDir, getReleaseInstallerPath
        from mozrelease.versions import getPrettyVersion

        candidates_dir = getCandidatesDir(
            self.config["stage_product"], self.config["to_version"],
            self.config["to_build_number"],
        )
        to_ = getReleaseInstallerPath(
            self.config["product"], self.config["product"].title(),
            self.config["to_version"], self.config["platform"],
            locale="%locale%"
        )
        to_path = "{}/{}".format(candidates_dir, to_)

        to_display_version = self.config.get("to_display_version")
        if not to_display_version:
            to_display_version = getPrettyVersion(self.config["to_version"])

        self.update_verify_config = UpdateVerifyConfig(
            product=self.config["product"].title(), channel=self.config["channel"],
            aus_server=self.config["aus_server"], to=to_path,
            to_build_id=self.config["to_buildid"],
            to_app_version=self.config["to_app_version"],
            to_display_version=to_display_version,
            override_certs=self.config.get("override_certs"),
        )

        to_shipped_locales_url = urljoin(
            self.config["hg_server"],
            "{}/raw-file/{}/{}/locales/shipped-locales".format(
                self.config["repo_path"],
                self.config["to_revision"],
                self.config["app_name"],
            ),
        )
        to_shipped_locales = self._retry_download(to_shipped_locales_url, "WARNING").read().strip()
        to_locales = set(getPlatformLocales(to_shipped_locales, self.config["platform"]))

        completes_only_index = 0
        for fromVersion in reversed(sorted(self.update_paths, key=LooseVersion)):
            from_ = self.update_paths[fromVersion]
            locales = sorted(list(set(from_["locales"]).intersection(to_locales)))
            appVersion = from_["appVersion"]
            build_id = from_["buildID"]
            mar_channel_IDs = from_.get('marChannelIds')

            # Use new build targets for Windows, but only on compatible
            #  versions (42+). See bug 1185456 for additional context.
            if self.config["platform"] not in ("win32", "win64") or \
                    LooseVersion(fromVersion) < LooseVersion("42.0"):
                update_platform = ftp2updatePlatforms(self.config["platform"])[0]
            else:
                update_platform = ftp2updatePlatforms(self.config["platform"])[1]

            release_dir = getReleasesDir(
                self.config["stage_product"], fromVersion
            )
            path_ = getReleaseInstallerPath(
                self.config["product"], self.config["product"].title(),
                fromVersion, self.config["platform"], locale="%locale%",
            )
            from_path = "{}/{}".format(release_dir, path_)

            updater_package = "{}/{}".format(
                release_dir,
                getReleaseInstallerPath(
                    self.config["product"], self.config["product"].title(),
                    fromVersion, self.config["updater_platform"],
                    locale="%locale%",
                )
            )

            # Exclude locales being full checked
            quick_check_locales = [l for l in locales
                                   if l not in self.config["full_check_locales"]]
            # Get the intersection of from and to full_check_locales
            this_full_check_locales = [l for l in self.config["full_check_locales"]
                                       if l in locales]

            if fromVersion in self.config["partial_versions"]:
                self.info("Generating configs for partial update checks for %s" % fromVersion)
                self.update_verify_config.addRelease(
                    release=appVersion, build_id=build_id, locales=locales,
                    patch_types=["complete", "partial"], from_path=from_path,
                    ftp_server_from=self.config["previous_archive_prefix"],
                    ftp_server_to=self.config["archive_prefix"],
                    mar_channel_IDs=mar_channel_IDs, platform=update_platform,
                    updater_package=updater_package
                )
            else:
                if this_full_check_locales and is_triangualar(completes_only_index):
                    self.info("Generating full check configs for %s" % fromVersion)
                    self.update_verify_config.addRelease(
                        release=appVersion, build_id=build_id, locales=this_full_check_locales,
                        from_path=from_path,
                        ftp_server_from=self.config["previous_archive_prefix"],
                        ftp_server_to=self.config["archive_prefix"],
                        mar_channel_IDs=mar_channel_IDs, platform=update_platform,
                        updater_package=updater_package
                    )
                # Quick test for other locales, no download
                if len(quick_check_locales) > 0:
                    self.info("Generating quick check configs for %s" % fromVersion)
                    if not is_triangualar(completes_only_index):
                        # Assuming we skipped full check locales, using all locales
                        _locales = locales
                    else:
                        # Excluding full check locales from the quick check
                        _locales = quick_check_locales
                    self.update_verify_config.addRelease(
                        release=appVersion, build_id=build_id,
                        locales=_locales, platform=update_platform
                    )
                completes_only_index += 1

    def write_config(self):
        with open(self.config["output_file"], "w+") as fh:
            self.update_verify_config.write(fh)
Esempio n. 2
0
class TestUpdateVerifyConfig(unittest.TestCase):
    config = str(DATA_PATH.joinpath("sample-update-verify.cfg"))

    def setUp(self):
        self.uvc = UpdateVerifyConfig()
        fd, self.tmpfilename = mkstemp()
        self.tmpfile = os.fdopen(fd, "wb")

    def tearDown(self):
        self.tmpfile.close()
        os.unlink(self.tmpfilename)

    def testEq(self):
        self.uvc.product = "foo"
        self.uvc.channel = "betatest"
        self.uvc.aus_server = "aus"
        self.uvc.ftp_server_from = "ftp"
        self.uvc.ftp_server_to = "ftp"
        self.uvc.to = "/firefox/4.0rc2.tar.bz2"
        self.uvc.mar_channel_IDs = 'baz'
        self.uvc.to_build_id = "999"
        self.uvc.to_display_version = "99.0 Zeta 9"
        self.uvc.to_app_version = "99.0"
        uvc2 = UpdateVerifyConfig()
        uvc2.product = "foo"
        uvc2.channel = "betatest"
        uvc2.aus_server = "aus"
        uvc2.ftp_server_form = "ftp"
        uvc2.ftp_server_to = "ftp"
        uvc2.to = "/firefox/4.0rc2.tar.bz2"
        uvc2.mar_channel_IDs = 'baz'
        uvc2.to_build_id = "999"
        uvc2.to_display_version = "99.0 Zeta 9"
        uvc2.to_app_version = "99.0"
        self.assertEquals(self.uvc, uvc2)

    def testNe(self):
        self.uvc.product = "foo"
        uvc2 = UpdateVerifyConfig()
        # assertNotEqual doesn't test the __ne__ function, so we do this
        self.assertTrue(self.uvc != uvc2)

    def testAddRelease(self):
        releases = [
            {
                "release": "4.0",
                "platform": "bar",
                "build_id": 555,
                "locales": ["af", "de"],
                "patch_types": ["partial", "complete"],
                "from": "/pub/firefox/foo.bz2",
                "ftp_server_from": "from",
                "ftp_server_to": "to",
                "mar_channel_IDs": "firefox-mozilla-booyah",
                "updater_package": None,
            },
        ]
        self.uvc.addRelease("4.0",
                            build_id=555,
                            locales=["af", "de"],
                            patch_types=["partial", "complete"],
                            from_path="/pub/firefox/foo.bz2",
                            ftp_server_from="from",
                            ftp_server_to="to",
                            mar_channel_IDs="firefox-mozilla-booyah",
                            platform="bar")
        self.assertEquals(self.uvc.releases, releases)

    def testAddReleasesWithDifferentPlatforms(self):
        releases = [
            {
                "release": "4.0",
                "platform": "WINNT_x86-msvc",
                "build_id": 555,
                "locales": ["af", "de"],
                "patch_types": ["partial", "complete"],
                "from": "/pub/firefox/foo.bz2",
                "ftp_server_from": "from",
                "ftp_server_to": "to",
                "mar_channel_IDs": "firefox-mozilla-booyah",
                "updater_package": None,
            },
            {
                "release": "5.0",
                "platform": "WINNT_x86-msvc-x86",
                "build_id": 666,
                "locales": ["af", "de"],
                "patch_types": ["partial", "complete"],
                "from": "/pub/firefox/foo2.bz2",
                "ftp_server_from": "from",
                "ftp_server_to": "to",
                "mar_channel_IDs": "firefox-mozilla-booyah",
                "updater_package": None,
            },
        ]
        self.uvc.addRelease("4.0",
                            build_id=555,
                            locales=["af", "de"],
                            patch_types=["partial", "complete"],
                            from_path="/pub/firefox/foo.bz2",
                            ftp_server_from="from",
                            ftp_server_to="to",
                            mar_channel_IDs="firefox-mozilla-booyah",
                            platform="WINNT_x86-msvc")
        self.uvc.addRelease("5.0",
                            build_id=666,
                            locales=["af", "de"],
                            patch_types=["partial", "complete"],
                            from_path="/pub/firefox/foo2.bz2",
                            ftp_server_from="from",
                            ftp_server_to="to",
                            mar_channel_IDs="firefox-mozilla-booyah",
                            platform="WINNT_x86-msvc-x86")
        self.assertEquals(self.uvc.releases, releases)

    def testRead(self):
        ftp_server_from = "stage.mozilla.org/firefox"
        ftp_server_to = "stage.mozilla.org/firefox"
        uvc2 = UpdateVerifyConfig()
        uvc2.product = "Firefox"
        uvc2.channel = "betatest"
        uvc2.aus_server = "https://aus4.mozilla.org"
        uvc2.to = "/firefox/4.0rc2.tar.bz2"
        uvc2.to_build_id = "999"
        uvc2.to_display_version = "99.0 Zeta 9"
        uvc2.to_app_version = "99.0"
        uvc2.addRelease("4.0",
                        build_id="888",
                        platform="Linux_x86-gcc3",
                        locales=["af", "de", "en-US", "ja", "zh-TW"],
                        patch_types=["partial", "complete"],
                        from_path="/firefox/4.0rc1.tar.bz2",
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to,
                        mar_channel_IDs="firefox-mozilla-beta")
        uvc2.addRelease("4.0b12",
                        build_id="777",
                        platform="Linux_x86-gcc3",
                        locales=["af", "en-US"],
                        from_path="/firefox/4.0b12.tar.bz2",
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to)
        uvc2.addRelease("4.0b12",
                        build_id="777",
                        platform="Linux_x86-gcc3",
                        locales=["de", "ja", "zh-TW"],
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to)
        uvc2.addRelease("3.7a1",
                        build_id="666",
                        locales=["en-US"],
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to,
                        platform="Linux_x86-gcc3")

        self.uvc.read(self.config)
        self.assertEquals(self.uvc, uvc2)

    def testWrite(self):
        ftp_server_from = "stage.mozilla.org/firefox"
        ftp_server_to = "stage.mozilla.org/firefox"
        self.uvc.product = "Firefox"
        self.uvc.channel = "betatest"
        self.uvc.aus_server = "https://aus4.mozilla.org"
        self.uvc.to = "/firefox/4.0rc2.tar.bz2"
        self.uvc.to_build_id = "999"
        self.uvc.to_display_version = "99.0 Zeta 9"
        self.uvc.to_app_version = "99.0"
        self.uvc.addRelease("4.0",
                            build_id="888",
                            platform="Linux_x86-gcc3",
                            locales=("af", "de", "en-US", "ja", "zh-TW"),
                            patch_types=("partial", "complete"),
                            from_path="/firefox/4.0rc1.tar.bz2",
                            ftp_server_from=ftp_server_from,
                            ftp_server_to=ftp_server_to,
                            mar_channel_IDs="firefox-mozilla-beta")
        self.uvc.addRelease("4.0b12",
                            build_id="777",
                            platform="Linux_x86-gcc3",
                            locales=["af", "en-US"],
                            from_path="/firefox/4.0b12.tar.bz2",
                            ftp_server_from=ftp_server_from,
                            ftp_server_to=ftp_server_to)
        self.uvc.addRelease("4.0b12",
                            build_id="777",
                            platform="Linux_x86-gcc3",
                            locales=("de", "ja", "zh-TW"),
                            ftp_server_from=ftp_server_from,
                            ftp_server_to=ftp_server_to)
        self.uvc.addRelease("3.7a1",
                            build_id="666",
                            locales=("en-US", ),
                            ftp_server_from=ftp_server_from,
                            ftp_server_to=ftp_server_to,
                            platform="Linux_x86-gcc3")

        self.uvc.write(self.tmpfile)
        self.tmpfile.close()
        self.assertEquals(
            open(self.config).read(),
            open(self.tmpfilename).read())

    def testReadInvalidKey(self):
        invalidLine = 'foo="bar"'
        self.assertRaises(UpdateVerifyError, self.uvc._parseLine, invalidLine)

    def testReadDuplicateKey(self):
        invalidLine = 'release="bar" release="blah"'
        self.assertRaises(UpdateVerifyError, self.uvc._parseLine, invalidLine)

    def testParseLineBad(self):
        invalidLine = 'abh nthntuehonhuh nhhueont hntueoh nthouo'
        self.assertRaises(UpdateVerifyError, self.uvc._parseLine, invalidLine)

    def testGetChunk(self):
        ftp_server_from = "stage.mozilla.org/firefox"
        ftp_server_to = "stage.mozilla.org/firefox"
        self.uvc.read(self.config)
        uvc2 = UpdateVerifyConfig()
        uvc2.product = "Firefox"
        uvc2.channel = "betatest"
        uvc2.aus_server = "https://aus4.mozilla.org"
        uvc2.to = "/firefox/4.0rc2.tar.bz2"
        uvc2.to_build_id = "999"
        uvc2.to_display_version = "99.0 Zeta 9"
        uvc2.to_app_version = "99.0"
        uvc2.addRelease("4.0",
                        build_id="888",
                        platform="Linux_x86-gcc3",
                        locales=["af", "de", "en-US"],
                        patch_types=["partial", "complete"],
                        from_path="/firefox/4.0rc1.tar.bz2",
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to,
                        mar_channel_IDs="firefox-mozilla-beta")
        uvc2.addRelease("4.0b12",
                        build_id="777",
                        platform="Linux_x86-gcc3",
                        locales=["de", "ja"],
                        patch_types=["complete"],
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to,
                        from_path=None)
        chunkedConfig = self.uvc.getChunk(chunks=3, thisChunk=1)
        self.assertEquals(chunkedConfig, uvc2)

    def testGetChunkWithPathWithSpaces(self):
        self.uvc.product = "Firefox"
        self.uvc.channel = "betatest"
        self.uvc.aus_server = "https://aus4.mozilla.org"
        self.uvc.ftp_server_from = "stage.mozilla.org/firefox"
        self.uvc.ftp_server_to = "stage.mozilla.org/firefox"
        self.uvc.to = "/firefox/Firefox 4.0 Beta 2.exe"
        self.uvc.to_build_id = "999"
        self.uvc.to_display_version = "99.0 Zeta 9"
        self.uvc.to_app_version = "99.0"
        self.uvc.addRelease("4.0b1",
                            build_id="222",
                            platform="Linux_x86-gcc3",
                            locales=["en-US", "ja", "zh-TW"],
                            patch_types=["complete"],
                            from_path="/firefox/Firefox 4.0 Beta 1.exe")
        uvc2 = UpdateVerifyConfig()
        uvc2.product = "Firefox"
        uvc2.channel = "betatest"
        uvc2.aus_server = "https://aus4.mozilla.org"
        uvc2.ftp_server_from = "stage.mozilla.org/firefox"
        uvc2.ftp_server_to = "stage.mozilla.org/firefox"
        uvc2.to = "/firefox/Firefox 4.0 Beta 2.exe"
        uvc2.to_build_id = "999"
        uvc2.to_display_version = "99.0 Zeta 9"
        uvc2.to_app_version = "99.0"
        uvc2.addRelease("4.0b1",
                        build_id="222",
                        platform="Linux_x86-gcc3",
                        locales=["en-US", "ja"],
                        patch_types=["complete"],
                        from_path="/firefox/Firefox 4.0 Beta 1.exe")
        chunkedConfig = self.uvc.getChunk(chunks=2, thisChunk=1)
        self.assertEquals(chunkedConfig, uvc2)

    def testAddLocaleToRelease(self):
        from_path = "/firefox/4.0rc1.tar.bz2"
        self.uvc.read(self.config)
        self.uvc.addLocaleToRelease("888", "he", from_path)
        self.assertEquals(
            self.uvc.getRelease("888", from_path)["locales"],
            ["af", "de", "en-US", "he", "ja", "zh-TW"])

    def testAddLocaleToReleaseMultipleBuildIDs(self):
        from_path = None
        self.uvc.read(self.config)
        self.uvc.addLocaleToRelease("777", "he", from_path)
        self.assertEquals(
            self.uvc.getRelease("777", from_path)["locales"],
            ["de", "he", "ja", "zh-TW"])

    def testAddLocaleToNonexistentRelease(self):
        self.uvc.read(self.config)
        self.assertRaises(UpdateVerifyError, self.uvc.addLocaleToRelease,
                          "123", "he")

    def testGetReleaseNonexistenceRelease(self):
        self.uvc.read(self.config)
        self.assertEquals(self.uvc.getRelease("123", None), {})

    def testGetFullReleaseTests(self):
        ftp_server_from = "stage.mozilla.org/firefox"
        ftp_server_to = "stage.mozilla.org/firefox"
        self.uvc.read(self.config)
        uvc2 = UpdateVerifyConfig()
        uvc2.product = "Firefox"
        uvc2.channel = "betatest"
        uvc2.aus_server = "https://aus4.mozilla.org"
        uvc2.to = "/firefox/4.0rc2.tar.bz2"
        uvc2.to_build_id = "999"
        uvc2.to_display_version = "99.0 Zeta 9"
        uvc2.to_app_version = "99.0"
        uvc2.addRelease("4.0",
                        build_id="888",
                        platform="Linux_x86-gcc3",
                        locales=["af", "de", "en-US", "ja", "zh-TW"],
                        patch_types=["partial", "complete"],
                        from_path="/firefox/4.0rc1.tar.bz2",
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to,
                        mar_channel_IDs="firefox-mozilla-beta")
        uvc2.addRelease("4.0b12",
                        build_id="777",
                        platform="Linux_x86-gcc3",
                        locales=["af", "en-US"],
                        patch_types=["complete"],
                        from_path="/firefox/4.0b12.tar.bz2",
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to)
        self.assertEquals(self.uvc.getFullReleaseTests(), uvc2.releases)

    def testGetQuickReleaseTests(self):
        ftp_server_from = "stage.mozilla.org/firefox"
        ftp_server_to = "stage.mozilla.org/firefox"
        self.uvc.read(self.config)
        uvc2 = UpdateVerifyConfig()
        uvc2.product = "Firefox"
        uvc2.channel = "betatest"
        uvc2.aus_server = "https://aus4.mozilla.org"
        uvc2.to = "/firefox/4.0rc2.tar.bz2"
        uvc2.to_build_id = "999"
        uvc2.to_display_version = "99.0 Zeta 9"
        uvc2.to_app_version = "99.0"
        uvc2.addRelease("4.0b12",
                        build_id="777",
                        platform="Linux_x86-gcc3",
                        locales=["de", "ja", "zh-TW"],
                        patch_types=["complete"],
                        from_path=None,
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to)
        uvc2.addRelease("3.7a1",
                        build_id="666",
                        platform="Linux_x86-gcc3",
                        locales=["en-US"],
                        patch_types=["complete"],
                        from_path=None,
                        ftp_server_from=ftp_server_from,
                        ftp_server_to=ftp_server_to)
        self.assertEquals(self.uvc.getQuickReleaseTests(), uvc2.releases)