示例#1
0
def gen_api_ladder(members=None,
                   team_size=1,
                   url='http://fake-url',
                   gd=True,
                   **kwargs):
    """ Generate api ladder object from members and other data. Can generalte legacy data or gamedata version. """
    if members is None:
        members = [gen_member(**kwargs)]

    if gd:
        return ApiLadder(gen_ladder_data(members, team_size=team_size), url)
    else:

        # Skipping races for now, since it is not needed for current set of tests.
        # races["favoriteRaceP%d" % (i + 1)] = Race.key_by_ids[m['race']].upper()

        return ApiLadder(
            {
                'ladderMembers': [{
                    "points": m['points'],
                    "previousRank": 0,
                    "wins": m['wins'],
                    "losses": m['losses'],
                    "highestRank": 0,
                    "joinTimestamp": to_unix(m['join_time']),
                    "character": {
                        "realm": m['realm'],
                        "profilePath": None,
                        "clanName": m['clan'],
                        "id": m['bid'],
                        "clanTag": m['tag'],
                        "displayName": m['name'],
                    }
                } for m in members]
            }, url)
示例#2
0
 def test_survives_missing_legacy_name(self):
     l = deepcopy(API_LADDER_1V1)
     del l['team'][0]['member'][0]['legacy_link']['name']
     al = ApiLadder(l)
     self.assertEqual([{
         'join_time': 1479018088,
         'bid': 6205328,
         'realm': 1,
         'name': '',
         'tag': 'Partha',
         'clan': 'boom boom long time',
         'points': 381,
         'mmr': 2136,
         'wins': 12,
         'losses': 24,
         'race': Race.PROTOSS,
     }], al.members_for_ranking(1))
示例#3
0
def gen_api_data(l_bid,
                 *p_bids,
                 mmq="HOTS_SOLO",
                 league="SILVER",
                 race="ZERG",
                 join_time=None,
                 join_times=None,
                 season="currentSeason",
                 team_size=None):
    """ Generate api data from blizzard. Returns <ladder_data,
    player_ladder_data>. Player ladder data will contain one team. """

    join_time = join_time or utcnow()
    join_times = join_times or [join_time]

    team_size = team_size or len(p_bids)

    names = [uniqueid(10) for _ in p_bids]

    pld = {
        "ladderId": l_bid,
        "league": league,
        "matchMakingQueue": mmq,
        "wins": 20,
        "losses": 22
    }

    ppds = [{
        "id": p_bid,
        "realm": 1,
        "displayName": name,
        "profilePath": "/profile/%d/1/%s/" % (p_bid, name)
    } for p_bid, name in zip(p_bids, names)]

    members = [{
        "character": {
            "id": p_bid,
            "realm": 1,
            "profilePath": "/profile/%d/1/%s/" % (p_bid, name)
        },
        "joinTimestamp": int(jt.strftime("%s")),
        "points": 102.2,
        "wins": 20,
        "losses": 22,
        "favoriteRaceP1": race
    } for p_bid, jt, name in zip(p_bids, itertools.cycle(join_times), names)]

    for member in members:
        if team_size > 1: member['favoriteRaceP2'] = race
        if team_size > 2: member['favoriteRaceP3'] = race
        if team_size > 3: member['favoriteRaceP4'] = race

    l = {"ladderMembers": members}
    p = {season: [{"ladder": [pld], "characters": ppds}]}

    # To simplify l_bid = p_bid.
    return ApiLadder(l, '/ladder/%d/' % l_bid), ApiPlayerLadders(
        p, '/profile/%d/' % l_bid)
示例#4
0
 def test_handles_empty(self):
     l = deepcopy(API_LADDER_1V1)
     del l['team']
     al = ApiLadder(l)
     self.assertEqual(None, al.first_join())
     self.assertEqual(None, al.last_join())
     self.assertEqual(0, al.member_count())
     self.assertEqual(None, al.max_points())
     self.assertEqual([], al.members_for_ranking(1))
示例#5
0
    def test_parsing_of_4v4_ladder_works(self):
        al = ApiLadder(API_LADDER_4V4)

        self.assertEqual(from_unix(1479927625), al.first_join())
        self.assertEqual(from_unix(1479927625), al.last_join())
        self.assertEqual(4, al.member_count())
        self.assertEqual(0, al.max_points())
        self.assertEqual([{
            'join_time': 1479927625,
            'bid': 897866,
            'realm': 1,
            'name': 'AaxeoiS',
            'tag': '',
            'clan': '',
            'race': Race.TERRAN,
            'points': 0,
            'mmr': 3965,
            'wins': 4,
            'losses': 1,
        }, {
            'join_time': 1479927625,
            'bid': 1048851,
            'realm': 1,
            'name': 'Hodn',
            'tag': '',
            'clan': '',
            'race': Race.RANDOM,
            'points': 0,
            'mmr': 3965,
            'wins': 4,
            'losses': 1,
        }, {
            'join_time': 1479927625,
            'bid': 1371993,
            'realm': 1,
            'name': 'Tsakal',
            'tag': 'GROF',
            'clan': 'Greek Operation Forces',
            'race': Race.ZERG,
            'points': 0,
            'mmr': 3965,
            'wins': 4,
            'losses': 1,
        }, {
            'join_time': 1479927625,
            'bid': 2972548,
            'realm': 1,
            'name': 'sakis',
            'tag': 'munaki',
            'clan': 'munaki',
            'race': Race.RANDOM,
            'points': 0,
            'mmr': 3965,
            'wins': 4,
            'losses': 1,
        }], al.members_for_ranking(4))
示例#6
0
    def test_skips_empty_member(self):
        l = deepcopy(API_LADDER_1V1)
        l['team'][0]['member'] = []
        al = ApiLadder(l)

        self.assertEqual(from_unix(1479018088), al.first_join())
        self.assertEqual(from_unix(1479018088), al.last_join())
        self.assertEqual(0, al.member_count())
        self.assertEqual(381, al.max_points())
        self.assertEqual([], al.members_for_ranking(1))
示例#7
0
    def test_parsing_of_1v1_ladder_works(self):
        al = ApiLadder(API_LADDER_1V1)

        self.assertEqual(from_unix(1479018088), al.first_join())
        self.assertEqual(from_unix(1479018088), al.last_join())
        self.assertEqual(1, al.member_count())
        self.assertEqual(381, al.max_points())
        self.assertEqual([{
            'join_time': 1479018088,
            'bid': 6205328,
            'realm': 1,
            'name': 'peimon',
            'tag': 'Partha',
            'clan': 'boom boom long time',
            'points': 381,
            'mmr': 2136,
            'wins': 12,
            'losses': 24,
            'race': Race.PROTOSS,
        }], al.members_for_ranking(1))
示例#8
0
    def test_parsing_of_1v1_legacy_ladder_works(self):
        al = ApiLadder(LEGACY_API_LADDER_1V1)

        self.assertEqual(from_unix(1468138637), al.first_join())
        self.assertEqual(from_unix(1468138637), al.last_join())
        self.assertEqual(1, al.member_count())
        self.assertEqual(101, al.max_points())
        self.assertEqual([{
            'join_time': 1468138637,
            'bid': 6061640,
            'realm': 1,
            'name': 'QueenOFpaiN',
            'tag': 'PIN',
            'clan': 'Pain',
            'race': Race.ZERG,
            'points': 101.0,
            'mmr': NO_MMR,
            'wins': 4,
            'losses': 1,
        }], al.members_for_ranking(1))
示例#9
0
def countinously_update(regions=None,
                        check_stop=None,
                        update_manager=None,
                        switch_hour=10):

    update_manager = update_manager or UpdateManager()

    ranking = Ranking.objects.order_by('-id').first()

    if ranking.status != Ranking.COMPLETE_WITH_DATA:
        raise Exception("ranking %d is not in a good state, clean up" %
                        ranking.id)

    season = ranking.season

    cpp = sc2.RankingData(get_db_name(), Enums.INFO)

    while not check_stop(throw=False):

        # Check if we want to switch to new season.

        current_season = Season.get_current_season()
        if current_season.id != season.id:

            if current_season.id != season.get_next().id:
                raise Exception(
                    "something is really wrong, current season is not next")

            if Ladder.objects.filter(season=current_season,
                                     strangeness=Ladder.GOOD).count() > 8:
                season = current_season
                logger.info(
                    "switching to rank new season %d multiple new season ladders was detected"
                    % season.id)

        # Do we want to create new ranking? We want to switch around switch_hour UTC every day but not if ranking is
        # too young. If too old, switch anyway.
        now = utcnow()

        if season.id != ranking.season_id:
            # Create new ranking based on new season.
            ranking = Ranking.objects.create(season=season,
                                             created=now,
                                             data_time=season.start_time(),
                                             min_data_time=season.start_time(),
                                             max_data_time=season.start_time(),
                                             status=Ranking.CREATED)
            logger.info("created new ranking %d based on new season %d" %
                        (ranking.id, season.id))

            cpp.clear_team_ranks()
            cpp.reconnect_db()
            update_manager.save_ranking(cpp, ranking, 0)

        elif ((ranking.created + timedelta(hours=48) < now or
               (ranking.created + timedelta(hours=12) < now
                and now.hour == switch_hour))
              and not ranking.season.near_start(now, days=4)):
            # Create a new ranking within the season.

            cpp.clear_team_ranks()
            cpp.reconnect_db()

            with transaction.atomic():
                new_ranking = Ranking.objects.create(
                    season=season,
                    created=now,
                    data_time=ranking.data_time,
                    min_data_time=ranking.min_data_time,
                    max_data_time=ranking.max_data_time,
                    status=Ranking.CREATED)
                # Copy all caches of old ranking to new ranking. Also remake the full ranking while doing so to get
                # rid of leave leaguers.

                logger.info(
                    "created new ranking %d basing it on copy of ranking %d, seaons %d"
                    % (new_ranking.id, ranking.id, season.id))

                count = ranking.sources.count()
                logger.info(
                    "copying %d cached ladders from ranking %d to ranking %d and adding them to ranking"
                    % (count, ranking.id, new_ranking.id))

                for i, lc in enumerate(ranking.sources.all(), start=1):
                    lc.pk = None
                    lc.created = utcnow()
                    lc.ladder = None
                    lc.ranking = ranking
                    lc.save()

                    new_ranking.sources.add(lc)

                    ladder = Ladder.objects.get(region=lc.region, bid=lc.bid)
                    team_size = Mode.team_size(ladder.mode)
                    stats = cpp.update_with_ladder(
                        ladder.id, lc.id, ladder.region, ladder.mode,
                        ladder.league, ladder.tier, ladder.version,
                        ladder.season_id, to_unix(lc.updated), team_size,
                        ApiLadder(lc.data,
                                  lc.url).members_for_ranking(team_size))

                    if i % 100 == 0:
                        logger.info(
                            "copied and added cache %d/%d, player cache size %d, team cache size %d"
                            % (i, count, stats['player_cache_size'],
                               stats['team_cache_size']))

            ranking = new_ranking
            update_manager.save_ranking(cpp, ranking, 0)
        else:
            logger.info("continuing with ranking %d, season %d" %
                        (ranking.id, season.id))
            cpp.reconnect_db()
            cpp.load(ranking.id)

        now = utcnow()
        until = now.replace(hour=switch_hour, minute=0, second=0)
        if until < now:
            until += timedelta(hours=24)

        update_manager.update_until(ranking=ranking,
                                    cpp=cpp,
                                    regions=regions,
                                    until=until,
                                    check_stop=check_stop)
示例#10
0
    def run(self, args, logger):
        logger.info(
            "NOTE: fetching needs to be turned off if repairing latest rank")

        ranking = Ranking.objects.get(pk=args.ranking_id)

        if ranking.status not in [Ranking.CREATED, Ranking.COMPLETE_WITH_DATA]:
            raise Exception("ranking with status %s can not be repaired" %
                            ranking.status)

        # If last in season use all available ladders, not only those connected to ranking.
        last_in_season = Ranking.objects.filter(
            season=ranking.season).order_by('-id').first()
        if last_in_season == ranking:
            cursor = connection.cursor()
            cursor.execute(
                "SELECT id FROM ("
                "  SELECT DISTINCT ON (c.bid, c.region) c.id, c.updated FROM cache c JOIN ladder l"
                "    ON c.bid = l.bid AND c.region = l.region"
                "    WHERE l.strangeness = %s AND l.season_id = %s"
                "    ORDER BY c.bid, c.region, c.updated DESC) s"
                " ORDER by updated", [Ladder.GOOD, ranking.season_id])
            cache_ids = [row[0] for row in cursor.fetchall()]
            cursor.execute(
                "UPDATE cache SET ranking_id = NULL WHERE ranking_id = %s",
                [ranking.id])
        else:
            cache_ids = [
                c['id']
                for c in ranking.sources.values('id').order_by('updated')
            ]

        cpp = sc2.RankingData(get_db_name(), Enums.INFO)

        count = len(cache_ids)
        for i, id_ in enumerate(cache_ids, start=1):
            cache = Cache.objects.get(id=id_)
            self.check_stop()
            try:
                ladder = Ladder.objects.get(season=ranking.season,
                                            region=cache.region,
                                            bid=cache.bid)
            except Ladder.DoesNotExist:
                raise Exception(
                    "ladder region %s, bid %s missing in ladder table" %
                    (cache.region, cache.bid))

            if cache.ranking is None and cache.ladder is None:
                cache.ranking = ranking
                cache.save()
            elif cache.ranking != ranking:
                logger.info("cache %s was not included in ranking copying" %
                            cache.id)
                cache.id = None
                cache.ladder = None
                cache.ranking = ranking
                cache.save()

            logger.info("adding cache %s, ladder %s, %d/%d" %
                        (cache.id, ladder.id, i, count))

            team_size = Mode.team_size(ladder.mode)
            cpp.update_with_ladder(
                ladder.id, cache.id, ladder.region, ladder.mode, ladder.league,
                ladder.tier, ladder.version, ladder.season_id,
                to_unix(cache.updated), team_size,
                ApiLadder(cache.data).members_for_ranking(team_size))

        ranking.set_data_time(ranking.season, cpp)
        ranking.save()
        self.check_stop()
        cpp.save_data(ranking.id, ranking.season_id, to_unix(utcnow()))
        self.check_stop()
        cpp.save_stats(ranking.id, to_unix(utcnow()))

        return 0
示例#11
0
 def test_name_is_truncated_to_12_chars(self):
     l = deepcopy(API_LADDER_1V1)
     l['team'][0]['member'][0]['legacy_link'][
         'name'] = '12345678901234567890#123'
     al = ApiLadder(l)
     self.assertEqual('123456789012', al.members_for_ranking(1)[0]['name'])
示例#12
0
    def test_parsing_of_4v4_legacy_ladder_works(self):
        al = ApiLadder(LEGACY_API_LADDER_4V4)

        self.assertEqual(from_unix(1478313972), al.first_join())
        self.assertEqual(from_unix(1478313972), al.last_join())
        self.assertEqual(4, al.member_count())
        self.assertEqual(0.0, al.max_points())
        self.assertEqual([
            {
                'join_time': 1478313972,
                'bid': 6539206,
                'realm': 1,
                'name': 'Maximus',
                'tag': '',
                'clan': '',
                'race': Race.PROTOSS,
                'points': 0.0,
                'mmr': NO_MMR,
                'wins': 0,
                'losses': 5,
            },
            {
                'join_time': 1478313972,
                'bid': 6714244,
                'realm': 1,
                'name': 'Herakles',
                'tag': '',
                'clan': '',
                'race': Race.TERRAN,
                'points': 0.0,
                'mmr': NO_MMR,
                'wins': 0,
                'losses': 5,
            },
            {
                'join_time': 1478313972,
                'bid': 6718054,
                'realm': 1,
                'name': 'Amazone',
                'tag': '',
                'clan': '',
                'race': Race.TERRAN,
                'points': 0.0,
                'mmr': NO_MMR,
                'wins': 0,
                'losses': 5,
            },
            {
                'join_time': 1478313972,
                'bid': 6742389,
                'realm': 1,
                'name': 'philipp',
                'tag': 'TAG',
                'clan': 'CLAN',
                'race': Race.ZERG,
                'points': 0.0,
                'mmr': NO_MMR,
                'wins': 0,
                'losses': 5,
            },
        ], al.members_for_ranking(4))
示例#13
0
 def test_converts_high_mmr_as_no_mmr(self):
     l = deepcopy(API_LADDER_1V1)
     l['team'][0]['rating'] = 500342
     al = ApiLadder(l)
     self.assertEqual(NO_MMR, al.members_for_ranking(1)[0]['mmr'])
    def run(self, args, logger):
        seasons = list(Season.objects.filter(pk__gte=args.ss_id, pk__lte=args.es_id))

        for region in args.regions:
            logger.info("processing region %s" % region)

            for ladder in Ladder.objects.filter(season__in=seasons, region=region, bid__gte=args.bid).order_by('bid'):

                self.check_stop()

                context = "ladder %d, region %s, bid %d, %s" %\
                          (ladder.id, Region.key_by_ids[region], ladder.bid, ladder.info())

                try:
                    lcs = ladder.cached_raw.filter(type=Cache.LADDER).order_by('id')
                    if len(lcs) != 1:
                        raise Exception("expected one ladder cache for ladder %d, found %s" %
                                        (ladder.id, [c.id for c in lcs]))
                    lc = lcs[0]
                    if lc.bid != ladder.bid or lc.region != ladder.region:
                        raise Exception("bid or region did not match lc on %s" % ladder.id)

                    al = ApiLadder(loads(lc.data), lc.url)

                    pcs = ladder.cached_raw.filter(type=Cache.PLAYER_LADDERS)
                    if len(pcs) > 1:
                        raise Exception("expected one player ladders cache for ladder %d, found %s" %
                                        (ladder.id, [c.id for c in pcs]))
                    pc = pcs[0] if pcs else None
                    if pc:
                        if pc.region != ladder.region:
                            raise Exception("region did not match pc on %s, %s" % ladder.id)
                        ap = ApiPlayerLadders(loads(pc.data), pc.url)
                    else:
                        ap = None

                    new = Ladder()

                    join_season, join_valid = get_season_based_on_join_times(al.first_join(), al.last_join())
                    if ap:
                        match = ap.refers(ladder.bid)
                        if not match:
                            logger.error("%s: failed match" % context)
                            continue

                        context += ", match %s" % match

                        new.season, valid = determine_season(fetch_time=lc.updated, match=match,
                                                             join_season=join_season, join_valid=join_valid)
                    else:
                        new.season, valid = join_season, join_valid
                        context += ", match None"

                    new.version, new.mode, new.league = get_version_mode_league(ladder.bid, new.season, al, ap)

                    new.strangeness = get_strangeness(lc.updated, al, ap)

                    for what in args.verify.split(','):
                        nv = getattr(new, what)
                        ov = getattr(ladder, what)
                        if nv != ov:
                            if new.strangeness in (Ladder.GOOD, Ladder.NOP):
                                log = logger.error
                            else:
                                log = logger.warning
                            log("%s: failed %s, old %s, new %s" % (context, what, ov, nv))
                            break
                    else:
                        logger.info("%s: success" % context)

                except Exception as e:
                    logger.error("%s: %s(\"%s\")" % (context, e.__class__.__name__, e))

        return 0