diff --git a/cloud/auth/auth.go b/cloud/auth/auth.go index d5e3a1259..14034c079 100644 --- a/cloud/auth/auth.go +++ b/cloud/auth/auth.go @@ -22,14 +22,15 @@ import ( "github.com/astronomer/astro-cli/config" "github.com/astronomer/astro-cli/context" "github.com/astronomer/astro-cli/pkg/ansi" + "github.com/astronomer/astro-cli/pkg/domainutil" "github.com/astronomer/astro-cli/pkg/httputil" "github.com/astronomer/astro-cli/pkg/input" "github.com/astronomer/astro-cli/pkg/util" ) const ( - Domain = "astronomer.io" - localDomain = "localhost" + authConfigEndpoint = "auth-config" + orgLookupEndpoint = "organization-lookup" cliChooseWorkspace = "Please choose a workspace:" cliSetWorkspaceExample = "\nNo default workspace detected, you can list workspaces with \n\tastro workspace list\nand set your default workspace with \n\tastro workspace switch [WORKSPACEID]\n\n" @@ -47,7 +48,6 @@ var ( var ( err error - splitNum = 2 callbackChannel = make(chan string, 1) callbackTimeout = time.Second * 300 redirectURI = "http://localhost:12345/callback" @@ -61,20 +61,8 @@ var authenticator = Authenticator{ } func orgLookup(domain string) (string, error) { - if strings.Contains(domain, "cloud") { // case when the domain has cloud as prefix, i.e. cloud.astronomer.io - splitDomain := strings.SplitN(domain, ".", splitNum) - domain = splitDomain[1] - } - var addr string - if domain == localDomain { - addr = "http://localhost:8871/organization-lookup" - } else { - addr = fmt.Sprintf( - "%s://api.%s/hub/organization-lookup", - config.CFG.CloudAPIProtocol.GetString(), - domain, - ) - } + addr := domainutil.GetURLToEndpoint("https", domain, orgLookupEndpoint) + ctx := http_context.Background() reqData, err := json.Marshal(orgLookupRequest{Email: userEmail}) if err != nil { @@ -358,7 +346,7 @@ func checkToken(c *config.Context, client astro.Client, out io.Writer) error { // Login handles authentication to astronomer api and registry func Login(domain, orgID, token string, client astro.Client, out io.Writer, shouldDisplayLoginLink bool) error { var res Result - domain = formatDomain(domain) + domain = domainutil.FormatDomain(domain) authConfig, err := ValidateDomain(domain) if err != nil { return err @@ -382,7 +370,6 @@ func Login(domain, orgID, token string, client astro.Client, out io.Writer, shou } } - // If no domain specified // Create context if it does not exist if domain != "" { // Switch context now that we ensured context exists @@ -433,46 +420,21 @@ func Logout(domain string, out io.Writer) { fmt.Fprintln(out, "Successfully logged out of Astronomer") } -func formatDomain(domain string) string { - if strings.Contains(domain, "cloud") { - domain = strings.Replace(domain, "cloud.", "", 1) - } else if domain == "" { - domain = Domain - } - - return domain -} - func ValidateDomain(domain string) (astro.AuthConfig, error) { var ( authConfig astro.AuthConfig - prNum, addr string + addr string validDomain bool ) - if strings.Contains(domain, "pr") { - prNum, domain, _ = strings.Cut(domain, ".") - } validDomain = context.IsCloudDomain(domain) if !validDomain { return authConfig, errors.New("Error! Invalid domain. You are attempting to login into Astro. " + "Are you trying to authenticate to Astronomer Software? If so, please change your current context with 'astro context switch'") } - // TODO refactor and dry this out to remove the nolint - if domain == "localhost" { // nolint - addr = fmt.Sprintf("http://%s:8871/auth-config", domain) - } else if prNum != "" { - addr = fmt.Sprintf( - "https://%s.api.%s/hub/auth-config", - prNum, domain, - ) - } else { - addr = fmt.Sprintf( - "https://api.%s/hub/auth-config", - domain, - ) - } + addr = domainutil.GetURLToEndpoint("https", domain, authConfigEndpoint) + ctx := http_context.Background() doOptions := &httputil.DoOptions{ Context: ctx, diff --git a/cloud/auth/auth_test.go b/cloud/auth/auth_test.go index 111b94b25..cb3083c32 100644 --- a/cloud/auth/auth_test.go +++ b/cloud/auth/auth_test.go @@ -89,13 +89,27 @@ func Test_validateDomain(t *testing.T) { "Are you trying to authenticate to Astronomer Software? If so, change your current context with 'astro context switch'. ") t.Run("pr preview is a valid domain", func(t *testing.T) { - // TODO need to mock this as once this PR closes, test will fail - domain = "pr5723.astronomer-dev.io" + // mocking this as once a PR closes, test would fail + mockResponse := astro.AuthConfig{ + ClientID: "client-id", + Audience: "audience", + DomainURL: "https://myURL.com/", + } + jsonResponse, err := json.Marshal(mockResponse) + assert.NoError(t, err) + httpClient = testUtil.NewTestClient(func(req *http.Request) *http.Response { + return &http.Response{ + StatusCode: 200, + Body: io.NopCloser(bytes.NewBuffer(jsonResponse)), + Header: make(http.Header), + } + }) + domain = "pr1234.astronomer-dev.io" actual, err = ValidateDomain(domain) assert.NoError(t, err) - assert.Equal(t, actual.ClientID, "GWCArPCS6pgFZbhnwx3WCDaJLBcvdFaV") - assert.Equal(t, actual.Audience, "astronomer-ee") - assert.Equal(t, actual.DomainURL, "https://astronomer-sandbox.us.auth0.com") + assert.Equal(t, actual.ClientID, mockResponse.ClientID) + assert.Equal(t, actual.Audience, mockResponse.Audience) + assert.Equal(t, actual.DomainURL, mockResponse.DomainURL) }) } @@ -467,6 +481,21 @@ func TestLogin(t *testing.T) { }) t.Run("can login to a pr preview environment successfully", func(t *testing.T) { testUtil.InitTestConfig(testUtil.CloudPrPreview) + // mocking this as once a PR closes, test would fail + mockAuthConfigResponse := astro.AuthConfig{ + ClientID: "client-id", + Audience: "audience", + DomainURL: "https://myURL.com/", + } + jsonResponse, err := json.Marshal(mockAuthConfigResponse) + assert.NoError(t, err) + httpClient = testUtil.NewTestClient(func(req *http.Request) *http.Response { + return &http.Response{ + StatusCode: 200, + Body: io.NopCloser(bytes.NewBuffer(jsonResponse)), + Header: make(http.Header), + } + }) mockResponse := Result{RefreshToken: "test-token", AccessToken: "test-token", ExpiresIn: 300} orgChecker := func(domain string) (string, error) { return "test-org-id", nil @@ -486,7 +515,7 @@ func TestLogin(t *testing.T) { mockClient.On("GetUserInfo").Return(mockSelfResp, nil).Once() mockClient.On("ListWorkspaces", "test-org-id").Return([]astro.Workspace{{ID: "test-id"}}, nil).Once() - err := Login("pr5723.cloud.astronomer-dev.io", "", "", mockClient, os.Stdout, false) + err = Login("pr5723.cloud.astronomer-dev.io", "", "", mockClient, os.Stdout, false) assert.NoError(t, err) }) @@ -551,8 +580,11 @@ func TestLogin(t *testing.T) { Label: "something-label", }}, nil).Once() // initialize the test authenticator + orgChecker := func(domain string) (string, error) { + return "test-org-id", nil + } authenticator = Authenticator{ - orgChecker: orgLookup, + orgChecker: orgChecker, callbackHandler: func() (string, error) { return "authorizationCode", nil }, tokenRequester: func(authConfig astro.AuthConfig, verifier, code string) (Result, error) { return Result{ @@ -580,8 +612,11 @@ func TestLogin(t *testing.T) { Label: "something-label", }}, nil).Once() // initialize the test authenticator + orgChecker := func(domain string) (string, error) { + return "test-org-id", nil + } authenticator = Authenticator{ - orgChecker: orgLookup, + orgChecker: orgChecker, callbackHandler: func() (string, error) { return "authorizationCode", nil }, tokenRequester: func(authConfig astro.AuthConfig, verifier, code string) (Result, error) { return Result{ @@ -720,30 +755,3 @@ func Test_writeResultToContext(t *testing.T) { // test after changes assertConfigContents("Bearer new_token", "new_refresh_token", time.Now().Add(1234*time.Second), "test.user@astronomer.io") } - -func TestFormatDomain(t *testing.T) { - t.Run("removes cloud from cloud.astronomer.io", func(t *testing.T) { - actual := formatDomain("cloud.astronomer.io") - assert.Equal(t, "astronomer.io", actual) - }) - t.Run("removes cloud from cloud.astronomer-dev.io", func(t *testing.T) { - actual := formatDomain("cloud.astronomer-dev.io") - assert.Equal(t, "astronomer-dev.io", actual) - }) - t.Run("removes cloud from cloud.astronomer-stage.io", func(t *testing.T) { - actual := formatDomain("cloud.astronomer-stage.io") - assert.Equal(t, "astronomer-stage.io", actual) - }) - t.Run("removes cloud from cloud.astronomer-perf.io", func(t *testing.T) { - actual := formatDomain("cloud.astronomer-perf.io") - assert.Equal(t, "astronomer-perf.io", actual) - }) - t.Run("removes cloud from pr1234.cloud.astronomer-dev.io", func(t *testing.T) { - actual := formatDomain("pr1234.cloud.astronomer-dev.io") - assert.Equal(t, "pr1234.astronomer-dev.io", actual) - }) - t.Run("sets default domain if one was not provided", func(t *testing.T) { - actual := formatDomain("") - assert.Equal(t, "astronomer.io", actual) - }) -} diff --git a/cloud/organization/organization.go b/cloud/organization/organization.go index 72d502bf4..d002ddaa5 100644 --- a/cloud/organization/organization.go +++ b/cloud/organization/organization.go @@ -12,6 +12,7 @@ import ( astro "github.com/astronomer/astro-cli/astro-client" "github.com/astronomer/astro-cli/cloud/auth" "github.com/astronomer/astro-cli/config" + "github.com/astronomer/astro-cli/pkg/domainutil" "github.com/astronomer/astro-cli/pkg/httputil" "github.com/astronomer/astro-cli/pkg/input" "github.com/astronomer/astro-cli/pkg/printutil" @@ -45,11 +46,10 @@ func newTableOut() *printutil.Table { func listOrganizations(c *config.Context) ([]OrgRes, error) { var orgDomain string - if c.Domain == "localhost" { - orgDomain = config.CFG.LocalCore.GetString() + "/organizations" - } else { - orgDomain = "https://api." + c.Domain + "/v1alpha1/organizations" - } + withOutCloud := domainutil.FormatDomain(c.Domain) + // we use core api for this + orgDomain = domainutil.GetURLToEndpoint("https", withOutCloud, "v1alpha1/organizations") + orgDomain = domainutil.TransformToCoreAPIEndpoint(orgDomain) authToken := c.Token ctx := context.Background() doOptions := &httputil.DoOptions{ diff --git a/cmd/auth.go b/cmd/auth.go index fa025a547..bbbb01bf1 100644 --- a/cmd/auth.go +++ b/cmd/auth.go @@ -3,6 +3,8 @@ package cmd import ( "io" + "github.com/astronomer/astro-cli/pkg/domainutil" + astro "github.com/astronomer/astro-cli/astro-client" cloudAuth "github.com/astronomer/astro-cli/cloud/auth" "github.com/astronomer/astro-cli/context" @@ -66,7 +68,7 @@ func login(cmd *cobra.Command, args []string, astroClient astro.Client, out io.W ctx, err := context.GetCurrentContext() if err != nil || ctx.Domain == "" { // Default case when no domain is passed, and error getting current context - return cloudLogin(cloudAuth.Domain, "", token, astroClient, out, shouldDisplayLoginLink) + return cloudLogin(domainutil.DefaultDomain, "", token, astroClient, out, shouldDisplayLoginLink) } else if context.IsCloudDomain(ctx.Domain) { return cloudLogin(ctx.Domain, "", token, astroClient, out, shouldDisplayLoginLink) } diff --git a/config/cloud.go b/config/cloud.go index d98fab96e..592dae3d6 100644 --- a/config/cloud.go +++ b/config/cloud.go @@ -5,9 +5,14 @@ import ( "io" "strings" + "github.com/astronomer/astro-cli/pkg/domainutil" "github.com/astronomer/astro-cli/pkg/printutil" ) +const ( + graphqlEndpoint = "graphql" +) + // PrintCloudContext prints current context to stdOut func (c *Context) PrintCloudContext(out io.Writer) error { context, err := c.GetContext() @@ -75,15 +80,6 @@ func (c *Context) GetPublicAPIURL() string { return CFG.LocalPublicAstro.GetString() } - domain := c.Domain - if strings.Contains(domain, cloudDomain) { - splitDomain := strings.SplitN(domain, ".", splitNum) // This splits out 'cloud' from the domain string - domain = splitDomain[1] - } - - return fmt.Sprintf( - "%s://api.%s/hub/graphql", - CFG.CloudAPIProtocol.GetString(), - domain, - ) + domain := domainutil.FormatDomain(c.Domain) + return domainutil.GetURLToEndpoint(CFG.CloudAPIProtocol.GetString(), domain, graphqlEndpoint) } diff --git a/config/config.go b/config/config.go index 87c484577..a69aa8546 100644 --- a/config/config.go +++ b/config/config.go @@ -56,7 +56,7 @@ var ( Context: newCfg("context", ""), Contexts: newCfg("contexts", ""), LocalAstro: newCfg("local.astrohub", "http://localhost:8871/v1"), - LocalCore: newCfg("local.core", "http://localhost:8888/v1alpha1"), + LocalCore: newCfg("local.core", "http://localhost:8888/"), LocalPublicAstro: newCfg("local.public_astrohub", "http://localhost:8871/graphql"), LocalRegistry: newCfg("local.registry", "localhost:5555"), LocalHouston: newCfg("local.houston", ""), diff --git a/context/context.go b/context/context.go index 46272755d..04ba1dde7 100644 --- a/context/context.go +++ b/context/context.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/astronomer/astro-cli/config" + "github.com/astronomer/astro-cli/pkg/domainutil" "github.com/astronomer/astro-cli/pkg/input" "github.com/astronomer/astro-cli/pkg/printutil" "github.com/spf13/cobra" @@ -16,8 +17,7 @@ var ( // CloudDomainRegex is used to differentiate cloud domain from software domain // See https://github.com/astronomer/astrohub-cli/issues/7 for regexp rationale // This will need to be handled as part of the permanent solution to issue #432 - CloudDomainRegex = regexp.MustCompile(`(cloud\.|^)astronomer(?:(-dev|-stage|-perf))?\.io`) - + CloudDomainRegex = regexp.MustCompile(`(?:(pr\d{4,6})\.|^)(?:cloud\.|)astronomer(?:-(dev|stage|perf))?\.io$`) contextDeleteWarnMsg = "Are you sure you want to delete currently used context: %s" cancelCtxDeleteMsg = "Canceling context delete..." failCtxDeleteMsg = "Error deleting context %s: " @@ -30,12 +30,6 @@ var tab = printutil.Table{ ColorRowCode: [2]string{"\033[1;32m", "\033[0m"}, } -const ( - DevCloudDomain = "astronomer-dev.io" - StageCloudDomain = "astronomer-stage.io" - PerfCloudDomain = "astronomer-perf.io" -) - // ContextExists checks to see if context exist in config func Exists(domain string) bool { c := config.Context{Domain: domain} @@ -166,10 +160,10 @@ func IsCloudContext() bool { // IsCloudDomain returns whether the given domain is related to cloud platform or not func IsCloudDomain(domain string) bool { - if domain == DevCloudDomain || - domain == StageCloudDomain || - domain == PerfCloudDomain || - CloudDomainRegex.MatchString(domain) { + if CloudDomainRegex.MatchString(domain) { + return true + } + if domainutil.PRPreviewDomainRegex.MatchString(domain) { return true } diff --git a/context/context_test.go b/context/context_test.go index 4c5226d63..d552cbc4e 100644 --- a/context/context_test.go +++ b/context/context_test.go @@ -41,40 +41,47 @@ func TestGetContextKeyInvalidContextConfig(t *testing.T) { } func TestIsCloudContext(t *testing.T) { - testUtil.InitTestConfig(testUtil.CloudPlatform) - tests := []struct { - name string - contextDomain string - localPlatform string - expectedOutput bool - }{ - {"cloud-domain", "cloud.astronomer.io", config.CloudPlatform, true}, - {"cloud-domain", "astronomer.io", config.CloudPlatform, true}, - {"cloud-dev-domain", "astronomer-dev.io", config.CloudPlatform, true}, - {"cloud-dev-domain", "cloud.astronomer-dev.io", config.CloudPlatform, true}, - {"cloud-stage-domain", "astronomer-stage.io", config.CloudPlatform, true}, - {"cloud-stage-domain", "cloud.astronomer-stage.io", config.CloudPlatform, true}, - {"cloud-perf-domain", "astronomer-perf.io", config.CloudPlatform, true}, - {"cloud-perf-domain", "cloud.astronomer-perf.io", config.CloudPlatform, true}, - {"local-cloud", "localhost", config.CloudPlatform, true}, - {"software-domain", "dev.astrodev.com", config.SoftwarePlatform, false}, - {"software-domain", "software.astronomer-test.io", config.SoftwarePlatform, false}, - {"local-software", "localhost", config.SoftwarePlatform, false}, - {"prpreview", "pr1234.cloud.astronomer-dev.io", config.PrPreview, true}, - } - - for _, tt := range tests { - SetContext(tt.contextDomain) - Switch(tt.contextDomain) - config.CFG.LocalPlatform.SetHomeString(tt.localPlatform) + t.Run("validates cloud context based on domains", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.CloudPlatform) + tests := []struct { + name string + contextDomain string + localPlatform string + expectedOutput bool + }{ + {"cloud-domain", "cloud.astronomer.io", config.CloudPlatform, true}, + {"cloud-domain", "astronomer.io", config.CloudPlatform, true}, + {"cloud-dev-domain", "astronomer-dev.io", config.CloudPlatform, true}, + {"cloud-dev-domain", "cloud.astronomer-dev.io", config.CloudPlatform, true}, + {"cloud-stage-domain", "astronomer-stage.io", config.CloudPlatform, true}, + {"cloud-stage-domain", "cloud.astronomer-stage.io", config.CloudPlatform, true}, + {"cloud-perf-domain", "astronomer-perf.io", config.CloudPlatform, true}, + {"cloud-perf-domain", "cloud.astronomer-perf.io", config.CloudPlatform, true}, + {"local-cloud", "localhost", config.CloudPlatform, true}, + {"software-domain", "dev.astrodev.com", config.SoftwarePlatform, false}, + {"software-domain", "software.astronomer-test.io", config.SoftwarePlatform, false}, + {"local-software", "localhost", config.SoftwarePlatform, false}, + {"prpreview", "pr1234.astronomer-dev.io", config.PrPreview, true}, + {"prpreview", "pr1234.cloud.astronomer-dev.io", config.PrPreview, true}, + {"prpreview", "pr12345.cloud.astronomer-dev.io", config.PrPreview, true}, + {"prpreview", "pr12346.cloud.astronomer-dev.io", config.PrPreview, true}, + {"prpreview", "pr123.cloud.astronomer-dev.io", config.PrPreview, false}, + } + + for _, tt := range tests { + SetContext(tt.contextDomain) + Switch(tt.contextDomain) + config.CFG.LocalPlatform.SetHomeString(tt.localPlatform) + output := IsCloudContext() + assert.Equal(t, tt.expectedOutput, output, fmt.Sprintf("input: %+v", tt)) + } + }) + t.Run("returns true when no current context is set", func(t *testing.T) { + // Case when no current context is set + config.ResetCurrentContext() output := IsCloudContext() - assert.Equal(t, tt.expectedOutput, output, fmt.Sprintf("input: %+v", tt)) - } - - // Case when no current context is set - config.ResetCurrentContext() - output := IsCloudContext() - assert.Equal(t, true, output) + assert.Equal(t, true, output) + }) } func TestDelete(t *testing.T) { @@ -115,14 +122,37 @@ func TestListContext(t *testing.T) { } func TestIsCloudDomain(t *testing.T) { - testUtil.InitTestConfig(testUtil.CloudPrPreview) - actual := IsCloudDomain("pr1234.cloud.astronomer.io") - assert.True(t, actual) - - // TODO this makes the first find pass in viper.IsSet() - // SetContext("pr1234.cloud.astronomer.io") - // TODO this finds the context - Switch("pr1234.cloud.astronomer.io") - actual = IsCloudContext() - assert.True(t, actual) + domainList := []string{ + "astronomer.io", + "astronomer-dev.io", + "astronomer-stage.io", + "astronomer-perf.io", + "cloud.astronomer-dev.io", + "pr1234.cloud.astronomer-dev.io", + "pr1234.astronomer-dev.io", + "pr12345.astronomer-dev.io", + "pr123456.astronomer-dev.io", + "localhost", + "localhost123", + } + t.Run("returns true for valid domains", func(t *testing.T) { + testUtil.InitTestConfig(testUtil.CloudPlatform) + for _, domain := range domainList { + actual := IsCloudDomain(domain) + assert.True(t, actual, domain) + } + }) + t.Run("returns false for invalid domains", func(t *testing.T) { + NotCloudList := []string{ + "cloud.prastronomer-dev.io", + "pr1234567.astronomer-dev.io", + "drum.cloud.astronomer-dev.io", + "localbeast", + } + testUtil.InitTestConfig(testUtil.Initial) + for _, domain := range NotCloudList { + actual := IsCloudDomain(domain) + assert.False(t, actual, domain) + } + }) } diff --git a/pkg/domainutil/domain.go b/pkg/domainutil/domain.go new file mode 100644 index 000000000..cc5987cd0 --- /dev/null +++ b/pkg/domainutil/domain.go @@ -0,0 +1,60 @@ +package domainutil + +import ( + "fmt" + "regexp" + "strings" +) + +const ( + DefaultDomain = "astronomer.io" + LocalDomain = "localhost" +) + +var PRPreviewDomainRegex = regexp.MustCompile(`^(pr\d{4,6}).astronomer-dev\.io$`) + +func FormatDomain(domain string) string { + if strings.Contains(domain, "cloud") { + domain = strings.Replace(domain, "cloud.", "", 1) + } else if domain == "" { + domain = DefaultDomain + } + + return domain +} + +func isPrPreviewDomain(domain string) bool { + return PRPreviewDomainRegex.MatchString(domain) +} + +func getPRSubDomain(domain string) (prSubDomain, restOfDomain string) { + if isPrPreviewDomain(domain) { + prSubDomain, domain, _ = strings.Cut(domain, ".") + } + return prSubDomain, domain +} + +func GetURLToEndpoint(protocol, domain, endpoint string) string { + var addr, prSubDomain string + + switch domain { + case LocalDomain: + addr = fmt.Sprintf("%s://%s:8871/%s", "http", domain, endpoint) + return addr + default: + if isPrPreviewDomain(domain) { + prSubDomain, domain = getPRSubDomain(domain) + addr = fmt.Sprintf("%s://%s.api.%s/hub/%s", protocol, prSubDomain, domain, endpoint) + return addr + } + addr = fmt.Sprintf("%s://api.%s/hub/%s", protocol, domain, endpoint) + } + return addr +} + +func TransformToCoreAPIEndpoint(addr string) string { + if strings.Contains(addr, "v1alpha1") { + addr = strings.Replace(addr, "/hub", "", 1) + } + return addr +} diff --git a/pkg/domainutil/domain_test.go b/pkg/domainutil/domain_test.go new file mode 100644 index 000000000..0d6d7a464 --- /dev/null +++ b/pkg/domainutil/domain_test.go @@ -0,0 +1,170 @@ +package domainutil + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + listOfURLs = []string{ + "cloud.astronomer.io", + "cloud.astronomer-dev.io", + "cloud.astronomer-stage.io", + "cloud.astronomer-perf.io", + "pr1234.fail.astronomer-dev.io", + "pr1234.astronomer-dev.fail.io", + "pr1234.astronomer-devpr.io", + "pr1234.astroprnomer-dev.io", + "pr123.astroprnomer-dev.io", + "pr1234.astronomer-dev.io.fail", + "pr1234.cloud.astronomer-stage.io", + "pr1234.cloud.astronomer-perf.io", + "pr12345.cloud.astronomer-perf.io", + "pr1234.cloud1.astronomer-perf.io", + "pr1234.cloud.astronomer-stage.io", + "foo.pr1234.cloud.astronomer-perf.io", + "pr123.cloud.astronomer-stage.io", + "pr123.cloud.astronomer-perf.io", + "pr1234.cloud.astronomer.io", + "drum.cloud.astronomer-dev.io", + "drum.cloud.astronomer.io", + } + listOfPRURLs = []string{ + "pr1234.astronomer-dev.io", + "pr12345.astronomer-dev.io", + "pr12346.astronomer-dev.io", + } + listOfPRs = []string{ + "pr1234", + "pr12345", + "pr12346", + } +) + +func TestFormatDomain(t *testing.T) { + t.Run("removes cloud from cloud.astronomer.io", func(t *testing.T) { + actual := FormatDomain("cloud.astronomer.io") + assert.Equal(t, "astronomer.io", actual) + }) + t.Run("removes cloud from cloud.astronomer-dev.io", func(t *testing.T) { + actual := FormatDomain("cloud.astronomer-dev.io") + assert.Equal(t, "astronomer-dev.io", actual) + }) + t.Run("removes cloud from cloud.astronomer-stage.io", func(t *testing.T) { + actual := FormatDomain("cloud.astronomer-stage.io") + assert.Equal(t, "astronomer-stage.io", actual) + }) + t.Run("removes cloud from cloud.astronomer-perf.io", func(t *testing.T) { + actual := FormatDomain("cloud.astronomer-perf.io") + assert.Equal(t, "astronomer-perf.io", actual) + }) + t.Run("removes cloud from pr1234.cloud.astronomer-dev.io", func(t *testing.T) { + actual := FormatDomain("pr1234.cloud.astronomer-dev.io") + assert.Equal(t, "pr1234.astronomer-dev.io", actual) + }) + t.Run("sets default domain if one was not provided", func(t *testing.T) { + actual := FormatDomain("") + assert.Equal(t, "astronomer.io", actual) + }) + t.Run("does not mutate domain if cloud is not found in input", func(t *testing.T) { + actual := FormatDomain("fail.astronomer-dev.io") + assert.Equal(t, "fail.astronomer-dev.io", actual) + }) +} + +func TestIsPrPreviewDomain(t *testing.T) { + t.Run("returns true if its pr preview domain", func(t *testing.T) { + for _, urlToCheck := range listOfPRURLs { + actual := isPrPreviewDomain(urlToCheck) + assert.True(t, actual, urlToCheck+" should be true") + } + }) + t.Run("returns false if its not pr preview domain", func(t *testing.T) { + for _, urlToCheck := range listOfURLs { + actual := isPrPreviewDomain(urlToCheck) + assert.False(t, actual, urlToCheck+" should be false") + } + }) +} + +func TestGetPRSubDomain(t *testing.T) { + t.Run("returns pr subdomain for a valid PR preview domain", func(t *testing.T) { + for i, domainToCheck := range listOfPRURLs { + actualPR, actualDomain := getPRSubDomain(domainToCheck) + assert.Equal(t, "astronomer-dev.io", actualDomain) + assert.Equal(t, listOfPRs[i], actualPR) + } + }) + t.Run("returns empty pr subdomain for domains that are not a PR Preview domain", func(t *testing.T) { + for _, domainToCheck := range listOfURLs { + actualPRDomain, actualDomain := getPRSubDomain(domainToCheck) + assert.Equal(t, domainToCheck, actualDomain) + assert.Equal(t, "", actualPRDomain) + } + }) +} + +func TestGetURLToEndpoint(t *testing.T) { + var prSubDomain, domain, expectedURL, endpoint string + endpoint = "myendpoint" + t.Run("returns localhost endpoint", func(t *testing.T) { + domain = "localhost" + expectedURL = fmt.Sprintf("http://%s:8871/%s", domain, endpoint) + actualURL := GetURLToEndpoint("https", domain, endpoint) + assert.Equal(t, expectedURL, actualURL) + }) + t.Run("returns pr preview endpoint", func(t *testing.T) { + prSubDomain = "pr1234" + domain = "pr1234.astronomer-dev.io" + expectedURL = fmt.Sprintf("https://%s.api.%s/hub/%s", prSubDomain, "astronomer-dev.io", endpoint) + actualURL := GetURLToEndpoint("https", domain, endpoint) + assert.Equal(t, expectedURL, actualURL) + }) + t.Run("returns cloud endpoint for prod", func(t *testing.T) { + domain = "astronomer.io" + expectedURL = fmt.Sprintf("https://api.%s/hub/%s", domain, endpoint) + actualURL := GetURLToEndpoint("https", domain, endpoint) + assert.Equal(t, expectedURL, actualURL) + }) + t.Run("returns cloud endpoint for dev", func(t *testing.T) { + domain = "astronomer-dev.io" + expectedURL = fmt.Sprintf("https://api.%s/hub/%s", domain, endpoint) + actualURL := GetURLToEndpoint("https", domain, endpoint) + assert.Equal(t, expectedURL, actualURL) + }) + t.Run("returns cloud endpoint for stage", func(t *testing.T) { + domain = "astronomer-stage.io" + expectedURL = fmt.Sprintf("https://api.%s/hub/%s", domain, endpoint) + actualURL := GetURLToEndpoint("https", domain, endpoint) + assert.Equal(t, expectedURL, actualURL) + }) + t.Run("returns cloud endpoint for perf", func(t *testing.T) { + domain = "astronomer-perf.io" + expectedURL = fmt.Sprintf("https://api.%s/hub/%s", domain, endpoint) + actualURL := GetURLToEndpoint("https", domain, endpoint) + assert.Equal(t, expectedURL, actualURL) + }) + t.Run("returns cloud endpoint for everything else", func(t *testing.T) { + domain = "someotherdomain.io" + expectedURL = fmt.Sprintf("https://api.%s/hub/%s", domain, endpoint) + actualURL := GetURLToEndpoint("https", domain, endpoint) + assert.Equal(t, expectedURL, actualURL) + }) +} + +func TestTransformToCoreApiEndpoint(t *testing.T) { + t.Run("transforms non-local url to core api endpoint", func(t *testing.T) { + actual := TransformToCoreAPIEndpoint("https://somedomain.io/hub/v1alpha1/great-endpoint") + assert.Equal(t, "https://somedomain.io/v1alpha1/great-endpoint", actual) + }) + t.Run("does not transform local url to core api endpoint", func(t *testing.T) { + actual := TransformToCoreAPIEndpoint("http://localhost:1234/v1alpha1/great-endpoint") + assert.Equal(t, "http://localhost:1234/v1alpha1/great-endpoint", actual) + }) + t.Run("returns without changes if url is not meant for core api", func(t *testing.T) { + actual := TransformToCoreAPIEndpoint("https://somedomain.io/hub/valpha1/great-enedpoint") + assert.Equal(t, "https://somedomain.io/hub/valpha1/great-enedpoint", actual) + }) +}