Skip to content
This repository was archived by the owner on Jun 13, 2025. It is now read-only.

Commit 1bfc6d8

Browse files
committed
all tests passing now, fixed a couple small logic bugs too
1 parent 42488fb commit 1bfc6d8

File tree

15 files changed

+277
-75
lines changed

15 files changed

+277
-75
lines changed

api/internal/owner/serializers.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ def validate(self, plan: Dict[str, Any]) -> Dict[str, Any]:
148148
)
149149

150150
active_plans = list(
151-
Plan.objects.filter(paid_plan=True, is_active=True).values_list(
152-
"name", "tier"
153-
)
151+
Plan.objects.select_related("tier").filter(paid_plan=True, is_active=True)
154152
)
155-
active_plan_names = {name for name, _ in active_plans}
153+
active_plan_names = {plan.name for plan in active_plans}
156154
team_tier_plans = {
157-
name for name, tier in active_plans if tier == TierName.TEAM.value
155+
plan.name
156+
for plan in active_plans
157+
if plan.tier.tier_name == TierName.TEAM.value
158158
}
159159

160160
# Validate quantity here because we need access to whole plan object
@@ -347,7 +347,7 @@ def update(self, instance: Owner, validated_data: Dict[str, Any]) -> object:
347347

348348
sentry_plans = Plan.objects.filter(
349349
tier__tier_name=TierName.SENTRY.value, is_active=True
350-
)
350+
).values_list("name", flat=True)
351351

352352
if desired_plan["value"] in sentry_plans:
353353
current_owner = self.context["view"].request.current_owner
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
interactions:
2+
- request:
3+
body: billing_address_collection=required&payment_method_collection=if_required&client_reference_id=65&success_url=http%3A%2F%2Flocalhost%3A3000%2Fplan%2Fgh%2Fjustin47%3Fsuccess&cancel_url=http%3A%2F%2Flocalhost%3A3000%2Fplan%2Fgh%2Fjustin47%3Fcancel&customer=1000&mode=subscription&line_items[0][price]=price_1OCM0gGlVGuVgOrkWDYEBtSL&line_items[0][quantity]=11&subscription_data[metadata][service]=github&subscription_data[metadata][obo_organization]=65&subscription_data[metadata][username]=justin47&subscription_data[metadata][obo_name]=Kelly+Williams&subscription_data[metadata][obo_email]=christopher27%40lopez-welch.com&subscription_data[metadata][obo]=65&tax_id_collection[enabled]=True&customer_update[name]=auto&customer_update[address]=auto
4+
headers:
5+
Accept:
6+
- '*/*'
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
Content-Length:
12+
- '744'
13+
Content-Type:
14+
- application/x-www-form-urlencoded
15+
Idempotency-Key:
16+
- 2e7e12e1-9051-4766-b947-1abe985b5e98
17+
Stripe-Version:
18+
- 2024-12-18.acacia
19+
User-Agent:
20+
- Stripe/v1 PythonBindings/11.4.1
21+
X-Stripe-Client-User-Agent:
22+
- '{"bindings_version": "11.4.1", "lang": "python", "publisher": "stripe", "httplib":
23+
"requests", "lang_version": "3.12.8", "platform": "Linux-6.10.14-linuxkit-aarch64-with-glibc2.36",
24+
"uname": "Linux 35c9e7c77efc 6.10.14-linuxkit #1 SMP Fri Nov 29 17:22:03 UTC
25+
2024 aarch64 "}'
26+
method: POST
27+
uri: https://api.stripe.com/v1/checkout/sessions
28+
response:
29+
body:
30+
string: "{\n \"error\": {\n \"code\": \"resource_missing\",\n \"doc_url\":
31+
\"https://stripe.com/docs/error-codes/resource-missing\",\n \"message\":
32+
\"No such customer: '1000'\",\n \"param\": \"customer\",\n \"request_log_url\":
33+
\"https://dashboard.stripe.com/test/logs/req_oevRZUbMiaT1kM?t=1737668618\",\n
34+
\ \"type\": \"invalid_request_error\"\n }\n}\n"
35+
headers:
36+
Access-Control-Allow-Credentials:
37+
- 'true'
38+
Access-Control-Allow-Methods:
39+
- GET, HEAD, PUT, PATCH, POST, DELETE
40+
Access-Control-Allow-Origin:
41+
- '*'
42+
Access-Control-Expose-Headers:
43+
- Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required,
44+
X-Stripe-Privileged-Session-Required
45+
Access-Control-Max-Age:
46+
- '300'
47+
Cache-Control:
48+
- no-cache, no-store
49+
Connection:
50+
- keep-alive
51+
Content-Length:
52+
- '325'
53+
Content-Security-Policy:
54+
- base-uri 'none'; default-src 'none'; form-action 'none'; frame-ancestors 'none';
55+
img-src 'self'; script-src 'self' 'report-sample'; style-src 'self'; upgrade-insecure-requests;
56+
report-uri https://q.stripe.com/csp-violation?q=ieXMYrsoTw4hsNfwL6RhDPN6zQnVwnAAc0QsFb8i8xtl4N7V94VZzDmgDhKzWxW8mHRRg08-d5GW6oHr
57+
Content-Type:
58+
- application/json
59+
Cross-Origin-Opener-Policy-Report-Only:
60+
- same-origin; report-to="coop"
61+
Date:
62+
- Thu, 23 Jan 2025 21:43:38 GMT
63+
Idempotency-Key:
64+
- 2e7e12e1-9051-4766-b947-1abe985b5e98
65+
Original-Request:
66+
- req_oevRZUbMiaT1kM
67+
Report-To:
68+
- '{"group":"coop","max_age":8640,"endpoints":[{"url":"https://q.stripe.com/coop-report"}],"include_subdomains":true}'
69+
Reporting-Endpoints:
70+
- coop="https://q.stripe.com/coop-report"
71+
Request-Id:
72+
- req_oevRZUbMiaT1kM
73+
Server:
74+
- nginx
75+
Strict-Transport-Security:
76+
- max-age=63072000; includeSubDomains; preload
77+
Stripe-Version:
78+
- 2024-12-18.acacia
79+
Vary:
80+
- Origin
81+
X-Content-Type-Options:
82+
- nosniff
83+
X-Stripe-Priority-Routing-Enabled:
84+
- 'true'
85+
X-Stripe-Routing-Context-Priority-Tier:
86+
- api-testmode
87+
X-Wc:
88+
- AB
89+
status:
90+
code: 400
91+
message: Bad Request
92+
version: 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
interactions:
2+
- request:
3+
body: billing_address_collection=required&payment_method_collection=if_required&client_reference_id=93&success_url=http%3A%2F%2Flocalhost%3A3000%2Fplan%2Fgh%2Fjocelyn62%3Fsuccess&cancel_url=http%3A%2F%2Flocalhost%3A3000%2Fplan%2Fgh%2Fjocelyn62%3Fcancel&customer=1000&mode=subscription&line_items[0][price]=price_1OCM0gGlVGuVgOrkWDYEBtSL&line_items[0][quantity]=11&subscription_data[metadata][service]=github&subscription_data[metadata][obo_organization]=93&subscription_data[metadata][username]=jocelyn62&subscription_data[metadata][obo_name]=Crystal+Schmitt&subscription_data[metadata][obo_email]=smithamanda%40flowers.biz&subscription_data[metadata][obo]=93&tax_id_collection[enabled]=True&customer_update[name]=auto&customer_update[address]=auto
4+
headers:
5+
Accept:
6+
- '*/*'
7+
Accept-Encoding:
8+
- gzip, deflate
9+
Connection:
10+
- keep-alive
11+
Content-Length:
12+
- '742'
13+
Content-Type:
14+
- application/x-www-form-urlencoded
15+
Idempotency-Key:
16+
- 26000f5a-feb8-4647-ac57-32a5e5ff8729
17+
Stripe-Version:
18+
- 2024-12-18.acacia
19+
User-Agent:
20+
- Stripe/v1 PythonBindings/11.4.1
21+
X-Stripe-Client-Telemetry:
22+
- '{"last_request_metrics": {"request_id": "req_AaY8IvHbbSDcvz", "request_duration_ms":
23+
2}}'
24+
X-Stripe-Client-User-Agent:
25+
- '{"bindings_version": "11.4.1", "lang": "python", "publisher": "stripe", "httplib":
26+
"requests", "lang_version": "3.12.8", "platform": "Linux-6.10.14-linuxkit-aarch64-with-glibc2.36",
27+
"uname": "Linux 35c9e7c77efc 6.10.14-linuxkit #1 SMP Fri Nov 29 17:22:03 UTC
28+
2024 aarch64 "}'
29+
method: POST
30+
uri: https://api.stripe.com/v1/checkout/sessions
31+
response:
32+
body:
33+
string: "{\n \"error\": {\n \"code\": \"resource_missing\",\n \"doc_url\":
34+
\"https://stripe.com/docs/error-codes/resource-missing\",\n \"message\":
35+
\"No such customer: '1000'\",\n \"param\": \"customer\",\n \"request_log_url\":
36+
\"https://dashboard.stripe.com/test/logs/req_k8lY68XdxWIFHo?t=1737668619\",\n
37+
\ \"type\": \"invalid_request_error\"\n }\n}\n"
38+
headers:
39+
Access-Control-Allow-Credentials:
40+
- 'true'
41+
Access-Control-Allow-Methods:
42+
- GET, HEAD, PUT, PATCH, POST, DELETE
43+
Access-Control-Allow-Origin:
44+
- '*'
45+
Access-Control-Expose-Headers:
46+
- Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required,
47+
X-Stripe-Privileged-Session-Required
48+
Access-Control-Max-Age:
49+
- '300'
50+
Cache-Control:
51+
- no-cache, no-store
52+
Connection:
53+
- keep-alive
54+
Content-Length:
55+
- '325'
56+
Content-Security-Policy:
57+
- base-uri 'none'; default-src 'none'; form-action 'none'; frame-ancestors 'none';
58+
img-src 'self'; script-src 'self' 'report-sample'; style-src 'self'; upgrade-insecure-requests;
59+
report-uri https://q.stripe.com/csp-violation?q=1vgSiZ6UPd0qoBXo1Mjsk02GXFGP3M7PXsjua2jiowWQKm8jByxTHbhTeRirsQsrZ7jscQLjXtdCc_sh
60+
Content-Type:
61+
- application/json
62+
Cross-Origin-Opener-Policy-Report-Only:
63+
- same-origin; report-to="coop"
64+
Date:
65+
- Thu, 23 Jan 2025 21:43:39 GMT
66+
Idempotency-Key:
67+
- 26000f5a-feb8-4647-ac57-32a5e5ff8729
68+
Original-Request:
69+
- req_k8lY68XdxWIFHo
70+
Report-To:
71+
- '{"group":"coop","max_age":8640,"endpoints":[{"url":"https://q.stripe.com/coop-report"}],"include_subdomains":true}'
72+
Reporting-Endpoints:
73+
- coop="https://q.stripe.com/coop-report"
74+
Request-Id:
75+
- req_k8lY68XdxWIFHo
76+
Server:
77+
- nginx
78+
Strict-Transport-Security:
79+
- max-age=63072000; includeSubDomains; preload
80+
Stripe-Version:
81+
- 2024-12-18.acacia
82+
Vary:
83+
- Origin
84+
X-Content-Type-Options:
85+
- nosniff
86+
X-Stripe-Priority-Routing-Enabled:
87+
- 'true'
88+
X-Stripe-Routing-Context-Priority-Tier:
89+
- api-testmode
90+
X-Wc:
91+
- AB
92+
status:
93+
code: 400
94+
message: Bad Request
95+
version: 1

api/internal/tests/views/test_account_viewset.py

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@
1212
AccountFactory,
1313
InvoiceBillingFactory,
1414
OwnerFactory,
15-
PlanFactory,
16-
TierFactory,
1715
UserFactory,
1816
)
19-
from shared.plan.constants import PlanName, TierName, TrialStatus
17+
from shared.plan.constants import PlanName, TrialStatus
2018
from stripe import StripeError
2119

2220
from api.internal.tests.test_utils import GetAdminProviderAdapter
21+
from billing.helpers import mock_all_plans_and_tiers
2322
from codecov_auth.models import Service
2423
from utils.test_utils import APIClient
2524

@@ -93,6 +92,11 @@ def _update(self, kwargs, data):
9392
def _destroy(self, kwargs):
9493
return self.client.delete(reverse("account_details-detail", kwargs=kwargs))
9594

95+
@classmethod
96+
def setUpClass(cls):
97+
super().setUpClass()
98+
mock_all_plans_and_tiers()
99+
96100
def setUp(self):
97101
self.service = "gitlab"
98102
self.current_owner = OwnerFactory(
@@ -189,15 +193,6 @@ def test_retrieve_account_gets_account_fields(self):
189193
def test_retrieve_account_gets_account_fields_when_there_are_scheduled_details(
190194
self, mock_retrieve_subscription, mock_retrieve_schedule
191195
):
192-
pro_tier = TierFactory(tier_name=TierName.PRO.value)
193-
194-
PlanFactory(
195-
name="users-pr-inappm",
196-
tier=pro_tier,
197-
is_active=True,
198-
billing_rate="monthly",
199-
marketing_name="Pro",
200-
)
201196
owner = OwnerFactory(
202197
admins=[self.current_owner.ownerid], stripe_subscription_id="sub_123"
203198
)
@@ -294,16 +289,6 @@ def test_retrieve_account_gets_account_fields_when_there_are_scheduled_details(
294289
def test_retrieve_account_returns_last_phase_when_more_than_one_scheduled_phases(
295290
self, mock_retrieve_subscription, mock_retrieve_schedule
296291
):
297-
pro_tier = TierFactory(tier_name=TierName.PRO.value)
298-
299-
PlanFactory(
300-
name="users-pr-inappm",
301-
tier=pro_tier,
302-
is_active=True,
303-
billing_rate="monthly",
304-
marketing_name="Pro",
305-
)
306-
307292
owner = OwnerFactory(
308293
admins=[self.current_owner.ownerid], stripe_subscription_id="sub_2345687"
309294
)
@@ -541,13 +526,13 @@ def test_account_with_paid_user_plan_billed_monthly(self):
541526
}
542527

543528
def test_account_with_paid_user_plan_billed_annually(self):
544-
self.current_owner.plan = PlanName.CODECOV_PRO_YEARLY_LEGACY.value
529+
self.current_owner.plan = PlanName.CODECOV_PRO_YEARLY.value
545530
self.current_owner.save()
546531
response = self._retrieve()
547532
assert response.status_code == status.HTTP_200_OK
548533
assert response.data["plan"] == {
549534
"marketing_name": "Pro",
550-
"value": PlanName.CODECOV_PRO_YEARLY_LEGACY.value,
535+
"value": PlanName.CODECOV_PRO_YEARLY.value,
551536
"billing_rate": "annually",
552537
"base_unit_price": 10,
553538
"benefits": [
@@ -707,7 +692,7 @@ def test_update_can_set_plan_auto_activate_on_org_with_account(self):
707692
assert response.data["plan_auto_activate"] is False
708693

709694
def test_update_can_set_plan_to_users_basic(self):
710-
self.current_owner.plan = PlanName.CODECOV_PRO_YEARLY_LEGACY.value
695+
self.current_owner.plan = PlanName.CODECOV_PRO_YEARLY.value
711696
self.current_owner.save()
712697

713698
response = self._update(
@@ -1518,7 +1503,7 @@ def test_update_sentry_plan_monthly_with_users_org(
15181503
@patch("api.internal.owner.serializers.send_sentry_webhook")
15191504
@patch("services.billing.StripeService.modify_subscription")
15201505
def test_update_sentry_plan_annual(self, modify_sub_mock, send_sentry_webhook):
1521-
desired_plan = {"value": "users-sentryy", "quantity": 12}
1506+
desired_plan = {"value": PlanName.SENTRY_YEARLY.value, "quantity": 12}
15221507
self.current_owner.stripe_customer_id = "flsoe"
15231508
self.current_owner.stripe_subscription_id = "djfos"
15241509
self.current_owner.sentry_user_id = "sentry-user-id"
@@ -1540,7 +1525,7 @@ def test_update_sentry_plan_annual(self, modify_sub_mock, send_sentry_webhook):
15401525
def test_update_sentry_plan_annual_with_users_org(
15411526
self, modify_sub_mock, send_sentry_webhook
15421527
):
1543-
desired_plan = {"value": "users-sentryy", "quantity": 12}
1528+
desired_plan = {"value": PlanName.SENTRY_YEARLY.value, "quantity": 12}
15441529
org = OwnerFactory(
15451530
service=Service.GITHUB.value,
15461531
service_id="923836740",
@@ -1648,7 +1633,7 @@ def test_update_apply_cancellation_discount_yearly(
16481633
):
16491634
coupon_create_mock.return_value = MagicMock(id="test-coupon-id")
16501635

1651-
self.current_owner.plan = PlanName.CODECOV_PRO_YEARLY_LEGACY.value
1636+
self.current_owner.plan = PlanName.CODECOV_PRO_YEARLY.value
16521637
self.current_owner.stripe_customer_id = "flsoe"
16531638
self.current_owner.stripe_subscription_id = "djfos"
16541639
self.current_owner.save()
@@ -1701,7 +1686,7 @@ def test_retrieve_org_with_account(self):
17011686
name="Hello World",
17021687
plan_seat_count=5,
17031688
free_seat_count=3,
1704-
plan="users-enterprisey",
1689+
plan=PlanName.ENTERPRISE_CLOUD_YEARLY.value,
17051690
is_delinquent=False,
17061691
)
17071692
InvoiceBillingFactory(is_active=True, account=account)

api/internal/tests/views/test_user_viewset.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
from rest_framework import status
55
from rest_framework.reverse import reverse
66
from rest_framework.test import APITestCase
7+
from shared.django_apps.codecov_auth.tests.factories import PlanFactory, TierFactory
78
from shared.django_apps.core.tests.factories import (
89
OwnerFactory,
910
PullFactory,
1011
RepositoryFactory,
1112
)
13+
from shared.plan.constants import PlanName, TierName
1214

1315
from core.models import Pull
1416
from utils.test_utils import APIClient
@@ -17,8 +19,10 @@
1719
class UserViewSetTests(APITestCase):
1820
def setUp(self):
1921
non_org_active_user = OwnerFactory()
22+
tier = TierFactory(tier_name=TierName.BASIC.value)
23+
plan = PlanFactory(name=PlanName.BASIC_PLAN_NAME.value, tier=tier)
2024
self.current_owner = OwnerFactory(
21-
plan="users-free",
25+
plan=plan.name,
2226
plan_user_count=5,
2327
plan_activated_users=[non_org_active_user.ownerid],
2428
)

0 commit comments

Comments
 (0)