Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Publish onboarding events #1147

Merged
merged 4 commits into from
Feb 11, 2025

Conversation

spalmurray-codecov
Copy link
Contributor

Publishes Amplitude events for App Installed, User Created, and User Logged in.

Closes codecov/engineering-team#3179

Copy link

codecov bot commented Feb 10, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.04%. Comparing base (d39b6b1) to head (b16b26a).
Report is 3 commits behind head on main.

Changes have been made to critical files, which contain lines commonly executed in production. Learn more

✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1147   +/-   ##
=======================================
  Coverage   96.03%   96.04%           
=======================================
  Files         837      837           
  Lines       19769    19781   +12     
=======================================
+ Hits        18986    18998   +12     
  Misses        783      783           
Flag Coverage Δ
unit 95.92% <100.00%> (+<0.01%) ⬆️
unit-latest-uploader 95.92% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@codecov-staging
Copy link

codecov-staging bot commented Feb 10, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@codecov-qa
Copy link

codecov-qa bot commented Feb 10, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 95.92%. Comparing base (d39b6b1) to head (b16b26a).
Report is 3 commits behind head on main.

✅ All tests successful. No failed tests found.

Copy link
Contributor

github-actions bot commented Feb 10, 2025

✅ All tests successful. No failed tests were found.

📣 Thoughts on this report? Let Codecov know! | Powered by Codecov

Copy link

codecov-public-qa bot commented Feb 10, 2025

❌ 2 Tests Failed:

Tests completed Failed Passed Skipped
2738 2 2736 6
View the top 2 failed tests by shortest run time
codecov_auth/tests/unit/views/test_base.py::LoginMixinTests::test_get_or_create_calls_amplitude_user_logged_in_when_owner_not_created
Stack Traces | 0.016s run time
self = <MagicMock name='publish' id='140710405411504'>
calls = [call('User Logged in', {'user_ownerid': 16}), call('set_orgs', {'user_ownerid': 16, 'org_ids': [1, 2]})]
any_order = False

    def assert_has_calls(self, calls, any_order=False):
        """assert the mock has been called with the specified calls.
        The `mock_calls` list is checked for the calls.
    
        If `any_order` is False (the default) then the calls must be
        sequential. There can be extra calls before or after the
        specified calls.
    
        If `any_order` is True then the calls can be in any order, but
        they must all appear in `mock_calls`."""
        expected = [self._call_matcher(c) for c in calls]
        cause = next((e for e in expected if isinstance(e, Exception)), None)
        all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
        if not any_order:
            if expected not in all_calls:
                if cause is None:
                    problem = 'Calls not found.'
                else:
                    problem = ('Error processing expected calls.\n'
                               'Errors: {}').format(
                                   [e if isinstance(e, Exception) else None
                                    for e in expected])
>               raise AssertionError(
                    f'{problem}\n'
                    f'Expected: {_CallList(calls)}'
                    f'{self._calls_repr(prefix="  Actual").rstrip(".")}'
                ) from cause
E               AssertionError: Calls not found.
E               Expected: [call('User Logged in', {'user_ownerid': 16}),
E                call('set_orgs', {'user_ownerid': 16, 'org_ids': [1, 2]})]
E                 Actual: [call('User Logged in', {'user_ownerid': 1585}),
E                call('set_orgs', {'user_ownerid': 1585, 'org_ids': [1, 2]})]

.../local/lib/python3.12/unittest/mock.py:986: AssertionError

During handling of the above exception, another exception occurred:

self = <codecov_auth.tests.unit.views.test_base.LoginMixinTests testMethod=test_get_or_create_calls_amplitude_user_logged_in_when_owner_not_created>
amplitude_publish_mock = <MagicMock name='publish' id='140710405411504'>

    @patch("shared.events.amplitude.AmplitudeEventPublisher.publish")
    def test_get_or_create_calls_amplitude_user_logged_in_when_owner_not_created(
        self, amplitude_publish_mock
    ):
        owner = OwnerFactory(service_id=89, service="github", organizations=[1, 2])
        self.mixin_instance._get_or_create_owner(
            {
                "user": {
                    "id": owner.service_id,
                    "key": "02or0sa",
                    "login": owner.username,
                },
                "has_private_access": owner.private_access,
            },
            self.request,
        )
    
>       amplitude_publish_mock.assert_has_calls(
            [
                call("User Logged in", {"user_ownerid": 16}),
                call("set_orgs", {"user_ownerid": 16, "org_ids": [1, 2]}),
            ]
        )
E       AssertionError: Calls not found.
E       Expected: [call('User Logged in', {'user_ownerid': 16}),
E        call('set_orgs', {'user_ownerid': 16, 'org_ids': [1, 2]})]
E         Actual: [call('User Logged in', {'user_ownerid': 1585}),
E        call('set_orgs', {'user_ownerid': 1585, 'org_ids': [1, 2]})]
E       
E       pytest introspection follows:
E       
E       Args:
E       assert ('User Logged...nerid': 1585}) == ('User Logged...ownerid': 16})
E         
E         At index 1 diff: {'user_ownerid': 1585} != {'user_ownerid': 16}
E         Use -v to get more diff
E       Args:
E       assert ('set_orgs', ...nerid': 1585}) == ('set_orgs', ...ownerid': 16})
E         
E         At index 1 diff: {'user_ownerid': 1585, 'org_ids': [1, 2]} != {'user_ownerid': 16, 'org_ids': [1, 2]}
E         Use -v to get more diff

.../unit/views/test_base.py:231: AssertionError
codecov_auth/tests/unit/views/test_base.py::LoginMixinTests::test_get_or_create_calls_amplitude_user_created_when_owner_created
Stack Traces | 0.018s run time
self = <MagicMock name='publish' id='140711171717456'>
calls = [call('User Created', {'user_ownerid': 15}), call('set_orgs', {'user_ownerid': 15, 'org_ids': []})]
any_order = False

    def assert_has_calls(self, calls, any_order=False):
        """assert the mock has been called with the specified calls.
        The `mock_calls` list is checked for the calls.
    
        If `any_order` is False (the default) then the calls must be
        sequential. There can be extra calls before or after the
        specified calls.
    
        If `any_order` is True then the calls can be in any order, but
        they must all appear in `mock_calls`."""
        expected = [self._call_matcher(c) for c in calls]
        cause = next((e for e in expected if isinstance(e, Exception)), None)
        all_calls = _CallList(self._call_matcher(c) for c in self.mock_calls)
        if not any_order:
            if expected not in all_calls:
                if cause is None:
                    problem = 'Calls not found.'
                else:
                    problem = ('Error processing expected calls.\n'
                               'Errors: {}').format(
                                   [e if isinstance(e, Exception) else None
                                    for e in expected])
>               raise AssertionError(
                    f'{problem}\n'
                    f'Expected: {_CallList(calls)}'
                    f'{self._calls_repr(prefix="  Actual").rstrip(".")}'
                ) from cause
E               AssertionError: Calls not found.
E               Expected: [call('User Created', {'user_ownerid': 15}),
E                call('set_orgs', {'user_ownerid': 15, 'org_ids': []})]
E                 Actual: [call('User Created', {'user_ownerid': 1584}),
E                call('set_orgs', {'user_ownerid': 1584, 'org_ids': []})]

.../local/lib/python3.12/unittest/mock.py:986: AssertionError

During handling of the above exception, another exception occurred:

self = <codecov_auth.tests.unit.views.test_base.LoginMixinTests testMethod=test_get_or_create_calls_amplitude_user_created_when_owner_created>
amplitude_publish_mock = <MagicMock name='publish' id='140711171717456'>

    @patch("shared.events.amplitude.AmplitudeEventPublisher.publish")
    def test_get_or_create_calls_amplitude_user_created_when_owner_created(
        self, amplitude_publish_mock
    ):
        self.mixin_instance._get_or_create_owner(
            {
                "user": {"id": 12345, "key": "4567", "login": "testuser"},
                "has_private_access": False,
            },
            self.request,
        )
    
>       amplitude_publish_mock.assert_has_calls(
            [
                call("User Created", {"user_ownerid": 15}),
                call("set_orgs", {"user_ownerid": 15, "org_ids": []}),
            ]
        )
E       AssertionError: Calls not found.
E       Expected: [call('User Created', {'user_ownerid': 15}),
E        call('set_orgs', {'user_ownerid': 15, 'org_ids': []})]
E         Actual: [call('User Created', {'user_ownerid': 1584}),
E        call('set_orgs', {'user_ownerid': 1584, 'org_ids': []})]
E       
E       pytest introspection follows:
E       
E       Args:
E       assert ('User Create...nerid': 1584}) == ('User Create...ownerid': 15})
E         
E         At index 1 diff: {'user_ownerid': 1584} != {'user_ownerid': 15}
E         Use -v to get more diff
E       Args:
E       assert ('set_orgs', ...nerid': 1584}) == ('set_orgs', ...ownerid': 15})
E         
E         At index 1 diff: {'user_ownerid': 1584, 'org_ids': []} != {'user_ownerid': 15, 'org_ids': []}
E         Use -v to get more diff

.../unit/views/test_base.py:189: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

@spalmurray-codecov spalmurray-codecov force-pushed the spalmurray/amplitude-onboarding branch from dbd2986 to 2106b3d Compare February 10, 2025 20:32
@spalmurray-codecov spalmurray-codecov marked this pull request as ready for review February 10, 2025 20:32
"App Installed",
{
"user_ownerid": installer.ownerid
if installer is not None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this check fails if installer is none because we're already doing the access on line 523. I don't really know how python handles it tbh but this example on a python sandbox gave me an error

stuff = {
    "ownerid": 1
}
stuff2 = stuff3["ownerid"] if stuff3 is not None else stuff["ownerid"]
print(stuff2)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It think it's okay. installer will be defined but possibly None.

>>> stuff = { "ownerid": 1 }
>>> stuff2 = stuff3["ownerid"] if stuff3 is not None else stuff["ownerid"]
Traceback (most recent call last):
  File "<python-input-1>", line 1, in <module>
    stuff2 = stuff3["ownerid"] if stuff3 is not None else stuff["ownerid"]
                                  ^^^^^^
NameError: name 'stuff3' is not defined. Did you mean: 'stuff'?
>>> stuff3 = None
>>> stuff2 = stuff3["ownerid"] if stuff3 is not None else stuff["ownerid"]
>>> stuff2
1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh yeah okay I missed that part, sounds good

Copy link
Contributor

@ajay-sentry ajay-sentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@spalmurray-codecov spalmurray-codecov added this pull request to the merge queue Feb 11, 2025
Merged via the queue into main with commit eaf517c Feb 11, 2025
18 of 19 checks passed
@spalmurray-codecov spalmurray-codecov deleted the spalmurray/amplitude-onboarding branch February 11, 2025 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[API] Track onboarding events
3 participants