-
Notifications
You must be signed in to change notification settings - Fork 79
feat: add Twilio Lookup v2 API tests #1285
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
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
d360c7a
feat: add Twilio Lookup v2 API
fbm3307 65981b7
fix: golangci-lint gofmt error
fbm3307 cc76fd4
fix: use typed PhoneLookupMode enum in e2e tests
fbm3307 b2be335
Merge branch 'master' into twiliolapi
fbm3307 6a7cfd8
fix: use non-default PhoneLookupMode in config e2e test
fbm3307 91504da
fix: use Twilio magic numbers for deterministic e2e lookup tests
fbm3307 c35580d
Merge upstream/master and update to new annotation schema
fbm3307 45398b5
fix: remove phone_hash from details JSON, bump api+common replaces
fbm3307 fb34892
fix: remove fork replace directives, use upstream api and toolchain-c…
fbm3307 cae70d8
fix: address review comments — use states.Rejected, fix phone number bug
fbm3307 c4da9fe
fix: use fictional NANPA 555-01XX number for US phone lookup test
fbm3307 2f8016d
fix: address review — add t.Parallel, high-risk test, verify provisio…
fbm3307 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| package parallel | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "net/http" | ||
| "testing" | ||
|
|
||
| toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1" | ||
| "github.com/codeready-toolchain/toolchain-common/pkg/states" | ||
| testconfig "github.com/codeready-toolchain/toolchain-common/pkg/test/config" | ||
| . "github.com/codeready-toolchain/toolchain-e2e/testsupport" | ||
| "github.com/codeready-toolchain/toolchain-e2e/testsupport/wait" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| // Twilio test credentials with magic lookup numbers return deterministic SMS Pumping Risk | ||
| // responses at no cost. The API takes country_code and phone_number separately. | ||
| // See: https://www.twilio.com/docs/lookup/magic-numbers-for-lookup/testing-sms-pumping-risk-with-magic-numbers | ||
| // | ||
| // Magic numbers used: | ||
| // | ||
| // +441234567890 → high risk, not blocked, score 2 | ||
| // +441234567891 → high risk, blocked, score 34 | ||
| // +911234567890 → low risk, not blocked, score 2 | ||
| const ( | ||
| twilioMagicPhoneHighRisk = "1234567890" // +44 prefix → high risk, not blocked | ||
| twilioMagicPhoneHighRiskBlocked = "1234567891" // +44 prefix → high risk, blocked | ||
| usTestPhone = "2025550123" // +1 prefix → fictional NANPA 555-01XX range, safe with test credentials | ||
| ) | ||
|
|
||
| func TestPhoneLookupMode(t *testing.T) { | ||
|
MatousJobanek marked this conversation as resolved.
MatousJobanek marked this conversation as resolved.
|
||
| t.Parallel() | ||
| awaitilities := WaitForDeployments(t) | ||
| hostAwait := awaitilities.Host() | ||
| route := hostAwait.RegistrationServiceURL | ||
|
|
||
| t.Run("log mode stores annotations and user is provisioned", func(t *testing.T) { | ||
| // given | ||
| hostAwait.UpdateToolchainConfig(t, testconfig.RegistrationService().Verification().PhoneLookupMode(toolchainv1alpha1.PhoneLookupModeLog)) | ||
| userSignup, token := signup(t, hostAwait) | ||
|
|
||
| // when | ||
| NewHTTPRequest(t). | ||
| InvokeEndpoint("PUT", route+"/api/v1/signup/verification", token, | ||
| fmt.Sprintf(`{ "country_code":"+44", "phone_number":"%s" }`, twilioMagicPhoneHighRiskBlocked), http.StatusNoContent) | ||
|
|
||
| // then — verification code is set and lookup details are recorded | ||
| userSignup, err := hostAwait.WaitForUserSignup(t, userSignup.Name, | ||
| wait.UntilUserSignupHasAnnotationNotEmpty(toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey)) | ||
| require.NoError(t, err) | ||
|
|
||
| assert.NotEmpty(t, userSignup.Annotations[toolchainv1alpha1.UserSignupPhoneLookupDetailsAnnotationKey]) | ||
| assert.NotEmpty(t, userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) | ||
| assert.False(t, states.Rejected(userSignup), "UserSignup should NOT be rejected in log mode") | ||
|
|
||
| // complete verification and confirm user is provisioned | ||
| NewHTTPRequest(t).InvokeEndpoint("GET", route+fmt.Sprintf("/api/v1/signup/verification/%s", | ||
| userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), token, "", http.StatusOK) | ||
|
|
||
| userSignup, err = wait.For(t, hostAwait.Awaitility, &toolchainv1alpha1.UserSignup{}). | ||
| Update(userSignup.Name, hostAwait.Namespace, | ||
| func(instance *toolchainv1alpha1.UserSignup) { | ||
| states.SetApprovedManually(instance, true) | ||
| }) | ||
| require.NoError(t, err) | ||
|
MatousJobanek marked this conversation as resolved.
|
||
|
|
||
| VerifyResourcesProvisionedForSignup(t, awaitilities, userSignup) | ||
| }) | ||
|
|
||
| t.Run("enabled mode rejects high-risk phone number", func(t *testing.T) { | ||
| // given | ||
| hostAwait.UpdateToolchainConfig(t, testconfig.RegistrationService(). | ||
| Verification().PhoneLookupMode(toolchainv1alpha1.PhoneLookupModeEnabled). | ||
| Verification().PhoneLookupExcludedCountries([]string{"US", "CA"})) | ||
| userSignup, token := signup(t, hostAwait) | ||
|
|
||
| // when | ||
| responseMap := NewHTTPRequest(t). | ||
| InvokeEndpoint("PUT", route+"/api/v1/signup/verification", token, | ||
| fmt.Sprintf(`{ "country_code":"+44", "phone_number":"%s" }`, twilioMagicPhoneHighRiskBlocked), http.StatusForbidden). | ||
| UnmarshalMap() | ||
|
|
||
| // then | ||
| require.NotEmpty(t, responseMap) | ||
| assert.Equal(t, "Forbidden", responseMap["status"]) | ||
|
|
||
| userSignup, err := hostAwait.WaitForUserSignup(t, userSignup.Name) | ||
| require.NoError(t, err) | ||
| assert.True(t, states.Rejected(userSignup), "UserSignup should be rejected in enabled mode with high-risk phone") | ||
| assert.Empty(t, userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) | ||
| }) | ||
|
|
||
| t.Run("enabled mode blocks verification for previously rejected signup", func(t *testing.T) { | ||
| // given | ||
| hostAwait.UpdateToolchainConfig(t, testconfig.RegistrationService().Verification().PhoneLookupMode(toolchainv1alpha1.PhoneLookupModeEnabled)) | ||
| userSignup, token := signup(t, hostAwait) | ||
|
|
||
| _, err := wait.For(t, hostAwait.Awaitility, &toolchainv1alpha1.UserSignup{}). | ||
| Update(userSignup.Name, hostAwait.Namespace, | ||
| func(us *toolchainv1alpha1.UserSignup) { | ||
| states.SetRejected(us, true) | ||
| }) | ||
|
MatousJobanek marked this conversation as resolved.
|
||
| require.NoError(t, err) | ||
|
|
||
| // when | ||
| responseMap := NewHTTPRequest(t). | ||
| InvokeEndpoint("PUT", route+"/api/v1/signup/verification", token, | ||
| fmt.Sprintf(`{ "country_code":"+91", "phone_number":"%s" }`, twilioMagicPhoneHighRisk), http.StatusForbidden). | ||
| UnmarshalMap() | ||
|
|
||
| // then | ||
| require.NotEmpty(t, responseMap) | ||
| assert.Equal(t, "Forbidden", responseMap["status"]) | ||
|
|
||
| userSignup, err = hostAwait.WaitForUserSignup(t, userSignup.Name) | ||
| require.NoError(t, err) | ||
| assert.True(t, states.Rejected(userSignup), "UserSignup should remain rejected") | ||
| assert.Empty(t, userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) | ||
| }) | ||
|
|
||
| t.Run("enabled mode skips lookup for US numbers and user is provisioned", func(t *testing.T) { | ||
| // given | ||
| hostAwait.UpdateToolchainConfig(t, testconfig.RegistrationService(). | ||
| Verification().PhoneLookupMode(toolchainv1alpha1.PhoneLookupModeEnabled). | ||
| Verification().PhoneLookupExcludedCountries([]string{"US", "CA"})) | ||
| userSignup, token := signup(t, hostAwait) | ||
|
|
||
| // when — US is excluded so lookup is never called | ||
| NewHTTPRequest(t). | ||
| InvokeEndpoint("PUT", route+"/api/v1/signup/verification", token, | ||
| fmt.Sprintf(`{ "country_code":"+1", "phone_number":"%s" }`, usTestPhone), http.StatusNoContent) | ||
|
|
||
| // then | ||
| userSignup, err := hostAwait.WaitForUserSignup(t, userSignup.Name, | ||
| wait.UntilUserSignupHasAnnotationNotEmpty(toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey)) | ||
| require.NoError(t, err) | ||
|
|
||
| assert.Empty(t, userSignup.Annotations[toolchainv1alpha1.UserSignupPhoneLookupDetailsAnnotationKey]) | ||
| assert.NotEmpty(t, userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]) | ||
| assert.False(t, states.Rejected(userSignup), "UserSignup should NOT be rejected for excluded country") | ||
|
|
||
| // complete verification and confirm user is provisioned | ||
| NewHTTPRequest(t).InvokeEndpoint("GET", route+fmt.Sprintf("/api/v1/signup/verification/%s", | ||
| userSignup.Annotations[toolchainv1alpha1.UserSignupVerificationCodeAnnotationKey]), token, "", http.StatusOK) | ||
|
|
||
| userSignup, err = wait.For(t, hostAwait.Awaitility, &toolchainv1alpha1.UserSignup{}). | ||
| Update(userSignup.Name, hostAwait.Namespace, | ||
| func(instance *toolchainv1alpha1.UserSignup) { | ||
| states.SetApprovedManually(instance, true) | ||
| }) | ||
| require.NoError(t, err) | ||
|
MatousJobanek marked this conversation as resolved.
|
||
|
|
||
| VerifyResourcesProvisionedForSignup(t, awaitilities, userSignup) | ||
| }) | ||
|
MatousJobanek marked this conversation as resolved.
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.