Skip to content

Commit

Permalink
Add failure scenario tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gigerdo committed Sep 17, 2024
1 parent 7074d8e commit 587528b
Show file tree
Hide file tree
Showing 4 changed files with 437 additions and 28 deletions.
10 changes: 10 additions & 0 deletions ec/ecresource/organizationresource/mapper_to_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ func deploymentRolesApiToModel(ctx context.Context, member models.OrganizationMe
var result []DeploymentRoleAssignment
if member.RoleAssignments != nil {
for _, roleAssignment := range member.RoleAssignments.Deployment {
if roleAssignment.RoleID == nil {
diagnostics.Append(diag.NewErrorDiagnostic("API Error", "API returned role assignment without role"))
return nil
}

deploymentIds, diags := types.SetValueFrom(ctx, types.StringType, roleAssignment.DeploymentIds)
if diags.HasError() {
diagnostics.Append(diags...)
Expand Down Expand Up @@ -154,6 +159,11 @@ func rolesApiToModel(
var result []ProjectRoleAssignment

for _, roleAssignment := range apiRoleAssignments {
if roleAssignment.RoleID == nil {
diagnostics.Append(diag.NewErrorDiagnostic("API Error", "API returned role assignment without role"))
return nil
}

projectIds, diags := types.SetValueFrom(ctx, types.StringType, roleAssignment.ProjectIds)
if diags.HasError() {
diagnostics.Append(diags...)
Expand Down
88 changes: 88 additions & 0 deletions ec/ecresource/organizationresource/mapper_to_model_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package organizationresource

import (
"context"
"github.com/elastic/cloud-sdk-go/pkg/models"
"github.com/hashicorp/terraform-plugin-framework/diag"
"testing"
)

func TestEmptyDataCanBeMappedWithoutPanic(t *testing.T) {
tests := []struct {
name string
data models.OrganizationMembership
}{
{
name: "Empty membership",
data: models.OrganizationMembership{},
},
{
name: "Empty role assignments",
data: models.OrganizationMembership{
RoleAssignments: &models.RoleAssignments{},
},
},
{
name: "Empty roles - Deployment",
data: models.OrganizationMembership{
RoleAssignments: &models.RoleAssignments{
Deployment: []*models.DeploymentRoleAssignment{{}},
Organization: []*models.OrganizationRoleAssignment{{}},
},
},
},
{
name: "Empty roles - Elasticsearch",
data: models.OrganizationMembership{
RoleAssignments: &models.RoleAssignments{
Project: &models.ProjectRoleAssignments{
Elasticsearch: []*models.ProjectRoleAssignment{{}},
},
},
},
},
{
name: "Empty roles - Observability",
data: models.OrganizationMembership{
RoleAssignments: &models.RoleAssignments{
Project: &models.ProjectRoleAssignments{
Observability: []*models.ProjectRoleAssignment{{}},
},
},
},
},
{
name: "Empty roles - Security",
data: models.OrganizationMembership{
RoleAssignments: &models.RoleAssignments{
Project: &models.ProjectRoleAssignments{
Security: []*models.ProjectRoleAssignment{{}},
},
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
diags := diag.Diagnostics{}
apiToModel(context.Background(), test.data, false, &diags)
})
}
}
158 changes: 157 additions & 1 deletion ec/ecresource/organizationresource/resource_mock_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@ func getMembers(memberships []*models.OrganizationMembership) mock.Response {
)
}

func getMembersFails() mock.Response {
return mock.New404ResponseAssertion(
&mock.RequestAssertion{
Host: api.DefaultMockHost,
Header: api.DefaultReadMockHeaders,
Method: "GET",
Path: "/api/v1/organizations/123/members",
},
mock.NewStructBody(models.BasicFailedReply{
Errors: []*models.BasicFailedReplyElement{
{
Message: ec.String("organization-does-not-exist"),
},
}}),
)
}

func getInvitations(invitations []*models.OrganizationInvitation) mock.Response {
return mock.New200ResponseAssertion(
&mock.RequestAssertion{
Expand All @@ -55,8 +72,24 @@ func getInvitations(invitations []*models.OrganizationInvitation) mock.Response
)
}

func createInvitation(invitation *models.OrganizationInvitation) mock.Response {
func getInvitationsFails() mock.Response {
return mock.New404ResponseAssertion(
&mock.RequestAssertion{
Host: api.DefaultMockHost,
Header: api.DefaultReadMockHeaders,
Method: "GET",
Path: "/api/v1/organizations/123/invitations",
},
mock.NewStructBody(models.BasicFailedReply{
Errors: []*models.BasicFailedReplyElement{
{
Message: ec.String("organization-does-not-exist"),
},
}}),
)
}

func createInvitation(invitation *models.OrganizationInvitation) mock.Response {
return mock.New201ResponseAssertion(
&mock.RequestAssertion{
Host: api.DefaultMockHost,
Expand All @@ -77,6 +110,28 @@ func createInvitation(invitation *models.OrganizationInvitation) mock.Response {
)
}

func createInvitationFails(invitation *models.OrganizationInvitation) mock.Response {
return mock.New400ResponseAssertion(
&mock.RequestAssertion{
Host: api.DefaultMockHost,
Header: api.DefaultWriteMockHeaders,
Method: "POST",
Path: "/api/v1/organizations/123/invitations",
Body: mock.NewStructBody(models.OrganizationInvitationRequest{
Emails: []string{*invitation.Email},
ExpiresIn: "7d",
RoleAssignments: invitation.RoleAssignments,
}),
},
mock.NewStructBody(models.BasicFailedReply{
Errors: []*models.BasicFailedReplyElement{
{
Message: ec.String("organization.invitation_invalid_email"),
},
}}),
)
}

func deleteInvitation(invitation *models.OrganizationInvitation) mock.Response {
return mock.New200ResponseAssertion(
&mock.RequestAssertion{
Expand All @@ -89,6 +144,23 @@ func deleteInvitation(invitation *models.OrganizationInvitation) mock.Response {
)
}

func deleteInvitationFails(invitation *models.OrganizationInvitation) mock.Response {
return mock.New400ResponseAssertion(
&mock.RequestAssertion{
Host: api.DefaultMockHost,
Header: api.DefaultReadMockHeaders,
Method: "DELETE",
Path: "/api/v1/organizations/123/invitations/" + *invitation.Token,
},
mock.NewStructBody(models.BasicFailedReply{
Errors: []*models.BasicFailedReplyElement{
{
Message: ec.String("organization.invitation_token_invalid"),
},
}}),
)
}

func buildInvitationModel(email string) *models.OrganizationInvitation {
timestamp, _ := strfmt.ParseDateTime("2021-01-07T22:13:42.999Z")
expiration, _ := strfmt.ParseDateTime("2023-01-07T22:13:42.999Z")
Expand Down Expand Up @@ -145,6 +217,39 @@ func addRoleAssignments() mock.Response {
)
}

func addRoleAssignmentsFails() mock.Response {
return mock.New400ResponseAssertion(
&mock.RequestAssertion{
Host: api.DefaultMockHost,
Header: api.DefaultWriteMockHeaders,
Method: "POST",
Path: "/api/v1/users/userid2/role_assignments",
Body: mock.NewStructBody(models.RoleAssignments{
Deployment: []*models.DeploymentRoleAssignment{
{
All: ec.Bool(false),
OrganizationID: orgId,
RoleID: ec.String("deployment-editor"),
DeploymentIds: []string{"abc"},
},
{
OrganizationID: orgId,
RoleID: ec.String("deployment-viewer"),
All: ec.Bool(true),
},
},
Project: &models.ProjectRoleAssignments{},
}),
},
mock.NewStructBody(models.BasicFailedReply{
Errors: []*models.BasicFailedReplyElement{
{
Message: ec.String("role_assignments.invalid_config"),
},
}}),
)
}

func removeRoleAssignments() mock.Response {
return mock.New200ResponseAssertion(
&mock.RequestAssertion{
Expand Down Expand Up @@ -174,6 +279,40 @@ func removeRoleAssignments() mock.Response {
)
}

func removeRoleAssignmentsFails() mock.Response {
return mock.New400ResponseAssertion(
&mock.RequestAssertion{
Host: api.DefaultMockHost,
Header: api.DefaultWriteMockHeaders,
Method: "DELETE",
Path: "/api/v1/users/userid2/role_assignments",
Body: mock.NewStructBody(models.RoleAssignments{
Organization: []*models.OrganizationRoleAssignment{
{
OrganizationID: orgId,
RoleID: ec.String("organization-admin"),
},
},
Deployment: []*models.DeploymentRoleAssignment{
{
All: ec.Bool(false),
OrganizationID: orgId,
RoleID: ec.String("deployment-editor"),
DeploymentIds: []string{"abc"},
},
},
Project: &models.ProjectRoleAssignments{},
}),
},
mock.NewStructBody(models.BasicFailedReply{
Errors: []*models.BasicFailedReplyElement{
{
Message: ec.String("role_assignments.invalid_config"),
},
}}),
)
}

func removeMember() mock.Response {
return mock.New200ResponseAssertion(
&mock.RequestAssertion{
Expand All @@ -186,6 +325,23 @@ func removeMember() mock.Response {
)
}

func removeMemberFails() mock.Response {
return mock.New404ResponseAssertion(
&mock.RequestAssertion{
Host: api.DefaultMockHost,
Header: api.DefaultReadMockHeaders,
Method: "DELETE",
Path: "/api/v1/organizations/123/members/userid2",
},
mock.NewStructBody(models.BasicFailedReply{
Errors: []*models.BasicFailedReplyElement{
{
Message: ec.String("organization.membership_not_found"),
},
}}),
)
}

func buildExistingMember() *models.OrganizationMembership {
return &models.OrganizationMembership{
UserID: ec.String("userid"),
Expand Down
Loading

0 comments on commit 587528b

Please sign in to comment.