def test_rejects_invalid_events(app):
    setup_challenges(app)
    with app.app_context():
        db = get_db()

    redis_conn = redis.Redis.from_url(url=REDIS_URL)

    bus = ChallengeEventBus(redis_conn)
    with db.scoped_session() as session:
        mgr = ChallengeManager("test_challenge_1", DefaultUpdater())
        TEST_EVENT = "TEST_EVENT"
        bus.register_listener(TEST_EVENT, mgr)
        with bus.use_scoped_dispatch_queue():
            bus.dispatch(TEST_EVENT, None, 1)
            bus.dispatch(TEST_EVENT, 1, None)
            bus.dispatch(TEST_EVENT, 1, 1, 1)
        (count, did_error) = bus.process_events(session)
        assert count == 0
        assert did_error == False
def test_inactive_challenge(app):
    setup_challenges(app)
    with app.app_context():
        db = get_db()

    redis_conn = redis.Redis.from_url(url=REDIS_URL)

    bus = ChallengeEventBus(redis_conn)
    with db.scoped_session() as session:
        mgr = ChallengeManager("some_inactive_challenge", DefaultUpdater())
        TEST_EVENT = "TEST_EVENT"
        bus.register_listener(TEST_EVENT, mgr)
        with bus.use_scoped_dispatch_queue():
            bus.dispatch(TEST_EVENT, 100, 1, {})
        bus.process_events(session)
        state = mgr.get_user_challenge_state(session, ["1"])
        # We should not have any UserChallenges created for the
        # inactive challenge!!
        assert len(state) == 0
Example #3
0
def test_anon_listen(app):
    redis_conn = redis.Redis.from_url(url=REDIS_URL)
    bus = ChallengeEventBus(redis_conn)
    # Register events with the bus
    bus.register_listener(ChallengeEvent.track_listen,
                          listen_streak_challenge_manager)

    with app.app_context():
        db = get_db()

    with db.scoped_session() as session:
        setup_challenges(session)
        with bus.use_scoped_dispatch_queue():
            bus.dispatch(
                ChallengeEvent.track_listen,
                BLOCK_NUMBER,
                None,
                {"created_at": datetime.now()},
            )
        (num_processed, error) = bus.process_events(session)
        assert not error
        assert num_processed == 0
def test_in_memory_queue(app):
    setup_challenges(app)

    with app.app_context():
        db = get_db()

    redis_conn = redis.Redis.from_url(url=REDIS_URL)

    bus = ChallengeEventBus(redis_conn)
    with db.scoped_session() as session, bus.use_scoped_dispatch_queue():
        agg_challenge = ChallengeManager("test_challenge_3",
                                         AggregateUpdater())
        agg_challenge.process(session, "test_event", [])
        TEST_EVENT = "TEST_EVENT"

        bus.register_listener(
            TEST_EVENT, ChallengeManager("test_challenge_1", DefaultUpdater()))
        bus.register_listener(
            TEST_EVENT, ChallengeManager("test_challenge_2", DefaultUpdater()))
        # - Multiple events with the same user_id but diff specifiers get created
        bus.register_listener(TEST_EVENT, agg_challenge)
        bus.dispatch(TEST_EVENT, 100, 1, {"referred_id": 2})
        bus.dispatch(TEST_EVENT, 100, 1, {"referred_id": 3})
        bus.process_events(session)

        # no events should be processed because we haven't dispatched yet
        state = agg_challenge.get_user_challenge_state(session, ["1-2", "1-3"])
        assert len(state) == 0

    bus.process_events(session)
    state = agg_challenge.get_user_challenge_state(session, ["1-2", "1-3"])
    assert len(state) == 2
    # Also make sure the thing is incomplete
    res = get_challenges(1, False, session, bus)
    agg_chal = {c["challenge_id"]: c for c in res}["test_challenge_3"]
    assert agg_chal["is_complete"] == False

    redis_conn = redis.Redis.from_url(url=REDIS_URL)
Example #5
0
def enqueue_trending_challenges(db: SessionManager, redis: Redis,
                                challenge_bus: ChallengeEventBus,
                                date: datetime):
    logger.info(
        "calculate_trending_challenges.py | Start calculating trending challenges"
    )
    update_start = time.time()
    with db.scoped_session(
    ) as session, challenge_bus.use_scoped_dispatch_queue():

        latest_blocknumber = get_latest_blocknumber_via_redis(session, redis)
        if latest_blocknumber is None:
            logger.error(
                "calculate_trending_challenges.py | Unable to get latest block number"
            )
            return

        trending_track_versions = trending_strategy_factory.get_versions_for_type(
            TrendingType.TRACKS).keys()

        time_range = "week"
        for version in trending_track_versions:
            strategy = trending_strategy_factory.get_strategy(
                TrendingType.TRACKS, version)
            top_tracks = _get_trending_tracks_with_session(
                session, {"time": time_range}, strategy)
            top_tracks = top_tracks[:TRENDING_LIMIT]
            dispatch_trending_challenges(
                challenge_bus,
                ChallengeEvent.trending_track,
                latest_blocknumber,
                top_tracks,
                version,
                date,
                TrendingType.TRACKS,
            )

        # Cache underground trending
        underground_trending_versions = trending_strategy_factory.get_versions_for_type(
            TrendingType.UNDERGROUND_TRACKS).keys()
        for version in underground_trending_versions:
            strategy = trending_strategy_factory.get_strategy(
                TrendingType.UNDERGROUND_TRACKS, version)
            underground_args: GetUndergroundTrendingTrackcArgs = {
                "offset": 0,
                "limit": TRENDING_LIMIT,
            }
            top_tracks = _get_underground_trending_with_session(
                session, underground_args, strategy, False)

            dispatch_trending_challenges(
                challenge_bus,
                ChallengeEvent.trending_underground,
                latest_blocknumber,
                top_tracks,
                version,
                date,
                TrendingType.UNDERGROUND_TRACKS,
            )

        trending_playlist_versions = trending_strategy_factory.get_versions_for_type(
            TrendingType.PLAYLISTS).keys()
        for version in trending_playlist_versions:
            strategy = trending_strategy_factory.get_strategy(
                TrendingType.PLAYLISTS, version)
            playlists_args: GetTrendingPlaylistsArgs = {
                "limit": TRENDING_LIMIT,
                "offset": 0,
                "time": time_range,
            }
            trending_playlists = _get_trending_playlists_with_session(
                session, playlists_args, strategy, False)
            for idx, playlist in enumerate(trending_playlists):
                challenge_bus.dispatch(
                    ChallengeEvent.trending_playlist,
                    latest_blocknumber,
                    playlist["playlist_owner_id"],
                    {
                        "id": playlist["playlist_id"],
                        "user_id": playlist["playlist_owner_id"],
                        "rank": idx + 1,
                        "type": str(TrendingType.PLAYLISTS),
                        "version": str(version),
                        "week": date_to_week(date),
                    },
                )

    update_end = time.time()
    update_total = update_end - update_start
    logger.info(
        f"calculate_trending_challenges.py | Finished calculating trending in {update_total} seconds"
    )
def test_catches_exceptions_in_single_processor(app):
    """Ensure that if a single processor fails, the others still succeed"""
    with app.app_context():
        db = get_db()

    redis_conn = redis.Redis.from_url(url=REDIS_URL)

    bus = ChallengeEventBus(redis_conn)
    with db.scoped_session() as session:

        session.add_all([
            Challenge(
                id="test_challenge_1",
                type=ChallengeType.numeric,
                amount="5",
                step_count=3,
                active=True,
            ),
            Challenge(
                id="test_challenge_2",
                type=ChallengeType.numeric,
                amount="5",
                step_count=3,
                active=True,
            ),
        ])
        session.commit()

        correct_manager = ChallengeManager("test_challenge_1",
                                           DefaultUpdater())
        broken_manager = ChallengeManager("test_challenge_2", BrokenUpdater())
        TEST_EVENT = "TEST_EVENT"
        TEST_EVENT_2 = "TEST_EVENT_2"
        bus.register_listener(TEST_EVENT, correct_manager)
        bus.register_listener(TEST_EVENT_2, broken_manager)

        with bus.use_scoped_dispatch_queue():
            # dispatch the broken one first
            bus.dispatch(TEST_EVENT_2, 101, 1)
            bus.dispatch(TEST_EVENT, 101, 1)
        try:
            bus.process_events(session)
        except:
            # pylint: disable=W0707
            raise Exception("Shouldn't have propogated error!")
        challenge_1_state = correct_manager.get_user_challenge_state(
            session, ["1"])
        # Make sure that the 'correct_manager' still executes
        assert len(challenge_1_state) == 1
        assert challenge_1_state[0].current_step_count == 1
        # Make sure broken manager didn't do anything
        challenge_2_state = broken_manager.get_user_challenge_state(
            session, ["1"])
        assert len(challenge_2_state) == 0

        # Try the other order
        with bus.use_scoped_dispatch_queue():
            # dispatch the correct one first
            bus.dispatch(TEST_EVENT, 101, 1)
            bus.dispatch(TEST_EVENT_2, 101, 1)
        try:
            bus.process_events(session)
        except:
            # pylint: disable=W0707
            raise Exception("Shouldn't have propogated error!")
        challenge_1_state = correct_manager.get_user_challenge_state(
            session, ["1"])
        assert len(challenge_1_state) == 1
        assert challenge_1_state[0].current_step_count == 2
        # Make sure broken manager didn't do anything
        challenge_2_state = broken_manager.get_user_challenge_state(
            session, ["1"])
        assert len(challenge_2_state) == 0