Skip to content

Commit

Permalink
Feat: add data source user (#361)
Browse files Browse the repository at this point in the history
* Feat: add data source user

* fixed a typo
  • Loading branch information
TomerHeber authored May 8, 2022
1 parent 494139a commit 08ca83b
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 0 deletions.
1 change: 1 addition & 0 deletions client/api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ type ApiClientInterface interface {
AssignAgentsToProjects(payload AssignProjectsAgentsAssignmentsPayload) (*ProjectsAgentsAssignments, error)
ProjectsAgentsAssignments() (*ProjectsAgentsAssignments, error)
Agents() ([]Agent, error)
Users() ([]OrganizationUser, error)
}

func NewApiClient(client http.HttpClientInterface) ApiClientInterface {
Expand Down
15 changes: 15 additions & 0 deletions client/api_client_mock.go

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

21 changes: 21 additions & 0 deletions client/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package client

type OrganizationUser struct {
User User `json:"user"`
Role string `json:"role"`
Status string `json:"status"`
}

func (client *ApiClient) Users() ([]OrganizationUser, error) {
organizationId, err := client.organizationId()
if err != nil {
return nil, err
}

var result []OrganizationUser
if err := client.http.Get("/organizations/"+organizationId+"/users", nil, &result); err != nil {
return nil, err
}

return result, nil
}
57 changes: 57 additions & 0 deletions client/user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package client_test

import (
"errors"

. "github.com/env0/terraform-provider-env0/client"
"github.com/golang/mock/gomock"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("User Client", func() {
mockUser := OrganizationUser{
User: User{
Email: "[email protected]",
UserId: "1",
},
}

Describe("Users", func() {
var users []OrganizationUser
mockUsers := []OrganizationUser{mockUser}
var err error

Describe("Success", func() {
BeforeEach(func() {
mockOrganizationIdCall(organizationId)

httpCall = mockHttpClient.EXPECT().
Get("/organizations/"+organizationId+"/users", gomock.Any(), gomock.Any()).
Do(func(path string, request interface{}, response *[]OrganizationUser) {
*response = mockUsers
}).Times(1)

users, err = apiClient.Users()
})

It("Should return the user", func() {
Expect(users).To(Equal(mockUsers))
})
})

Describe("Failure", func() {
It("On error from server return the error", func() {
mockOrganizationIdCall(organizationId)

expectedErr := errors.New("some error")
httpCall = mockHttpClient.EXPECT().
Get("/organizations/"+organizationId+"/users", gomock.Any(), gomock.Any()).
Times(1).
Return(expectedErr)
_, err = apiClient.Users()
Expect(expectedErr).Should(Equal(err))
})
})
})
})
64 changes: 64 additions & 0 deletions env0/data_user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package env0

import (
"context"

"github.com/env0/terraform-provider-env0/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataUser() *schema.Resource {
return &schema.Resource{
ReadContext: dataUserRead,

Schema: map[string]*schema.Schema{
"email": {
Type: schema.TypeString,
Description: "the email of the user",
Required: true,
},
"id": {
Type: schema.TypeString,
Description: "id of the user",
Computed: true,
},
},
}
}

func getUserByEmail(email string, meta interface{}) (*client.User, diag.Diagnostics) {
apiClient := meta.(client.ApiClientInterface)
organizationUsers, err := apiClient.Users()
if err != nil {
return nil, diag.Errorf("Could not get users: %v", err)
}

var usersByEmail []client.User
for _, organizationUser := range organizationUsers {
if organizationUser.User.Email == email {
usersByEmail = append(usersByEmail, organizationUser.User)
}
}

if len(usersByEmail) > 1 {
return nil, diag.Errorf("Found multiple users with the same email: %s", email)
}
if len(usersByEmail) == 0 {
return nil, diag.Errorf("Could not find a user with the email: %s", email)
}

return &usersByEmail[0], nil
}

func dataUserRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
email := d.Get("email").(string)
user, err := getUserByEmail(email, meta)
if err != nil {
return err
}

d.SetId(user.UserId)

return nil
}
87 changes: 87 additions & 0 deletions env0/data_user_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package env0

import (
"regexp"
"testing"

"github.com/env0/terraform-provider-env0/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestUserDataSource(t *testing.T) {
user := client.OrganizationUser{
User: client.User{
Email: "[email protected]",
UserId: "1",
},
}

otherUser := client.OrganizationUser{
User: client.User{
Email: "[email protected]",
UserId: "2",
},
}

resourceType := "env0_user"
resourceName := "test_user"
accessor := dataSourceAccessor(resourceType, resourceName)

getValidTestCase := func(input map[string]interface{}) resource.TestCase {
return resource.TestCase{
Steps: []resource.TestStep{
{
Config: dataSourceConfigCreate(resourceType, resourceName, input),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(accessor, "id", user.User.UserId),
resource.TestCheckResourceAttr(accessor, "email", user.User.Email),
),
},
},
}
}

getErrorTestCase := func(input map[string]interface{}, expectedError string) resource.TestCase {
return resource.TestCase{
Steps: []resource.TestStep{
{
Config: dataSourceConfigCreate(resourceType, resourceName, input),
ExpectError: regexp.MustCompile(expectedError),
},
},
}
}

mockUsersCall := func(returnValue []client.OrganizationUser) func(mockFunc *client.MockApiClientInterface) {
return func(mock *client.MockApiClientInterface) {
mock.EXPECT().Users().AnyTimes().Return(returnValue, nil)
}
}

t.Run("Get user by email", func(t *testing.T) {
input := map[string]interface{}{"email": user.User.Email}

runUnitTest(t,
getValidTestCase(input),
mockUsersCall([]client.OrganizationUser{user, otherUser}),
)
})

t.Run("Return error when user by email not found", func(t *testing.T) {
input := map[string]interface{}{"email": user.User.Email}

runUnitTest(t,
getErrorTestCase(input, "not find a user"),
mockUsersCall([]client.OrganizationUser{otherUser}),
)
})

t.Run("Throw error when multiple users by email found", func(t *testing.T) {
input := map[string]interface{}{"email": user.User.Email}

runUnitTest(t,
getErrorTestCase(input, "multiple users"),
mockUsersCall([]client.OrganizationUser{user, otherUser, user}),
)
})
}
1 change: 1 addition & 0 deletions env0/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func Provider(version string) plugin.ProviderFunc {
"env0_git_token": dataGitToken(),
"env0_api_key": dataApiKey(),
"env0_agents": dataAgents(),
"env0_user": dataUser(),
},
ResourcesMap: map[string]*schema.Resource{
"env0_project": resourceProject(),
Expand Down
7 changes: 7 additions & 0 deletions examples/data-sources/env0_user/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
data "env0_user" "user_by_email_example" {
email = "[email protected]"
}

output "user_id" {
value = data.env0_user.user_by_email_exmple.id
}

0 comments on commit 08ca83b

Please sign in to comment.