def test_key_incr(self, epoch_mock):
     epoch_mock.return_value = 123456
     cache_ns_key(self.namespace)  # Sets ns to 123456
     ns_key = cache_ns_key(self.namespace, increment=True)
     expected = '123457:ns:%s' % self.namespace
     assert ns_key == expected
     assert cache_ns_key(self.namespace) == expected
 def test_key_incr(self, epoch_mock):
     epoch_mock.return_value = 123456
     cache_ns_key(self.namespace)  # Sets ns to 123456
     ns_key = cache_ns_key(self.namespace, increment=True)
     expected = '123457:ns:%s' % self.namespace
     eq_(ns_key, expected)
     eq_(cache_ns_key(self.namespace), expected)
 def test_key_incr(self, epoch_mock):
     epoch_mock.return_value = 1549383758398
     cache_ns_key(self.namespace)  # Sets ns to 1549383758398
     ns_key = cache_ns_key(self.namespace, increment=True)  # Increments it.
     expected = '1549383758399:ns:%s' % self.namespace
     assert ns_key == expected
     assert cache_ns_key(self.namespace) == expected
Exemple #4
0
 def get_key(cls, key=None, invalidate=False):
     namespace = "riscore"
     if not key:  # Assuming we're invalidating the namespace.
         cache_ns_key(namespace, invalidate)
         return
     else:
         # Using cache_ns_key so each cache val is invalidated together.
         ns_key = cache_ns_key(namespace, invalidate)
         return "%s:%s" % (ns_key, key)
Exemple #5
0
 def get_key(cls, key=None, invalidate=False):
     namespace = 'riscore'
     if not key:  # Assuming we're invalidating the namespace.
         cache_ns_key(namespace, invalidate)
         return
     else:
         # Using cache_ns_key so each cache val is invalidated together.
         ns_key = cache_ns_key(namespace, invalidate)
         return '%s:%s' % (ns_key, key)
Exemple #6
0
def update_incompatible_appversions(data, **kw):
    """Updates the incompatible_versions table for this version."""
    log.info('Updating incompatible_versions for %s versions.' % len(data))

    addon_ids = set()

    for version_id in data:
        # This is here to handle both post_save and post_delete hooks.
        IncompatibleVersions.objects.filter(version=version_id).delete()

        try:
            version = Version.objects.get(pk=version_id)
        except Version.DoesNotExist:
            log.info('Version ID [%d] not found. Incompatible versions were '
                     'cleared.' % version_id)
            return

        addon_ids.add(version.addon_id)

        try:
            compat = CompatOverride.objects.get(addon=version.addon)
        except CompatOverride.DoesNotExist:
            log.info('Compat override for addon with version ID [%d] not '
                     'found. Incompatible versions were cleared.' % version_id)
            return

        app_ranges = []
        ranges = compat.collapsed_ranges()

        for range in ranges:
            if range.min == '0' and range.max == '*':
                # Wildcard range, add all app ranges
                app_ranges.extend(range.apps)
            else:
                # Since we can't rely on add-on version numbers, get the min
                # and max ID values and find versions whose ID is within those
                # ranges, being careful with wildcards.
                min_id = max_id = None

                if range.min == '0':
                    versions = (Version.objects.filter(
                        addon=version.addon_id).order_by('id').values_list(
                            'id', flat=True)[:1])
                    if versions:
                        min_id = versions[0]
                else:
                    try:
                        min_id = Version.objects.get(addon=version.addon_id,
                                                     version=range.min).id
                    except Version.DoesNotExist:
                        pass

                if range.max == '*':
                    versions = (Version.objects.filter(
                        addon=version.addon_id).order_by('-id').values_list(
                            'id', flat=True)[:1])
                    if versions:
                        max_id = versions[0]
                else:
                    try:
                        max_id = Version.objects.get(addon=version.addon_id,
                                                     version=range.max).id
                    except Version.DoesNotExist:
                        pass

                if min_id and max_id:
                    if min_id <= version.id <= max_id:
                        app_ranges.extend(range.apps)

        for app_range in app_ranges:
            IncompatibleVersions.objects.create(version=version,
                                                app=app_range.app.id,
                                                min_app_version=app_range.min,
                                                max_app_version=app_range.max)
            log.info(
                'Added incompatible version for version ID [%d]: '
                'app:%d, %s -> %s' %
                (version_id, app_range.app.id, app_range.min, app_range.max))

    # Increment namespace cache of compat versions.
    for addon_id in addon_ids:
        cache_ns_key('d2c-versions:%s' % addon_id, increment=True)
Exemple #7
0
def find_compatible_version(addon,
                            app_id,
                            app_version=None,
                            platform=None,
                            compat_mode='strict'):
    """Returns the newest compatible version (ordered by version id desc)
    for the given addon."""
    if not app_id:
        return None

    if platform:
        # We include platform_id=1 always in the SQL so we skip it here.
        platform = platform.lower()
        if platform != 'all' and platform in amo.PLATFORM_DICT:
            platform = amo.PLATFORM_DICT[platform].id
        else:
            platform = None

    log.debug(u'Checking compatibility for add-on ID:%s, APP:%s, V:%s, '
              u'OS:%s, Mode:%s' %
              (addon.id, app_id, app_version, platform, compat_mode))
    valid_file_statuses = ','.join(map(str, addon.valid_file_statuses))
    data = {
        'id': addon.id,
        'app_id': app_id,
        'platform': platform,
        'valid_file_statuses': valid_file_statuses,
        'channel': amo.RELEASE_CHANNEL_LISTED,
    }
    if app_version:
        data.update(version_int=version_int(app_version))
    else:
        # We can't perform the search queries for strict or normal without
        # an app version.
        compat_mode = 'ignore'

    ns_key = cache_ns_key('d2c-versions:%s' % addon.id)
    cache_key = '%s:%s:%s:%s:%s' % (ns_key, app_id, app_version, platform,
                                    compat_mode)
    version_id = cache.get(cache_key)
    if version_id is not None:
        log.debug(u'Found compatible version in cache: %s => %s' %
                  (cache_key, version_id))
        if version_id == 0:
            return None
        else:
            try:
                return Version.objects.get(pk=version_id)
            except Version.DoesNotExist:
                pass

    raw_sql = [
        """
        SELECT versions.*
        FROM versions
        INNER JOIN addons
            ON addons.id = versions.addon_id AND addons.id = %(id)s
        INNER JOIN applications_versions
            ON applications_versions.version_id = versions.id
        INNER JOIN appversions appmin
            ON appmin.id = applications_versions.min
            AND appmin.application_id = %(app_id)s
        INNER JOIN appversions appmax
            ON appmax.id = applications_versions.max
            AND appmax.application_id = %(app_id)s
        INNER JOIN files
            ON files.version_id = versions.id AND
               (files.platform_id = 1"""
    ]

    if platform:
        raw_sql.append(' OR files.platform_id = %(platform)s')

    raw_sql.append(') WHERE files.status IN (%(valid_file_statuses)s) ')

    raw_sql.append(' AND versions.channel = %(channel)s ')

    if app_version:
        raw_sql.append('AND appmin.version_int <= %(version_int)s ')

    if compat_mode == 'ignore':
        pass  # No further SQL modification required.

    elif compat_mode == 'normal':
        raw_sql.append("""AND
            CASE WHEN files.strict_compatibility = 1 OR
                      files.binary_components = 1
            THEN appmax.version_int >= %(version_int)s ELSE 1 END
        """)
        # Filter out versions that don't have the minimum maxVersion
        # requirement to qualify for default-to-compatible.
        d2c_max = amo.D2C_MAX_VERSIONS.get(app_id)
        if d2c_max:
            data['d2c_max_version'] = version_int(d2c_max)
            raw_sql.append("AND appmax.version_int >= %(d2c_max_version)s ")

        # Filter out versions found in compat overrides
        raw_sql.append("""AND
            NOT versions.id IN (
            SELECT version_id FROM incompatible_versions
            WHERE app_id=%(app_id)s AND
              (min_app_version='0' AND
                   max_app_version_int >= %(version_int)s) OR
              (min_app_version_int <= %(version_int)s AND
                   max_app_version='*') OR
              (min_app_version_int <= %(version_int)s AND
                   max_app_version_int >= %(version_int)s)) """)

    else:  # Not defined or 'strict'.
        raw_sql.append('AND appmax.version_int >= %(version_int)s ')

    raw_sql.append('ORDER BY versions.id DESC LIMIT 1;')

    version = Version.objects.raw(''.join(raw_sql) % data)
    if version:
        version = version[0]
        version_id = version.id
    else:
        version = None
        version_id = 0

    log.debug(u'Caching compat version %s => %s' % (cache_key, version_id))
    cache.set(cache_key, version_id, None)

    return version
 def test_no_preexisting_key_incr(self, epoch_mock):
     epoch_mock.return_value = 123456
     eq_(cache_ns_key(self.namespace, increment=True),
         '123456:ns:%s' % self.namespace)
Exemple #9
0
def find_compatible_version(addon, app_id, app_version=None, platform=None,
                            compat_mode='strict'):
    """Returns the newest compatible version (ordered by version id desc)
    for the given addon."""
    if not app_id:
        return None

    if platform:
        # We include platform_id=1 always in the SQL so we skip it here.
        platform = platform.lower()
        if platform != 'all' and platform in amo.PLATFORM_DICT:
            platform = amo.PLATFORM_DICT[platform].id
        else:
            platform = None

    log.debug(u'Checking compatibility for add-on ID:%s, APP:%s, V:%s, '
              u'OS:%s, Mode:%s' % (addon.id, app_id, app_version, platform,
                                   compat_mode))
    valid_file_statuses = ','.join(map(str, addon.valid_file_statuses))
    data = {
        'id': addon.id,
        'app_id': app_id,
        'platform': platform,
        'valid_file_statuses': valid_file_statuses,
        'channel': amo.RELEASE_CHANNEL_LISTED,
    }
    if app_version:
        data.update(version_int=version_int(app_version))
    else:
        # We can't perform the search queries for strict or normal without
        # an app version.
        compat_mode = 'ignore'

    ns_key = cache_ns_key('d2c-versions:%s' % addon.id)
    cache_key = '%s:%s:%s:%s:%s' % (ns_key, app_id, app_version, platform,
                                    compat_mode)
    version_id = cache.get(cache_key)
    if version_id is not None:
        log.debug(u'Found compatible version in cache: %s => %s' % (
                  cache_key, version_id))
        if version_id == 0:
            return None
        else:
            try:
                return Version.objects.get(pk=version_id)
            except Version.DoesNotExist:
                pass

    raw_sql = ["""
        SELECT versions.*
        FROM versions
        INNER JOIN addons
            ON addons.id = versions.addon_id AND addons.id = %(id)s
        INNER JOIN applications_versions
            ON applications_versions.version_id = versions.id
        INNER JOIN appversions appmin
            ON appmin.id = applications_versions.min
            AND appmin.application_id = %(app_id)s
        INNER JOIN appversions appmax
            ON appmax.id = applications_versions.max
            AND appmax.application_id = %(app_id)s
        INNER JOIN files
            ON files.version_id = versions.id AND
               (files.platform_id = 1"""]

    if platform:
        raw_sql.append(' OR files.platform_id = %(platform)s')

    raw_sql.append(') WHERE files.status IN (%(valid_file_statuses)s) ')

    raw_sql.append(' AND versions.channel = %(channel)s ')

    if app_version:
        raw_sql.append('AND appmin.version_int <= %(version_int)s ')

    if compat_mode == 'ignore':
        pass  # No further SQL modification required.

    elif compat_mode == 'normal':
        raw_sql.append("""AND
            CASE WHEN files.strict_compatibility = 1 OR
                      files.binary_components = 1
            THEN appmax.version_int >= %(version_int)s ELSE 1 END
        """)
        # Filter out versions that don't have the minimum maxVersion
        # requirement to qualify for default-to-compatible.
        d2c_max = amo.D2C_MAX_VERSIONS.get(app_id)
        if d2c_max:
            data['d2c_max_version'] = version_int(d2c_max)
            raw_sql.append(
                "AND appmax.version_int >= %(d2c_max_version)s ")

        # Filter out versions found in compat overrides
        raw_sql.append("""AND
            NOT versions.id IN (
            SELECT version_id FROM incompatible_versions
            WHERE app_id=%(app_id)s AND
              (min_app_version='0' AND
                   max_app_version_int >= %(version_int)s) OR
              (min_app_version_int <= %(version_int)s AND
                   max_app_version='*') OR
              (min_app_version_int <= %(version_int)s AND
                   max_app_version_int >= %(version_int)s)) """)

    else:  # Not defined or 'strict'.
        raw_sql.append('AND appmax.version_int >= %(version_int)s ')

    raw_sql.append('ORDER BY versions.id DESC LIMIT 1;')

    version = Version.objects.raw(''.join(raw_sql) % data)
    if version:
        version = version[0]
        version_id = version.id
    else:
        version = None
        version_id = 0

    log.debug(u'Caching compat version %s => %s' % (cache_key, version_id))
    cache.set(cache_key, version_id, None)

    return version
Exemple #10
0
def update_incompatible_appversions(data, **kw):
    """Updates the incompatible_versions table for this version."""
    log.info('Updating incompatible_versions for %s versions.' % len(data))

    addon_ids = set()

    for version_id in data:
        # This is here to handle both post_save and post_delete hooks.
        IncompatibleVersions.objects.filter(version=version_id).delete()

        try:
            version = Version.objects.get(pk=version_id)
        except Version.DoesNotExist:
            log.info('Version ID [%d] not found. Incompatible versions were '
                     'cleared.' % version_id)
            return

        addon_ids.add(version.addon_id)

        try:
            compat = CompatOverride.objects.get(addon=version.addon)
        except CompatOverride.DoesNotExist:
            log.info('Compat override for addon with version ID [%d] not '
                     'found. Incompatible versions were cleared.' % version_id)
            return

        app_ranges = []
        ranges = compat.collapsed_ranges()

        for range in ranges:
            if range.min == '0' and range.max == '*':
                # Wildcard range, add all app ranges
                app_ranges.extend(range.apps)
            else:
                # Since we can't rely on add-on version numbers, get the min
                # and max ID values and find versions whose ID is within those
                # ranges, being careful with wildcards.
                min_id = max_id = None

                if range.min == '0':
                    versions = (Version.objects.filter(addon=version.addon_id)
                                .order_by('id')
                                .values_list('id', flat=True)[:1])
                    if versions:
                        min_id = versions[0]
                else:
                    try:
                        min_id = Version.objects.get(addon=version.addon_id,
                                                     version=range.min).id
                    except Version.DoesNotExist:
                        pass

                if range.max == '*':
                    versions = (Version.objects.filter(addon=version.addon_id)
                                .order_by('-id')
                                .values_list('id', flat=True)[:1])
                    if versions:
                        max_id = versions[0]
                else:
                    try:
                        max_id = Version.objects.get(addon=version.addon_id,
                                                     version=range.max).id
                    except Version.DoesNotExist:
                        pass

                if min_id and max_id:
                    if min_id <= version.id <= max_id:
                        app_ranges.extend(range.apps)

        for app_range in app_ranges:
            IncompatibleVersions.objects.create(version=version,
                                                app=app_range.app.id,
                                                min_app_version=app_range.min,
                                                max_app_version=app_range.max)
            log.info('Added incompatible version for version ID [%d]: '
                     'app:%d, %s -> %s' % (version_id, app_range.app.id,
                                           app_range.min, app_range.max))

    # Increment namespace cache of compat versions.
    for addon_id in addon_ids:
        cache_ns_key('d2c-versions:%s' % addon_id, increment=True)
Exemple #11
0
 def test_no_preexisting_key_incr(self, epoch_mock):
     epoch_mock.return_value = 123456
     assert cache_ns_key(self.namespace,
                         increment=True) == ('123456:ns:%s' %
                                             self.namespace)
 def test_no_preexisting_key_incr(self, epoch_mock):
     epoch_mock.return_value = 1549383758398
     assert cache_ns_key(self.namespace, increment=True) == (
         '1549383758398:ns:%s' % self.namespace)
 def test_no_preexisting_key(self, epoch_mock):
     epoch_mock.return_value = 123456
     eq_(cache_ns_key(self.namespace), '123456:ns:%s' % self.namespace)
Exemple #14
0
 def test_no_preexisting_key(self, epoch_mock):
     epoch_mock.return_value = 1549383758398
     assert cache_ns_key(self.namespace) == ('1549383758398:ns:%s' %
                                             self.namespace)
 def test_no_preexisting_key(self, epoch_mock):
     epoch_mock.return_value = 123456
     assert cache_ns_key(self.namespace) == '123456:ns:%s' % self.namespace