Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion cloud/organization/organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ func newTableOut() *printutil.Table {
}

func ListOrganizations(platformCoreClient astroplatformcore.CoreClient) ([]astroplatformcore.Organization, error) {
organizationListParams := &astroplatformcore.ListOrganizationsParams{}
limit := 100
organizationListParams := &astroplatformcore.ListOrganizationsParams{
Limit: &limit,
}
resp, err := platformCoreClient.ListOrganizationsWithResponse(http_context.Background(), organizationListParams)
if err != nil {
return nil, err
Expand All @@ -56,6 +59,18 @@ func ListOrganizations(platformCoreClient astroplatformcore.CoreClient) ([]astro
return orgs, nil
}

func GetOrganization(orgID string, platformCoreClient astroplatformcore.CoreClient) (*astroplatformcore.Organization, error) {
resp, err := platformCoreClient.GetOrganizationWithResponse(http_context.Background(), orgID, &astroplatformcore.GetOrganizationParams{})
if err != nil {
return nil, err
}
err = astroplatformcore.NormalizeAPIError(resp.HTTPResponse, resp.Body)
if err != nil {
return nil, err
}
return resp.JSON200, nil
}

// List all Organizations
func List(out io.Writer, platformCoreClient astroplatformcore.CoreClient) error {
c, err := config.GetCurrentContext()
Expand Down Expand Up @@ -173,6 +188,14 @@ func Switch(orgNameOrID string, coreClient astrocore.CoreClient, platformCoreCli
targetOrg = &or[i]
}
}
// If not found in list, try to get org by ID directly
Copy link
Contributor

Choose a reason for hiding this comment

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

It's unfortunate that we have this ambiguous value that could be a name or an ID. I'd prefer if we could deal with this more systematically than a hail mary get org call if the first page of list orgs doesn't produce it. Can we look at the value and if it is a CUID then we do a get org call, otherwise we paginate through list orgs responses until we find it? Then we avoid unnecessary lookups, and if we don't find it we know it is really not there instead of maybe being on another page.

// This handles cases where user has access to more orgs than the list limit
if targetOrg == nil {
org, err := GetOrganization(orgNameOrID, platformCoreClient)
if err == nil && org != nil {
targetOrg = org
}
}
}
if targetOrg == nil {
return errInvalidOrganizationName
Expand Down
68 changes: 51 additions & 17 deletions cloud/organization/organization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (s *Suite) TestList() {

s.Run("organization list success", func() {
mockClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()

buf := new(bytes.Buffer)
err := List(buf, mockClient)
Expand All @@ -98,7 +98,7 @@ func (s *Suite) TestList() {

s.Run("organization network error", func() {
mockClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(nil, errNetwork).Once()
mockClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(nil, errNetwork).Once()
buf := new(bytes.Buffer)
err := List(buf, mockClient)
s.Contains(err.Error(), "network error")
Expand All @@ -107,7 +107,7 @@ func (s *Suite) TestList() {

s.Run("organization list error", func() {
mockClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockErrorResponse, nil).Once()
mockClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockErrorResponse, nil).Once()
buf := new(bytes.Buffer)
err := List(buf, mockClient)
s.Contains(err.Error(), "failed to fetch organizations")
Expand All @@ -121,7 +121,7 @@ func (s *Suite) TestGetOrganizationSelection() {
s.Run("get organiation selection success", func() {
mockClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()

// mock os.Stdin
input := []byte("1")
Expand All @@ -144,7 +144,7 @@ func (s *Suite) TestGetOrganizationSelection() {

s.Run("get organization selection list error", func() {
mockClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockErrorResponse, nil).Once()
mockClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockErrorResponse, nil).Once()

buf := new(bytes.Buffer)
_, err := getOrganizationSelection(buf, mockClient)
Expand All @@ -154,7 +154,7 @@ func (s *Suite) TestGetOrganizationSelection() {

s.Run("get organization selection select error", func() {
mockClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()

// mock os.Stdin
input := []byte("3")
Expand All @@ -181,7 +181,7 @@ func (s *Suite) TestSwitch() {
s.Run("successful switch with name", func() {
mockCoreClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()
CheckUserSession = func(c *config.Context, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer) error {
return nil
}
Expand All @@ -196,7 +196,7 @@ func (s *Suite) TestSwitch() {
s.Run("switching to a current organization", func() {
mockCoreClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()

buf := new(bytes.Buffer)
err := Switch("org1", mockCoreClient, mockPlatformCoreClient, buf, false)
Expand All @@ -209,7 +209,7 @@ func (s *Suite) TestSwitch() {
s.Run("successful switch without name", func() {
mockCoreClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()
CheckUserSession = func(c *config.Context, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer) error {
return nil
}
Expand All @@ -234,7 +234,12 @@ func (s *Suite) TestSwitch() {
s.Run("failed switch wrong name", func() {
mockCoreClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()
// Mock GetOrganization to return error (org not found by ID either)
mockPlatformCoreClient.On("GetOrganizationWithResponse", mock.Anything, "name-wrong", mock.Anything).Return(&astroplatformcore.GetOrganizationResponse{
HTTPResponse: &http.Response{StatusCode: 404},
JSON404: &astroplatformcore.Error{Message: "not found"},
}, nil).Once()
CheckUserSession = func(c *config.Context, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer) error {
return nil
}
Expand All @@ -248,7 +253,7 @@ func (s *Suite) TestSwitch() {
s.Run("failed switch bad selection", func() {
mockCoreClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()
CheckUserSession = func(c *config.Context, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer) error {
return nil
}
Expand Down Expand Up @@ -283,7 +288,7 @@ func (s *Suite) TestSwitch() {
}
mockCoreClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()
CheckUserSession = func(c *config.Context, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer) error {
return nil
}
Expand All @@ -294,6 +299,35 @@ func (s *Suite) TestSwitch() {
mockCoreClient.AssertExpectations(s.T())
mockPlatformCoreClient.AssertExpectations(s.T())
})

s.Run("successful switch with ID not in list but found via GetOrganization", func() {
// Simulate org not being in the paginated list (e.g., user has >100 orgs)
emptyListResponse := astroplatformcore.ListOrganizationsResponse{
HTTPResponse: &http.Response{
StatusCode: 200,
},
JSON200: &astroplatformcore.OrganizationsPaginated{
Organizations: []astroplatformcore.Organization{},
},
}
mockCoreClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockPlatformCoreClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&emptyListResponse, nil).Once()
// Mock GetOrganization to return the org by ID
mockPlatformCoreClient.On("GetOrganizationWithResponse", mock.Anything, "org3-id", mock.Anything).Return(&astroplatformcore.GetOrganizationResponse{
HTTPResponse: &http.Response{StatusCode: 200},
JSON200: &astroplatformcore.Organization{Id: "org3-id", Name: "org3", Product: &mockOrganizationProduct},
}, nil).Once()
CheckUserSession = func(c *config.Context, coreClient astrocore.CoreClient, platformCoreClient astroplatformcore.CoreClient, out io.Writer) error {
return nil
}
buf := new(bytes.Buffer)
err := Switch("org3-id", mockCoreClient, mockPlatformCoreClient, buf, false)
s.NoError(err)
s.Equal("\nSuccessfully switched organization\n", buf.String())
mockCoreClient.AssertExpectations(s.T())
mockPlatformCoreClient.AssertExpectations(s.T())
})
}

func (s *Suite) TestIsOrgHosted() {
Expand Down Expand Up @@ -359,7 +393,7 @@ func (s *Suite) TestExportAuditLogs() {
s.Run("export audit logs success", func() {
mockPlatformClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()
mockClient.On("GetOrganizationAuditLogsWithResponse", mock.Anything, mock.Anything, mock.Anything).Return(&mockOKAuditLogResponse, nil).Once()
err := ExportAuditLogs(mockClient, mockPlatformClient, "", "", 1)
s.NoError(err)
Expand All @@ -369,7 +403,7 @@ func (s *Suite) TestExportAuditLogs() {
s.Run("export audit logs and select org success", func() {
mockPlatformClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()
mockClient.On("GetOrganizationAuditLogsWithResponse", mock.Anything, mock.Anything, mock.Anything).Return(&mockOKAuditLogResponse, nil).Once()
err := ExportAuditLogs(mockClient, mockPlatformClient, "org1", "", 1)
s.NoError(err)
Expand All @@ -379,7 +413,7 @@ func (s *Suite) TestExportAuditLogs() {
s.Run("export failure", func() {
mockPlatformClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()
mockClient.On("GetOrganizationAuditLogsWithResponse", mock.Anything, mock.Anything, mock.Anything).Return(nil, errNetwork).Once()
err := ExportAuditLogs(mockClient, mockPlatformClient, "", "", 1)
s.Contains(err.Error(), "network error")
Expand All @@ -389,7 +423,7 @@ func (s *Suite) TestExportAuditLogs() {
s.Run("list failure", func() {
mockPlatformClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(nil, errNetwork).Once()
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(nil, errNetwork).Once()
err := ExportAuditLogs(mockClient, mockPlatformClient, "org1", "", 1)
s.Contains(err.Error(), "network error")
mockPlatformClient.AssertExpectations(s.T())
Expand All @@ -398,7 +432,7 @@ func (s *Suite) TestExportAuditLogs() {
s.Run("organization list error", func() {
mockPlatformClient := new(astroplatformcore_mocks.ClientWithResponsesInterface)
mockClient := new(astrocore_mocks.ClientWithResponsesInterface)
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, &astroplatformcore.ListOrganizationsParams{}).Return(&mockOKResponse, nil).Once()
mockPlatformClient.On("ListOrganizationsWithResponse", mock.Anything, mock.Anything).Return(&mockOKResponse, nil).Once()
mockClient.On("GetOrganizationAuditLogsWithResponse", mock.Anything, mock.Anything, mock.Anything).Return(&mockOKAuditLogResponseError, nil).Once()
err := ExportAuditLogs(mockClient, mockPlatformClient, "", "", 1)
s.Contains(err.Error(), "failed to fetch organizations audit logs")
Expand Down