def test_first_tip_challenge(app):
    redis_conn = redis.Redis.from_url(url=REDIS_URL)

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

    block = Block(blockhash="0x1", number=BLOCK_NUMBER)
    user = User(
        blockhash="0x1",
        blocknumber=BLOCK_NUMBER,
        txhash="xyz",
        user_id=1,
        is_current=True,
        handle="TestHandle",
        handle_lc="testhandle",
        wallet="0x1",
        is_creator=False,
        is_verified=False,
        name="test_name",
        created_at=datetime.now(),
        updated_at=datetime.now(),
    )

    with db.scoped_session() as session:
        bus = ChallengeEventBus(redis_conn)
        session.query(Challenge).filter(
            Challenge.id == "send-first-tip").update({
                "active":
                True,
                "starting_block":
                BLOCK_NUMBER
            })

        # Register events with the bus
        bus.register_listener(ChallengeEvent.send_tip,
                              send_first_tip_challenge_manager)

        session.add(block)
        session.flush()
        session.add(user)
        session.flush()

        bus.dispatch(
            ChallengeEvent.send_tip,
            BLOCK_NUMBER,
            1,  # user_id
            {},
        )

        bus.flush()
        bus.process_events(session)
        session.flush()

        state = send_first_tip_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]

        assert state.is_complete
Example #2
0
def test_referral_challenge(app):
    redis_conn = redis.Redis.from_url(url=REDIS_URL)

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

    block = Block(blockhash="0x1", number=BLOCK_NUMBER)
    referrer = User(
        blockhash="0x1",
        blocknumber=BLOCK_NUMBER,
        txhash="xyz",
        user_id=1,
        is_current=True,
        handle="Referrer",
        handle_lc="referrer",
        wallet="0x1",
        is_creator=False,
        is_verified=False,
        name="referrer_name",
        created_at=datetime.now(),
        updated_at=datetime.now(),
    )

    with db.scoped_session() as session:
        # Setup
        bus = ChallengeEventBus(redis_conn)
        bus.register_listener(ChallengeEvent.referred_signup,
                              referred_challenge_manager)
        bus.register_listener(ChallengeEvent.referral_signup,
                              referral_challenge_manager)
        bus.register_listener(ChallengeEvent.referral_signup,
                              verified_referral_challenge_manager)
        session.add(block)
        session.flush()
        session.add(referrer)
        session.flush()
        # set challenge as active for purposes of test
        session.query(Challenge).filter(
            or_(
                Challenge.id == "referred",
                Challenge.id == "referrals",
                Challenge.id == "ref-v",
            )).update({
                "active": True,
                "starting_block": BLOCK_NUMBER
            })

        # Test:
        # Ensure a single referral from single signup
        # despite many challenge events
        dispatch_new_user_signup(referrer.user_id, 2, session, bus)
        for _ in range(0, 4):
            bus.dispatch(
                ChallengeEvent.referral_signup,
                BLOCK_NUMBER,
                referrer.user_id,
                {"referred_user_id": 2},
            )
            bus.dispatch(ChallengeEvent.referred_signup, BLOCK_NUMBER, 2)
        bus.flush()
        bus.process_events(session)

        challenges = (session.query(UserChallenge).filter(
            UserChallenge.user_id == referrer.user_id).all())
        assert len(challenges) == 1

        # Test:
        # Multiple signups
        # - Referrer is capped at 5
        # - Referred can keep going
        dispatch_new_user_signup(referrer.user_id, 3, session, bus)
        dispatch_new_user_signup(referrer.user_id, 4, session, bus)
        dispatch_new_user_signup(referrer.user_id, 5, session, bus)
        dispatch_new_user_signup(referrer.user_id, 6, session, bus)
        dispatch_new_user_signup(referrer.user_id, 7, session, bus)
        dispatch_new_user_signup(referrer.user_id, 8, session, bus)
        dispatch_new_user_signup(referrer.user_id, 9, session, bus)
        dispatch_new_user_signup(referrer.user_id, 10, session, bus)
        dispatch_new_user_signup(referrer.user_id, 11, session, bus)
        bus.flush()
        bus.process_events(session)
        challenges = (session.query(UserChallenge).filter(
            UserChallenge.user_id == referrer.user_id,
            UserChallenge.challenge_id == "referrals",
            UserChallenge.is_complete == True,
        ).all())
        assert len(challenges) == 5
        challenges = (session.query(UserChallenge).filter(
            UserChallenge.challenge_id == "referred",
            UserChallenge.is_complete == True,
        ).all())
        assert len(challenges) == 10

        # Test:
        # Ensure there are no verified user referrals created yet

        challenges = (session.query(UserChallenge).filter(
            UserChallenge.user_id == referrer.user_id,
            UserChallenge.challenge_id == "ref-v",
            UserChallenge.is_complete == True,
        ).all())
        assert len(challenges) == 0

        # Test: verified users
        # - Ensure that verified user referrals aren't counted
        #   for referrer credit
        # - Ensure that a verified user challenge exists

        verified_user = User(
            blockhash="0x1",
            blocknumber=BLOCK_NUMBER,
            txhash="xyz",
            user_id=12,
            is_current=True,
            handle="VerifiedReferrer",
            handle_lc="verifiedreferrer",
            wallet="0x1",
            is_creator=False,
            is_verified=True,
            name="referrer_name",
            created_at=datetime.now(),
            updated_at=datetime.now(),
        )
        session.add(verified_user)
        session.flush()

        dispatch_new_user_signup(verified_user.user_id, 13, session, bus)
        bus.flush()
        bus.process_events(session)

        # Ensure no regular referral created
        challenges = (session.query(UserChallenge).filter(
            UserChallenge.user_id == verified_user.user_id,
            UserChallenge.challenge_id == "referrals",
            UserChallenge.is_complete == True,
        ).all())
        assert len(challenges) == 0

        # Ensure one verified referral created
        challenges = (session.query(UserChallenge).filter(
            UserChallenge.user_id == verified_user.user_id,
            UserChallenge.challenge_id == "ref-v",
            UserChallenge.is_complete == True,
        ).all())
        assert len(challenges) == 1

        # Test: verified max count
        #  - Ensure with > 5000 verified referrals, we cap at 5000
        #  - No regular referrals are made

        for i in range(5010):
            dispatch_new_user_signup(verified_user.user_id, 14 + i, session,
                                     bus)
            if i % 500 == 0:
                bus.flush()
                bus.process_events(session)

        bus.flush()
        bus.process_events(session)

        # Ensure 5000 verified referral created
        challenges = (session.query(UserChallenge).filter(
            UserChallenge.user_id == verified_user.user_id,
            UserChallenge.challenge_id == "ref-v",
            UserChallenge.is_complete == True,
        ).all())
        assert len(challenges) == 5000

        # Ensure no regular referral created
        challenges = (session.query(UserChallenge).filter(
            UserChallenge.user_id == verified_user.user_id,
            UserChallenge.challenge_id == "referrals",
            UserChallenge.is_complete == True,
        ).all())
        assert len(challenges) == 0
def test_aggregates(app):

    setup_challenges(app)

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

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

    with db.scoped_session() as session:
        bus = ChallengeEventBus(redis_conn)
        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.flush()
        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

        # - Multiple events with the same specifier get deduped
        bus.dispatch(TEST_EVENT, 100, 1, {"referred_id": 4})
        bus.dispatch(TEST_EVENT, 100, 1, {"referred_id": 4})
        bus.flush()
        bus.process_events(session)
        state = agg_challenge.get_user_challenge_state(session, ["1-4"])
        assert len(state) == 1

        # - If we've maxed the # of challenges, don't create any more
        bus.dispatch(TEST_EVENT, 100, 1, {"referred_id": 5})
        bus.dispatch(TEST_EVENT, 100, 1, {"referred_id": 6})
        bus.flush()
        bus.process_events(session)

        def get_user_challenges():
            return (session.query(UserChallenge).filter(
                UserChallenge.challenge_id == "test_challenge_3",
                UserChallenge.user_id == 1,
            ).all())

        assert len(get_user_challenges()) == 5
        bus.dispatch(TEST_EVENT, 100, 1, {"referred_id": 7})
        bus.flush()
        bus.process_events(session)
        assert len(get_user_challenges()) == 5

        # Test get_challenges
        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"] == True
        # Assert all user challenges have proper finishing block #
        user_challenges = get_user_challenges()
        for uc in user_challenges:
            assert uc.completed_blocknumber == 100
def test_profile_completion_challenge_with_playlists(app):

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

    # create user
    with app.app_context():
        db = get_db()

    block = Block(blockhash="0x1", number=BLOCK_NUMBER)
    user = User(
        blockhash="0x1",
        blocknumber=BLOCK_NUMBER,
        txhash="xyz",
        user_id=1,
        is_current=True,
        handle="TestHandle",
        handle_lc="testhandle",
        wallet="0x123",
        is_creator=False,
        is_verified=False,
        name="test_name",
        created_at=datetime.now(),
        updated_at=datetime.now(),
    )

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

        # set challenge as active for purposes of test
        session.query(Challenge).filter(
            Challenge.id == "profile-completion").update({
                "active":
                True,
                "starting_block":
                BLOCK_NUMBER
            })

        # Register events with the bus
        bus.register_listener(ChallengeEvent.profile_update,
                              profile_challenge_manager)
        bus.register_listener(ChallengeEvent.repost, profile_challenge_manager)
        bus.register_listener(ChallengeEvent.follow, profile_challenge_manager)
        bus.register_listener(ChallengeEvent.favorite,
                              profile_challenge_manager)

        session.add(block)
        session.flush()
        session.add(user)

        # Process dummy event just to get this thing initted
        bus.dispatch(ChallengeEvent.profile_update, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]

        # We should have completed a single step (name)
        assert state.current_step_count == 1 and not state.is_complete

        # Do a repost
        repost = Repost(
            blockhash="0x1",
            blocknumber=BLOCK_NUMBER,
            user_id=1,
            repost_item_id=1,
            repost_type=RepostType.playlist,
            is_current=True,
            is_delete=False,
            created_at=datetime.now(),
        )
        session.add(repost)
        session.flush()
        bus.dispatch(ChallengeEvent.repost, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]
        assert state.current_step_count == 2 and not state.is_complete

        # Do a save
        save = Save(
            blockhash="0x1",
            blocknumber=BLOCK_NUMBER,
            user_id=1,
            save_item_id=1,
            save_type=SaveType.playlist,
            is_current=True,
            is_delete=False,
            created_at=datetime.now(),
        )
        session.add(save)
        session.flush()
        bus.dispatch(ChallengeEvent.favorite, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        session.flush()
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]
        assert state.current_step_count == 3 and not state.is_complete

        # Do 1 follow, then 5 total follows
        follow = Follow(
            blockhash="0x1",
            blocknumber=BLOCK_NUMBER,
            is_current=True,
            is_delete=False,
            created_at=datetime.now(),
            follower_user_id=1,
            followee_user_id=2,
        )
        session.add(follow)
        session.flush()
        bus.dispatch(ChallengeEvent.follow, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        session.flush()
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]
        # Assert 1 follow didn't do anything
        assert state.current_step_count == 3 and not state.is_complete
        follows = [
            Follow(
                blockhash="0x1",
                blocknumber=BLOCK_NUMBER,
                is_current=True,
                is_delete=False,
                created_at=datetime.now(),
                follower_user_id=1,
                followee_user_id=3,
            ),
            Follow(
                blockhash="0x1",
                blocknumber=BLOCK_NUMBER,
                is_current=True,
                is_delete=False,
                created_at=datetime.now(),
                follower_user_id=1,
                followee_user_id=4,
            ),
            Follow(
                blockhash="0x1",
                blocknumber=BLOCK_NUMBER,
                is_current=True,
                is_delete=False,
                created_at=datetime.now(),
                follower_user_id=1,
                followee_user_id=5,
            ),
            Follow(
                blockhash="0x1",
                blocknumber=BLOCK_NUMBER,
                is_current=True,
                is_delete=False,
                created_at=datetime.now(),
                follower_user_id=1,
                followee_user_id=6,
            ),
        ]
        session.add_all(follows)
        session.flush()
        bus.dispatch(ChallengeEvent.follow, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]
        assert state.current_step_count == 4 and not state.is_complete

        # profile_picture
        session.query(User).filter(User.user_id == 1).update(
            {"profile_picture": "profilepictureurl"})
        session.flush()
        bus.dispatch(ChallengeEvent.profile_update, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]
        assert state.current_step_count == 5 and not state.is_complete

        # profile description
        session.query(User).filter(User.user_id == 1).update(
            {"bio": "profiledescription"})
        session.flush()
        bus.dispatch(ChallengeEvent.profile_update, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]
        assert state.current_step_count == 6 and not state.is_complete

        # Undo it, ensure that our count goes down
        session.query(User).filter(User.user_id == 1).update({"bio": None})
        session.flush()
        bus.dispatch(ChallengeEvent.profile_update, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]
        assert state.current_step_count == 5 and not state.is_complete

        # profile_cover_photo
        session.query(User).filter(User.user_id == 1).update({
            "bio":
            "profiledescription",
            "cover_photo":
            "test_cover_photo"
        })
        session.flush()
        bus.dispatch(ChallengeEvent.profile_update, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]
        assert state.current_step_count == 7 and state.is_complete == True

        # ensure that if we lose some data now that the thing is complete, we don't change the status of the challenge
        session.query(User).filter(User.user_id == 1).update(
            {"cover_photo": None})
        session.flush()
        bus.dispatch(ChallengeEvent.profile_update, BLOCK_NUMBER, 1)
        bus.flush()
        bus.process_events(session)
        state = profile_challenge_manager.get_user_challenge_state(
            session, ["1"])[0]
        assert state.current_step_count == 7 and state.is_complete == True
Example #5
0
def test_track_upload_challenge(app):

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

    # create user
    with app.app_context():
        db = get_db()

    today = date.today()
    block1 = Block(blockhash="0x1", number=1)
    block2 = Block(blockhash="0x2", number=30000000)
    block3 = Block(blockhash="0x3", number=30000001)
    user = User(
        blockhash="0x1",
        blocknumber=1,
        txhash="xyz",
        user_id=1,
        handle="TestHandle",
        handle_lc="testhandle",
        is_current=True,
        created_at=today - timedelta(days=100),
        updated_at=today - timedelta(days=100),
    )
    track1 = Track(
        blockhash="0x1",
        blocknumber=1,
        txhash="xyz",
        owner_id=1,
        track_id=1,
        route_id="1",
        track_segments=[],
        is_unlisted=False,
        is_current=True,
        is_delete=False,
        created_at=today - timedelta(days=100),
        updated_at=today - timedelta(days=100),
    )
    track2 = Track(
        blockhash="0x2",
        blocknumber=30000000,
        txhash="yzx",
        owner_id=1,
        track_id=2,
        route_id="2",
        track_segments=[],
        is_unlisted=False,
        is_current=True,
        is_delete=False,
        created_at=today - timedelta(days=1),
        updated_at=today - timedelta(days=1),
    )
    track3 = Track(
        blockhash="0x3",
        blocknumber=30000001,
        txhash="zxy",
        owner_id=1,
        track_id=3,
        route_id="3",
        track_segments=[],
        is_unlisted=False,
        is_current=True,
        is_delete=False,
        created_at=today,
        updated_at=today,
    )
    track4 = Track(
        blockhash="0x3",
        blocknumber=30000001,
        txhash="abc",
        owner_id=1,
        track_id=4,
        route_id="4",
        track_segments=[],
        is_unlisted=False,
        is_current=True,
        is_delete=False,
        created_at=today,
        updated_at=today,
    )

    unlisted_track = Track(
        blockhash="0x3",
        blocknumber=30000001,
        txhash="cba",
        owner_id=1,
        track_id=5,
        route_id="5",
        track_segments=[],
        is_unlisted=True,
        is_current=True,
        is_delete=False,
        created_at=today,
        updated_at=today,
    )

    stem = Track(
        blockhash="0x3",
        blocknumber=30000001,
        txhash="stem",
        owner_id=1,
        track_id=6,
        route_id="6",
        track_segments=[],
        is_unlisted=False,
        is_current=True,
        is_delete=False,
        created_at=today,
        updated_at=today,
        stem_of={"parent_track_id": 4, "category": "bass"},
    )

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

        # Register events with the bus
        bus.register_listener(
            ChallengeEvent.track_upload, track_upload_challenge_manager
        )

        # set challenge as active for purposes of test
        session.query(Challenge).filter(Challenge.id == "track-upload").update(
            {"active": True}
        )

        session.add(block1)
        session.add(block2)
        session.add(block3)
        session.flush()
        session.add(user)
        session.add(track1)

        # Process dummy event at block number before this challenge is added
        bus.dispatch(ChallengeEvent.track_upload, 1, 1)
        bus.flush()
        bus.process_events(session)
        user_challenges = track_upload_challenge_manager.get_user_challenge_state(
            session, ["1"]
        )

        # We should not have registered a count for this event
        assert not user_challenges

        # Process dummy event at block number when challenge is added
        session.add(track2)
        bus.dispatch(ChallengeEvent.track_upload, 30000000, 1)
        bus.flush()
        bus.process_events(session)
        user_challenge = track_upload_challenge_manager.get_user_challenge_state(
            session, ["1"]
        )[0]

        # We should have completed a single step (one track upload)
        assert user_challenge.current_step_count == 1
        assert not user_challenge.is_complete

        # Ensure unlisted tracks and stems are not counted
        session.add(unlisted_track)
        bus.dispatch(ChallengeEvent.track_upload, 30000001, 1)
        session.add(stem)
        bus.dispatch(ChallengeEvent.track_upload, 30000001, 1)
        bus.flush()
        bus.process_events(session)
        user_challenge = track_upload_challenge_manager.get_user_challenge_state(
            session, ["1"]
        )[0]

        # Ensure stem is not counted

        assert user_challenge.current_step_count == 1

        # Process two more dummy events to reach the step count (i.e. 3) for completion
        session.add(track3)
        bus.dispatch(ChallengeEvent.track_upload, 30000001, 1)
        session.add(track4)
        bus.dispatch(ChallengeEvent.track_upload, 30000001, 1)
        bus.flush()
        bus.process_events(session)
        user_challenge = track_upload_challenge_manager.get_user_challenge_state(
            session, ["1"]
        )[0]

        # We should have completed the challenge
        assert user_challenge.current_step_count == 3
        assert user_challenge.is_complete

        # ensure that if we lose some data now that the thing is complete, we don't change the status of the challenge
        session.query(Track).filter(Track.owner_id == user.user_id).update(
            {"is_delete": True}
        )
        session.flush()
        bus.dispatch(ChallengeEvent.track_upload, 3, 1)
        bus.flush()
        bus.process_events(session)
        user_challenge = track_upload_challenge_manager.get_user_challenge_state(
            session, ["1"]
        )[0]

        # The challenge should still be completed
        assert user_challenge.current_step_count == 3
        assert user_challenge.is_complete