diff --git a/msgraph/models.go b/msgraph/models.go index 07832038..ed99f78a 100644 --- a/msgraph/models.go +++ b/msgraph/models.go @@ -1344,7 +1344,7 @@ type SynchronizationStatus struct { CountSuccssiveCompleteFailure *int64 `json:"countSuccessiveCompleteFailures,omitempty"` EscrowsPruned *bool `json:"escrowsPruned,omitempty"` LastExecution *SynchronizationTaskExecution `json:"lastExecution,omitempty"` - LastSuccessfulExecution *SynchronizationTaskExecution `json:"lastExecution,omitempty"` + LastSuccessfulExecution *SynchronizationTaskExecution `json:"lastSuccessfulExecution,omitempty"` LastSuccessfulExecutionWithExports *SynchronizationTaskExecution `json:"lastSuccessfulExecutionWithExports,omitempty"` Progress *[]SynchronizationProgress `json:"progress,omitempty"` Quarantine *SynchronizationQuarantine `json:"quarantine,omitempty"` diff --git a/msgraph/synchronization.go b/msgraph/synchronization.go index 93e29b47..f8611117 100644 --- a/msgraph/synchronization.go +++ b/msgraph/synchronization.go @@ -3,10 +3,11 @@ package msgraph import ( "context" "encoding/json" - // "errors" "fmt" "io" "net/http" + + "github.com/manicminer/hamilton/odata" ) // SynchronizationJobClient performs operations on SynchronizationJobs. @@ -21,12 +22,22 @@ func NewSynchronizationJobClient(tenantId string) *SynchronizationJobClient { } } +// Api calls give UnknownError on consistency errors +func ServicePrincipalDoesNotExistConsistency(resp *http.Response, o *odata.OData) bool { + return o != nil && o.Error != nil && resp.StatusCode == http.StatusUnauthorized +} + +// Api call give StatusConflict on consistency errors +func ConflictConsistencyFailureFunc(resp *http.Response, o *odata.OData) bool { + return o != nil && o.Error != nil && resp.StatusCode == http.StatusConflict +} + // List returns a list of SynchronizationJobs func (c *SynchronizationJobClient) List(ctx context.Context, servicePrincipalId string) (*[]SynchronizationJob, int, error) { resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ ValidStatusCodes: []int{http.StatusOK}, Uri: Uri{ - Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/jobs/", servicePrincipalId), + Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/jobs", servicePrincipalId), HasTenantId: true, }, }) @@ -53,7 +64,8 @@ func (c *SynchronizationJobClient) List(ctx context.Context, servicePrincipalId // Get retrieves a SynchronizationJob func (c *SynchronizationJobClient) Get(ctx context.Context, id string, servicePrincipalId string) (*SynchronizationJob, int, error) { resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ - ValidStatusCodes: []int{http.StatusOK}, + ValidStatusCodes: []int{http.StatusOK}, + ConsistencyFailureFunc: ServicePrincipalDoesNotExistConsistency, Uri: Uri{ Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/jobs/%s", servicePrincipalId, id), HasTenantId: true, @@ -80,9 +92,10 @@ func (c *SynchronizationJobClient) Get(ctx context.Context, id string, servicePr // GetSecrets retrieves a SynchronizationSecret func (c *SynchronizationJobClient) GetSecrets(ctx context.Context, servicePrincipalId string) (*SynchronizationSecret, int, error) { resp, status, _, err := c.BaseClient.Get(ctx, GetHttpRequestInput{ - ValidStatusCodes: []int{http.StatusOK}, + ValidStatusCodes: []int{http.StatusOK}, + ConsistencyFailureFunc: ServicePrincipalDoesNotExistConsistency, Uri: Uri{ - Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/secrets/", servicePrincipalId), + Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/secrets", servicePrincipalId), HasTenantId: true, }, }) @@ -113,8 +126,9 @@ func (c *SynchronizationJobClient) SetSecrets(ctx context.Context, synchronizati return status, fmt.Errorf("json.Marshal(): %v", err) } resp, status, _, err := c.BaseClient.Put(ctx, PutHttpRequestInput{ - Body: body, - ValidStatusCodes: []int{http.StatusNoContent}, + Body: body, + ConsistencyFailureFunc: ServicePrincipalDoesNotExistConsistency, + ValidStatusCodes: []int{http.StatusNoContent}, Uri: Uri{ Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/secrets", servicePrincipalId), HasTenantId: true, @@ -141,11 +155,13 @@ func (c *SynchronizationJobClient) Create(ctx context.Context, synchronizationJo if err != nil { return nil, status, fmt.Errorf("json.Marshal(): %v", err) } + resp, status, _, err := c.BaseClient.Post(ctx, PostHttpRequestInput{ - Body: body, - ValidStatusCodes: []int{http.StatusCreated}, + Body: body, + ConsistencyFailureFunc: ServicePrincipalDoesNotExistConsistency, + ValidStatusCodes: []int{http.StatusCreated}, Uri: Uri{ - Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/jobs/", servicePrincipalId), + Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/jobs", servicePrincipalId), HasTenantId: true, }, }) @@ -171,7 +187,8 @@ func (c *SynchronizationJobClient) Create(ctx context.Context, synchronizationJo func (c *SynchronizationJobClient) Start(ctx context.Context, id string, servicePrincipalId string) (int, error) { var status int resp, status, _, err := c.BaseClient.Post(ctx, PostHttpRequestInput{ - ValidStatusCodes: []int{http.StatusNoContent}, + ConsistencyFailureFunc: ConflictConsistencyFailureFunc, + ValidStatusCodes: []int{http.StatusNoContent}, Uri: Uri{ Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/jobs/%s/start", servicePrincipalId, id), HasTenantId: true, @@ -192,7 +209,7 @@ func (c *SynchronizationJobClient) Start(ctx context.Context, id string, service // Delete func (c *SynchronizationJobClient) Delete(ctx context.Context, id string, servicePrincipalId string) (int, error) { _, status, _, err := c.BaseClient.Delete(ctx, DeleteHttpRequestInput{ - ConsistencyFailureFunc: RetryOn404ConsistencyFailureFunc, + ConsistencyFailureFunc: ConflictConsistencyFailureFunc, ValidStatusCodes: []int{http.StatusNoContent}, Uri: Uri{ Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/jobs/%s/", servicePrincipalId, id), @@ -210,7 +227,8 @@ func (c *SynchronizationJobClient) Delete(ctx context.Context, id string, servic func (c *SynchronizationJobClient) Pause(ctx context.Context, id string, servicePrincipalId string) (int, error) { var status int resp, status, _, err := c.BaseClient.Post(ctx, PostHttpRequestInput{ - ValidStatusCodes: []int{http.StatusNoContent}, + ConsistencyFailureFunc: ConflictConsistencyFailureFunc, + ValidStatusCodes: []int{http.StatusNoContent}, Uri: Uri{ Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/jobs/%s/pause", servicePrincipalId, id), HasTenantId: true, @@ -238,8 +256,9 @@ func (c *SynchronizationJobClient) Restart(ctx context.Context, id string, synch } resp, status, _, err := c.BaseClient.Post(ctx, PostHttpRequestInput{ - Body: body, - ValidStatusCodes: []int{http.StatusNoContent}, + ConsistencyFailureFunc: ConflictConsistencyFailureFunc, + Body: body, + ValidStatusCodes: []int{http.StatusNoContent}, Uri: Uri{ Entity: fmt.Sprintf("/servicePrincipals/%s/synchronization/jobs/%s/restart", servicePrincipalId, id), HasTenantId: true, diff --git a/msgraph/synchronization_test.go b/msgraph/synchronization_test.go index 5b6edaa5..bce1c682 100644 --- a/msgraph/synchronization_test.go +++ b/msgraph/synchronization_test.go @@ -3,7 +3,6 @@ package msgraph_test import ( "fmt" "testing" - "time" "github.com/manicminer/hamilton/internal/test" "github.com/manicminer/hamilton/internal/utils" @@ -21,10 +20,6 @@ func TestSynchronizationClient(t *testing.T) { ID: template.ID, DisplayName: utils.StringPtr(fmt.Sprintf("test-applicationTemplate-%s", c.RandomString)), }) - - // It takes a moment for applications to be created - time.Sleep(4 * time.Second) - testSynchronizationJobClient_SetSecrets(t, c, msgraph.SynchronizationSecret{ Credentials: &[]msgraph.SynchronizationSecretKeyStringValuePair{ { @@ -48,7 +43,6 @@ func TestSynchronizationClient(t *testing.T) { testSynchronizationJobClient_Get(t, c, *job.ID, *app.ServicePrincipal.ID) testSynchronizationJobClient_Start(t, c, *job.ID, *app.ServicePrincipal.ID) testSynchronizationJobClient_List(t, c, *app.ServicePrincipal.ID) - time.Sleep(10 * time.Millisecond) testSynchronizationJobClient_Pause(t, c, *job.ID, *app.ServicePrincipal.ID) testSynchronizationJobClient_Restart(t, c, *job.ID, msgraph.SynchronizationJobRestartCriteria{}, *app.ServicePrincipal.ID) testSynchronizationJobClient_Delete(t, c, *job.ID, *app.ServicePrincipal.ID) @@ -64,11 +58,11 @@ func TestSynchronizationClient(t *testing.T) { func testSynchronizationJobClient_GetSecrets(t *testing.T, c *test.Test, servicePrincipalId string) (synchronizationSecret *msgraph.SynchronizationSecret) { synchronizationSecret, status, err := c.SynchronizationJobClient.GetSecrets(c.Context, servicePrincipalId) if err != nil { - t.Fatalf("SynchronizationJobClient.AddSecrets(): %v", err) + t.Fatalf("SynchronizationJobClient.GetSecrets(): %v", err) } if status < 200 || status >= 300 { - t.Fatalf("SynchronizationJobClient.AddSecrets(): invalid status: %d", status) + t.Fatalf("SynchronizationJobClient.GetSecrets(): invalid status: %d", status) } return } @@ -82,7 +76,6 @@ func testSynchronizationJobClient_SetSecrets(t *testing.T, c *test.Test, s msgra if status < 200 || status >= 300 { t.Fatalf("SynchronizationJobClient.SetSecrets(): invalid status: %d", status) } - return } func testSynchronizationJobClient_Create(t *testing.T, c *test.Test, a msgraph.SynchronizationJob, servicePrincipalId string) (synchronizationJob *msgraph.SynchronizationJob) { @@ -137,7 +130,6 @@ func testSynchronizationJobClient_Start(t *testing.T, c *test.Test, jobId string if status < 200 || status >= 300 { t.Fatalf("SynchronizationJobClient.Start(): invalid status: %d", status) } - return } func testSynchronizationJobClient_Pause(t *testing.T, c *test.Test, jobId string, servicePrincipalId string) { @@ -149,7 +141,6 @@ func testSynchronizationJobClient_Pause(t *testing.T, c *test.Test, jobId string if status < 200 || status >= 300 { t.Fatalf("SynchronizationJobClient.Pause(): invalid status: %d", status) } - return } func testSynchronizationJobClient_Restart(t *testing.T, c *test.Test, jobId string, synchronizationJobRestartCriteria msgraph.SynchronizationJobRestartCriteria, servicePrincipalId string) { @@ -161,8 +152,6 @@ func testSynchronizationJobClient_Restart(t *testing.T, c *test.Test, jobId stri if status < 200 || status >= 300 { t.Fatalf("SynchronizationJobClient.Restart(): invalid status: %d", status) } - - return } func testSynchronizationJobClient_Delete(t *testing.T, c *test.Test, jobId string, servicePrincipalId string) { @@ -174,5 +163,4 @@ func testSynchronizationJobClient_Delete(t *testing.T, c *test.Test, jobId strin if status < 200 || status >= 300 { t.Fatalf("SynchronizationJobClient.Delete(): invalid status: %d", status) } - return }