Skip to content

Commit

Permalink
feat: add organizationRevokeSharedAccount and `accountManagementCan…
Browse files Browse the repository at this point in the history
…celAccount` mutations (#1187)

Co-authored-by: pranav-new-relic <[email protected]>
  • Loading branch information
iamsumit and pranav-new-relic authored Jul 10, 2024
1 parent 13afc02 commit 396df9d
Show file tree
Hide file tree
Showing 10 changed files with 424 additions and 2 deletions.
6 changes: 4 additions & 2 deletions .tutone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ packages:
max_query_field_depth: 3
- name: accountManagementUpdateAccount
max_query_field_depth: 3
- name: accountManagementCancelAccount
max_query_field_depth: 3

- name: accounts
path: pkg/accounts
Expand Down Expand Up @@ -1242,8 +1244,8 @@ packages:
max_query_field_depth: 2
# - name: organizationCreateSharedAccount
# max_query_field_depth: 2
# - name: organizationRevokeSharedAccount
# max_query_field_depth: 2
- name: organizationRevokeSharedAccount
max_query_field_depth: 2
- name: organizationUpdateSharedAccount
max_query_field_depth: 2
types:
Expand Down
48 changes: 48 additions & 0 deletions pkg/accountmanagement/accountmanagement_api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 73 additions & 0 deletions pkg/accountmanagement/accountmanagement_api_.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Code **NOT** generated by tutone
package accountmanagement

import (
"context"

"github.com/newrelic/newrelic-client-go/v2/pkg/errors"
)

// --------------------------------------------------------------------
// NOTE: (for the maintainers and users of newrelic-client-go)
// --------------------------------------------------------------------
// The function `GetManagedAccountsWithAdditionalArguments`, function `GetManagedAccountsWithAdditionalArgumentsWithContext` and the query `getManagedAccountsWithAdditionalArgumentsQuery` in this file
// are "modified" versions of the function `GetManagedAccounts`, the function `GetManagedAccountsWithContext` and the query `getManagedAccountsQuery` respectively,
// originally defined in accountmanagement_api.go.
//
// These manual modifications had to be written owing to the introduction of a new input (and output) field to the `getManagedAccountsQuery`, "isCanceled", which
// is causing conflicts with the Tutone generated code; see the PR linked to this change for more details on the exact limitations.
//
// Owing to this, in order to facilitate using these functions with the isCanceled attribute, modified versions of the functions and mutations have been added to
// this file. This would also allow us to ensure the older counterparts of these functions defined in accountmanagement_api.go inflict no breaking changes onto upstream
// services, such as the New Relic Terraform Provider. While we shall aim to bring this under Tutone's scope, please use the functions in this file to use the "isCanceled"
// attribute recently added to this query.
//
// TL;DR The functions in this file are NOT Tutone generated; we would eventually need to move functionalities in these duplicated functions into the original ones
// in accountmanagement_api.go .

// Admin-level info about the accounts in an organization.
func (a *Accountmanagement) GetManagedAccountsWithAdditionalArguments(
isCanceled *bool,
) (*[]AccountManagementManagedAccount, error) {
return a.GetManagedAccountsWithAdditionalArgumentsWithContext(context.Background(),
isCanceled,
)
}

// Admin-level info about the accounts in an organization.
func (a *Accountmanagement) GetManagedAccountsWithAdditionalArgumentsWithContext(
ctx context.Context,
isCanceled *bool,
) (*[]AccountManagementManagedAccount, error) {

resp := managedAccountsResponse{}
vars := map[string]interface{}{
"isCanceled": &isCanceled,
}

if err := a.client.NerdGraphQueryWithContext(ctx, getManagedAccountsWithAdditionalArgumentsQuery, vars, &resp); err != nil {
return nil, err
}

if len(resp.Actor.Organization.AccountManagement.ManagedAccounts) == 0 {
return nil, errors.NewNotFound("")
}

return &resp.Actor.Organization.AccountManagement.ManagedAccounts, nil
}

const getManagedAccountsWithAdditionalArgumentsQuery = `query ($isCanceled: Boolean) {
actor {
organization {
accountManagement {
managedAccounts(isCanceled: $isCanceled) {
id
isCanceled
name
regionCode
}
}
}
}
}
`
137 changes: 137 additions & 0 deletions pkg/accountmanagement/accountmanagement_integration_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package accountmanagement

import (
"log"
"testing"
"time"

"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -64,3 +66,138 @@ func TestIntegrationUpdateAccountError(t *testing.T) {
require.Nil(t, actual)
require.NotNil(t, err)
}

func TestIntegrationAccountManagement_CreateUpdateCancelAccount(t *testing.T) {
t.Parallel()
accountManagementClient := newAccountManagementTestClient(t)

// Create Account
name := "client-go-test-account-" + mock.RandSeq(5)
createAccountInput := AccountManagementCreateInput{
Name: name,
RegionCode: "us01",
}
createAccountResponse, err := accountManagementClient.AccountManagementCreateAccount(createAccountInput)

require.Nil(t, err)
require.NotNil(t, createAccountResponse.ManagedAccount.ID)
require.Equal(t, createAccountInput.RegionCode, createAccountResponse.ManagedAccount.RegionCode)
require.Equal(t, createAccountInput.Name, createAccountResponse.ManagedAccount.Name)
time.Sleep(time.Second * 2)

// Update Account
updateAccountInput := AccountManagementUpdateInput{
ID: createAccountResponse.ManagedAccount.ID,
Name: name + "-updated",
}
updateAccountResponse, err := accountManagementClient.AccountManagementUpdateAccount(updateAccountInput)

require.Nil(t, err)
require.NotNil(t, updateAccountResponse.ManagedAccount.ID)
require.Equal(t, updateAccountResponse.ManagedAccount.ID, createAccountResponse.ManagedAccount.ID)
require.Equal(t, updateAccountInput.Name, updateAccountResponse.ManagedAccount.Name)
time.Sleep(time.Second * 3)

// Get Account
getAccountResponse, err := accountManagementClient.GetManagedAccounts()

require.Nil(t, err)
require.NotNil(t, getAccountResponse)
foundAccountInGetResponse := false

for _, account := range *getAccountResponse {
if account.ID == updateAccountResponse.ManagedAccount.ID {
foundAccountInGetResponse = true
break
}
}

require.True(t, foundAccountInGetResponse)

// Cancel Account
cancelAccountResponse, err := accountManagementClient.AccountManagementCancelAccount(createAccountResponse.ManagedAccount.ID)

require.Nil(t, err)
require.NotNil(t, cancelAccountResponse)
time.Sleep(time.Second * 2)

// Get Account to Confirm Account Cancellation based on the value of `isCanceled`
isCancelled := true
getAccountResponse, err = accountManagementClient.GetManagedAccountsWithAdditionalArguments(&isCancelled)

require.Nil(t, err)
require.NotNil(t, getAccountResponse)
foundAccountInGetResponse = false

for _, account := range *getAccountResponse {
if account.ID == updateAccountResponse.ManagedAccount.ID {
foundAccountInGetResponse = true
require.True(t, account.IsCanceled)
break
}
}

require.True(t, foundAccountInGetResponse)

}

func TestIntegrationGetManagedAccounts(t *testing.T) {
t.Parallel()
accountManagementClient := newAccountManagementTestClient(t)

actual, _ := accountManagementClient.GetManagedAccounts()

log.Println(actual)
require.NotNil(t, actual)
require.NotZero(t, len(*actual))
}

func TestIntegrationGetManagedAccountsModified_CanceledAccounts(t *testing.T) {
t.Parallel()
accountManagementClient := newAccountManagementTestClient(t)

cancelled := true
actual, _ := accountManagementClient.GetManagedAccountsWithAdditionalArguments(&cancelled)
log.Println(actual)
require.NotNil(t, actual)
require.NotZero(t, len(*actual))
}

func TestIntegrationGetManagedAccountsModified_NonCanceledAccounts(t *testing.T) {
t.Parallel()
accountManagementClient := newAccountManagementTestClient(t)

cancelled := false
actual, _ := accountManagementClient.GetManagedAccountsWithAdditionalArguments(&cancelled)
log.Println(actual)
require.NotNil(t, actual)
require.NotZero(t, len(*actual))
}

func TestIntegrationGetManagedAccountsModified_AllCancellationStatuses(t *testing.T) {
t.Parallel()
accountManagementClient := newAccountManagementTestClient(t)

actual, _ := accountManagementClient.GetManagedAccountsWithAdditionalArguments(nil)

require.NotNil(t, actual)
require.NotZero(t, len(*actual))

foundCancelledAccount := false
foundUncancelledAccount := false

for _, acct := range *actual {
if foundUncancelledAccount == true && foundCancelledAccount == true {
break
}
if acct.IsCanceled == true {
foundCancelledAccount = true
}
if acct.IsCanceled == false {
foundUncancelledAccount = true
}
}

require.True(t, foundCancelledAccount)
require.True(t, foundUncancelledAccount)
}
27 changes: 27 additions & 0 deletions pkg/accountmanagement/accountmanagement_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ var (
"regionCode": "us01"
}
}
}`
testCancelAccountResponseJSON = `{
"accountManagementCancelAccount": {
"id": 3833407,
"isCanceled": true,
"name": "test sub account",
"regionCode": "us01"
}
}`
)

Expand Down Expand Up @@ -78,3 +86,22 @@ func TestCreateAccount(t *testing.T) {
assert.NotNil(t, actual)
assert.Equal(t, expected, actual)
}

func TestCancelAccount(t *testing.T) {
t.Parallel()
respJSON := fmt.Sprintf(`{ "data":%s }`, testCancelAccountResponseJSON)
accountManagement := newMockResponse(t, respJSON, http.StatusCreated)

expected := &AccountManagementManagedAccount{
Name: "test sub account",
RegionCode: "us01",
ID: 3833407,
IsCanceled: true,
}

actual, err := accountManagement.AccountManagementCancelAccount(3833407)

assert.NoError(t, err)
assert.NotNil(t, actual)
assert.Equal(t, expected, actual)
}
13 changes: 13 additions & 0 deletions pkg/accountmanagement/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package accountmanagement
type AccountManagementCreateInput struct {
// The name of the account.
Name string `json:"name"`
// The id of the managed organization where the account will be created.
OrganizationId int `json:"organizationId,omitempty"`
// The data center region for the account
RegionCode string `json:"regionCode,omitempty"`
}
Expand All @@ -19,6 +21,8 @@ type AccountManagementCreateResponse struct {
type AccountManagementManagedAccount struct {
// The account ID.
ID int `json:"id"`
// True if account is canceled
IsCanceled bool `json:"isCanceled"`
// The name of the account.
Name string `json:"name"`
// The data center region for the account (US or EU).
Expand Down Expand Up @@ -57,6 +61,8 @@ type Organization struct {
AccountManagement AccountManagementOrganizationStitchedFields `json:"accountManagement,omitempty"`
// The customer id for the organization.
CustomerId string `json:"customerId,omitempty"`
// The ID of the organization.
ID int `json:"id,omitempty"`
// The name of the organization.
Name string `json:"name,omitempty"`
// The telemetry id for the organization
Expand All @@ -66,3 +72,10 @@ type Organization struct {
type managedAccountsResponse struct {
Actor Actor `json:"actor"`
}

// ID - The `ID` scalar type represents a unique identifier, often used to
// refetch an object or as key for a cache. The ID type appears in a JSON
// response as a String; however, it is not intended to be human-readable.
// When expected as an input type, any string (such as `"4"`) or integer
// (such as `4`) input value will be accepted as an ID.
type ID string
Loading

0 comments on commit 396df9d

Please sign in to comment.