diff --git a/houston/deployment.go b/houston/deployment.go index 84e6ba814..228936636 100644 --- a/houston/deployment.go +++ b/houston/deployment.go @@ -1,6 +1,12 @@ package houston -import "time" +import ( + "encoding/json" + "fmt" + "time" +) + +var errDeploymentNotFound = fmt.Errorf("deployment not found") // ListDeploymentsRequest - filters to list deployments according to set values type ListDeploymentsRequest struct { @@ -330,25 +336,27 @@ var ( }, { version: "0.29.0", - query: ` - query GetDeployment( - $id: String! - ){ - deployment( - where: {id: $id} - ){ - id - airflowVersion - desiredAirflowVersion - runtimeVersion - desiredRuntimeVersion - runtimeAirflowVersion - urls { - type - url - } - } - }`, + query: generateGetDeploymentQuery("id"), + }, + { + version: "0.30.8", + query: generateGetDeploymentQuery("deploymentId"), + }, + { + version: "0.32.0", + query: generateGetDeploymentQuery("id"), + }, + { + version: "0.32.3", + query: generateGetDeploymentQuery("deploymentId"), + }, + { + version: "0.33.0", + query: generateGetDeploymentQuery("id"), + }, + { + version: "0.33.1", + query: generateGetDeploymentQuery("deploymentId"), }, } @@ -464,6 +472,29 @@ var ( }` ) +// GenerateQuery generates the deployment query based on the given version and query parameter +func generateGetDeploymentQuery(queryParam string) string { + return ` + query GetDeployment( + $id: String! + ) { + deployment( + where: {` + queryParam + `: $id} + ) { + id + airflowVersion + desiredAirflowVersion + runtimeVersion + desiredRuntimeVersion + runtimeAirflowVersion + urls { + type + url + } + } + }` +} + // CreateDeployment - create a deployment func (h ClientImplementation) CreateDeployment(vars map[string]interface{}) (*Deployment, error) { reqQuery := DeploymentCreateRequest.GreatestLowerBound(version) @@ -551,7 +582,24 @@ func (h ClientImplementation) GetDeployment(deploymentID string) (*Deployment, e return nil, handleAPIErr(err) } - return &res.Data.GetDeployment, nil + var deploymentSlice []Deployment + var deployment Deployment + + err = json.Unmarshal(res.Data.GetDeployment, &deployment) + if err == nil { + return &deployment, nil + } + + err = json.Unmarshal(res.Data.GetDeployment, &deploymentSlice) + if err != nil { + return nil, handleAPIErr(err) + } + + if len(deploymentSlice) > 0 { + return &deploymentSlice[0], nil + } + + return nil, handleAPIErr(fmt.Errorf("GetDeployment failed for id: %s: %w", deploymentID, errDeploymentNotFound)) } // UpdateDeploymentAirflow - update airflow on a deployment diff --git a/houston/deployment_test.go b/houston/deployment_test.go index ac919b0f1..668c91593 100644 --- a/houston/deployment_test.go +++ b/houston/deployment_test.go @@ -255,25 +255,25 @@ func TestGetDeployment(t *testing.T) { mockDeployment := &Response{ Data: ResponseData{ - GetDeployment: Deployment{ - ID: "deployment-test-id", - Type: "airflow", - Label: "test deployment", - ReleaseName: "prehistoric-gravity-930", - Version: "2.2.0", - AirflowVersion: "2.2.0", - DesiredAirflowVersion: "2.2.0", - DeploymentInfo: DeploymentInfo{}, - Workspace: Workspace{ - ID: "test-workspace-id", - }, - Urls: []DeploymentURL{ - {Type: "airflow", URL: "http://airflow.com"}, - {Type: "flower", URL: "http://flower.com"}, - }, - CreatedAt: time.Time{}, - UpdatedAt: time.Time{}, - }, + GetDeployment: []byte(` + { + "id": "deployment-test-id", + "type": "airflow", + "label": "test deployment", + "releaseName": "prehistoric-gravity-930", + "version": "2.2.0", + "airflowVersion": "2.2.0", + "desiredAirflowVersion": "2.2.0", + "deploymentInfo": {}, + "workspace": { + "id": "test-workspace-id" + }, + "urls": [ + {"type": "airflow", "url": "http://airflow.com"}, + {"type": "flower", "url": "http://flower.com"} + ] + } + `), }, } jsonResponse, err := json.Marshal(mockDeployment) @@ -291,7 +291,7 @@ func TestGetDeployment(t *testing.T) { deployment, err := api.GetDeployment("deployment-id") assert.NoError(t, err) - assert.Equal(t, deployment, &mockDeployment.Data.GetDeployment) + assert.Equal(t, deployment.ID, "deployment-test-id") }) t.Run("error", func(t *testing.T) { @@ -307,6 +307,28 @@ func TestGetDeployment(t *testing.T) { _, err := api.GetDeployment("deployment-id") assert.Contains(t, err.Error(), "Internal Server Error") }) + + mockDeployment = &Response{ + Data: ResponseData{ + GetDeployment: []byte(`[]`), + }, + } + jsonResponse, err = json.Marshal(mockDeployment) + assert.NoError(t, err) + + t.Run("successful query but empty result error", func(t *testing.T) { + client := testUtil.NewTestClient(func(req *http.Request) *http.Response { + return &http.Response{ + StatusCode: 200, + Body: io.NopCloser(bytes.NewBuffer(jsonResponse)), + Header: make(http.Header), + } + }) + api := NewClient(client) + + _, err := api.GetDeployment("deployment-id") + assert.Contains(t, err.Error(), "GetDeployment failed for id:") + }) } func TestUpdateDeploymentAirflow(t *testing.T) { diff --git a/houston/types.go b/houston/types.go index 4ae31caf2..308bb8429 100644 --- a/houston/types.go +++ b/houston/types.go @@ -1,6 +1,7 @@ package houston import ( + "encoding/json" "fmt" "time" @@ -30,7 +31,7 @@ type ResponseData struct { DeleteWorkspaceServiceAccount *ServiceAccount `json:"deleteWorkspaceServiceAccount,omitempty"` DeleteDeploymentServiceAccount *ServiceAccount `json:"deleteDeploymentServiceAccount,omitempty"` DeleteWorkspace *Workspace `json:"deleteWorkspace,omitempty"` - GetDeployment Deployment `json:"deployment,omitempty"` + GetDeployment json.RawMessage `json:"deployment,omitempty"` GetDeployments []Deployment `json:"workspaceDeployments,omitempty"` GetAuthConfig *AuthConfig `json:"authConfig,omitempty"` GetAppConfig *AppConfig `json:"appConfig,omitempty"`