From 7078f9eec2636d3899d90a1cf7ddd8de115ddee7 Mon Sep 17 00:00:00 2001 From: Ricardo Zanini <1538000+ricardozanini@users.noreply.github.com> Date: Mon, 27 Jul 2020 11:33:41 -0300 Subject: [PATCH] Closes #12 - Introducing fake client (#17) * Closes #12 - Introducing fake client :see_no_evil: Signed-off-by: Ricardo Zanini * Add Maven Repository services fake Signed-off-by: Ricardo Zanini * Fixing Maven proxy repo bug Signed-off-by: Ricardo Zanini * Writing documentation Signed-off-by: Ricardo Zanini --- README.md | 39 +++++++++++++++++ nexus/client.go | 22 +++++++--- nexus/repositories_maven_group.go | 14 ++++-- nexus/repositories_maven_group_fake.go | 42 ++++++++++++++++++ nexus/repositories_maven_group_fake_test.go | 41 ++++++++++++++++++ nexus/repositories_maven_group_test.go | 7 +-- nexus/repositories_maven_proxy.go | 14 ++++-- nexus/repositories_maven_proxy_fake.go | 41 ++++++++++++++++++ nexus/repositories_maven_proxy_fake_test.go | 38 +++++++++++++++++ nexus/repositories_maven_proxy_test.go | 7 +-- nexus/users.go | 17 +++++--- nexus/users_fake.go | 47 +++++++++++++++++++++ nexus/users_fake_test.go | 40 ++++++++++++++++++ 13 files changed, 344 insertions(+), 25 deletions(-) create mode 100644 nexus/repositories_maven_group_fake.go create mode 100644 nexus/repositories_maven_group_fake_test.go create mode 100644 nexus/repositories_maven_proxy_fake.go create mode 100644 nexus/repositories_maven_proxy_fake_test.go create mode 100644 nexus/users_fake.go create mode 100644 nexus/users_fake_test.go diff --git a/README.md b/README.md index d4e5493..e6d78a6 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,45 @@ `aicura` is a client library for [Sonatype Nexus Manager v3 API](https://help.sonatype.com/repomanager3/rest-and-integration-api) written in GoLang. +## How to Use + +The most straightforward way to use this library is creating a new [`Client`](https://github.com/m88i/aicura/blob/master/nexus/client.go) and make calls to the API through services: + +```go +import "github.com/m88i/aicura/nexus" + +(...) + +// New client with default credentials +client := nexus.NewClient("http://localhost:8081").WithCredentials("admin", "admin123").Build() +user, err := client.UserService.GetUserByID("admin") +if err != nil { + return err +} +print(user.Name) +``` + +### Fake Client + +To use this library in your unit tests, create an instance of a "fake" `Client` instead: + +```go +import "github.com/m88i/aicura/nexus" + +(...) + +client := nexus.NewFakeClient() + +// all interfaces remain the same +user, err := client.UserService.GetUserByID("admin") +if err != nil { + return err +} +print(user.Name) //will print nothing since there's no user in the cache, call client.UserService.Add(user) first :) +``` + +The fake `Client` is backed up by hash maps, so all write and read operations will work like in real scenarios. + ## Development To run a local Nexus Server 3.x container with Podman: diff --git a/nexus/client.go b/nexus/client.go index bf6c30e..de55fa9 100644 --- a/nexus/client.go +++ b/nexus/client.go @@ -51,9 +51,9 @@ type Client struct { shared service // same instance shared among all services logger *zap.SugaredLogger - UserService *UserService - MavenProxyRepositoryService *MavenProxyRepositoryService - MavenGroupRepositoryService *MavenGroupRepositoryService + UserService UserService + MavenProxyRepositoryService MavenProxyRepositoryService + MavenGroupRepositoryService MavenGroupRepositoryService mavenRepositoryService *mavenRepositoryService } @@ -112,14 +112,24 @@ func NewClient(baseURL string) *ClientBuilder { c.shared.client = c // services builder - c.UserService = (*UserService)(&c.shared) - c.MavenProxyRepositoryService = (*MavenProxyRepositoryService)(&c.shared) - c.MavenGroupRepositoryService = (*MavenGroupRepositoryService)(&c.shared) + c.UserService = (*userService)(&c.shared) + c.MavenProxyRepositoryService = (*mavenProxyRepositoryService)(&c.shared) + c.MavenGroupRepositoryService = (*mavenGroupRepositoryService)(&c.shared) c.mavenRepositoryService = (*mavenRepositoryService)(&c.shared) return &ClientBuilder{c} } +// NewFakeClient creates a mocked client for testing purposes. +// It's backed up by hashmaps, so if you insert a user for instance, you can list, update, or delete +func NewFakeClient() *Client { + c := &Client{} + c.UserService = &userFakeService{} + c.MavenGroupRepositoryService = &mvnGroupFakeService{} + c.MavenProxyRepositoryService = &mvnProxyFakeService{} + return c +} + // NewDefaultClient creates a new raw, straight forward Nexus Client. For a more customizable client, use `NewClient` instead func NewDefaultClient(baseURL string) *Client { return NewClient(baseURL).Build() diff --git a/nexus/repositories_maven_group.go b/nexus/repositories_maven_group.go index 1c63c43..0b0b3a9 100644 --- a/nexus/repositories_maven_group.go +++ b/nexus/repositories_maven_group.go @@ -20,10 +20,16 @@ package nexus import "fmt" // MavenGroupRepositoryService service to handle all Maven Proxy Repositories operations -type MavenGroupRepositoryService service +type MavenGroupRepositoryService interface { + Update(repo MavenGroupRepository) error + List() ([]MavenGroupRepository, error) + GetRepoByName(name string) (*MavenGroupRepository, error) +} + +type mavenGroupRepositoryService service // Update updates a given Maven Group repository -func (m *MavenGroupRepositoryService) Update(repo MavenGroupRepository) error { +func (m *mavenGroupRepositoryService) Update(repo MavenGroupRepository) error { req, err := m.client.put(m.client.appendVersion(fmt.Sprintf("/repositories/maven/group/%s", repo.Name)), "", repo) if err != nil { return err @@ -33,14 +39,14 @@ func (m *MavenGroupRepositoryService) Update(repo MavenGroupRepository) error { } // List lists all maven repositories from the Nexus Server -func (m *MavenGroupRepositoryService) List() ([]MavenGroupRepository, error) { +func (m *mavenGroupRepositoryService) List() ([]MavenGroupRepository, error) { repositories := []MavenGroupRepository{} err := m.client.mavenRepositoryService.list(RepositoryTypeGroup, &repositories) return repositories, err } // GetRepoByName gets the repository by name or nil if not found -func (m *MavenGroupRepositoryService) GetRepoByName(name string) (*MavenGroupRepository, error) { +func (m *mavenGroupRepositoryService) GetRepoByName(name string) (*MavenGroupRepository, error) { repos, err := m.List() if err != nil { return nil, err diff --git a/nexus/repositories_maven_group_fake.go b/nexus/repositories_maven_group_fake.go new file mode 100644 index 0000000..9cfe31c --- /dev/null +++ b/nexus/repositories_maven_group_fake.go @@ -0,0 +1,42 @@ +// Copyright 2020 Aicura Nexus Client and/or its authors +// +// This file is part of Aicura Nexus Client. +// +// Aicura Nexus Client is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Aicura Nexus Client is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Aicura Nexus Client. If not, see . + +package nexus + +type mvnGroupFakeService struct{} + +var mvnGrpFake = make(map[string]*MavenGroupRepository) + +func (m *mvnGroupFakeService) Update(repo MavenGroupRepository) error { + if mvnGrpFake[repo.Name] == nil { + return nil + } + mvnGrpFake[repo.Name] = &repo + return nil +} + +func (m *mvnGroupFakeService) List() ([]MavenGroupRepository, error) { + repos := make([]MavenGroupRepository, 0) + for _, repo := range mvnGrpFake { + repos = append(repos, *repo) + } + return repos, nil +} + +func (m *mvnGroupFakeService) GetRepoByName(name string) (*MavenGroupRepository, error) { + return mvnGrpFake[name], nil +} diff --git a/nexus/repositories_maven_group_fake_test.go b/nexus/repositories_maven_group_fake_test.go new file mode 100644 index 0000000..6fc087c --- /dev/null +++ b/nexus/repositories_maven_group_fake_test.go @@ -0,0 +1,41 @@ +// Copyright 2020 Aicura Nexus Client and/or its authors +// +// This file is part of Aicura Nexus Client. +// +// Aicura Nexus Client is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Aicura Nexus Client is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Aicura Nexus Client. If not, see . + +package nexus + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMvnGroupServiceFakeCheck(t *testing.T) { + client := NewFakeClient() + repos, err := client.MavenGroupRepositoryService.List() + assert.NoError(t, err) + assert.Empty(t, repos) + group := MavenGroupRepository{ + Repository: Repository{ + Name: "maven-public", + }, + } + err = client.MavenGroupRepositoryService.Update(group) + assert.NoError(t, err) + newGroup, err := client.MavenGroupRepositoryService.GetRepoByName("maven-public") + assert.NoError(t, err) + assert.Nil(t, newGroup) +} diff --git a/nexus/repositories_maven_group_test.go b/nexus/repositories_maven_group_test.go index dd3b425..0958fc3 100644 --- a/nexus/repositories_maven_group_test.go +++ b/nexus/repositories_maven_group_test.go @@ -33,11 +33,12 @@ func TestMavenGroupRepositoryService_Update(t *testing.T) { if len(repos) > 0 { //sanity check to not panic s = newServerWrapper(t).Build() - apacheMavenRepoMockData.Name = apacheMavenRepoMockData.Name + "3" - err := s.Client().MavenProxyRepositoryService.Add(apacheMavenRepoMockData) + repo := apacheMavenRepoMockData + repo.Name = repo.Name + "3" + err := s.Client().MavenProxyRepositoryService.Add(repo) assert.NoError(t, err) - repos[0].Group.MemberNames = append(repos[0].Group.MemberNames, apacheMavenRepoMockData.Name) + repos[0].Group.MemberNames = append(repos[0].Group.MemberNames, repo.Name) err = s.Client().MavenGroupRepositoryService.Update(repos[0]) assert.NoError(t, err) } diff --git a/nexus/repositories_maven_proxy.go b/nexus/repositories_maven_proxy.go index b9e9ebd..9435d42 100644 --- a/nexus/repositories_maven_proxy.go +++ b/nexus/repositories_maven_proxy.go @@ -24,10 +24,16 @@ import ( ) // MavenProxyRepositoryService service to handle all Maven Proxy Repositories operations -type MavenProxyRepositoryService service +type MavenProxyRepositoryService interface { + Add(repositories ...MavenProxyRepository) error + List() ([]MavenProxyRepository, error) + GetRepoByName(name string) (*MavenProxyRepository, error) +} + +type mavenProxyRepositoryService service // Add adds new Proxy Maven repositories to the Nexus Server -func (m *MavenProxyRepositoryService) Add(repositories ...MavenProxyRepository) error { +func (m *mavenProxyRepositoryService) Add(repositories ...MavenProxyRepository) error { if len(repositories) == 0 { m.logger.Warnf("Called AddRepository with no repositories to add") return nil @@ -47,14 +53,14 @@ func (m *MavenProxyRepositoryService) Add(repositories ...MavenProxyRepository) } // List lists all maven repositories from the Nexus Server -func (m *MavenProxyRepositoryService) List() ([]MavenProxyRepository, error) { +func (m *mavenProxyRepositoryService) List() ([]MavenProxyRepository, error) { repositories := []MavenProxyRepository{} err := m.client.mavenRepositoryService.list(RepositoryTypeProxy, &repositories) return repositories, err } // GetRepoByName gets the repository by name or nil if not found -func (m *MavenProxyRepositoryService) GetRepoByName(name string) (*MavenProxyRepository, error) { +func (m *mavenProxyRepositoryService) GetRepoByName(name string) (*MavenProxyRepository, error) { repos, err := m.List() if err != nil { return nil, err diff --git a/nexus/repositories_maven_proxy_fake.go b/nexus/repositories_maven_proxy_fake.go new file mode 100644 index 0000000..94b4f45 --- /dev/null +++ b/nexus/repositories_maven_proxy_fake.go @@ -0,0 +1,41 @@ +// Copyright 2020 Aicura Nexus Client and/or its authors +// +// This file is part of Aicura Nexus Client. +// +// Aicura Nexus Client is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Aicura Nexus Client is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Aicura Nexus Client. If not, see . + +package nexus + +type mvnProxyFakeService struct{} + +var mvnProxyFake = make(map[string]*MavenProxyRepository) + +func (m *mvnProxyFakeService) Add(repositories ...MavenProxyRepository) error { + for _, repo := range repositories { + mvnProxyFake[repo.Name] = &repo + } + return nil +} + +func (m *mvnProxyFakeService) List() ([]MavenProxyRepository, error) { + repos := make([]MavenProxyRepository, 0) + for _, repo := range mvnProxyFake { + repos = append(repos, *repo) + } + return repos, nil +} + +func (m *mvnProxyFakeService) GetRepoByName(name string) (*MavenProxyRepository, error) { + return mvnProxyFake[name], nil +} diff --git a/nexus/repositories_maven_proxy_fake_test.go b/nexus/repositories_maven_proxy_fake_test.go new file mode 100644 index 0000000..c3e3ab1 --- /dev/null +++ b/nexus/repositories_maven_proxy_fake_test.go @@ -0,0 +1,38 @@ +// Copyright 2020 Aicura Nexus Client and/or its authors +// +// This file is part of Aicura Nexus Client. +// +// Aicura Nexus Client is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Aicura Nexus Client is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Aicura Nexus Client. If not, see . + +package nexus + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMvnProxyServiceFakeCheck(t *testing.T) { + client := NewFakeClient() + repo := apacheMavenRepoMockData + err := client.MavenProxyRepositoryService.Add(repo) + assert.NoError(t, err) + newRepo, err := client.MavenProxyRepositoryService.GetRepoByName(repo.Name) + assert.NoError(t, err) + assert.NotNil(t, newRepo) + assert.Equal(t, "apache", newRepo.Name) + repos, err := client.MavenProxyRepositoryService.List() + assert.NoError(t, err) + assert.Len(t, repos, 1) +} diff --git a/nexus/repositories_maven_proxy_test.go b/nexus/repositories_maven_proxy_test.go index ebe1945..2669265 100644 --- a/nexus/repositories_maven_proxy_test.go +++ b/nexus/repositories_maven_proxy_test.go @@ -51,15 +51,16 @@ func TestMavenProxyRepositoryService_Add(t *testing.T) { s := newServerWrapper(t).Build() defer s.teardown() client := s.Client() - apacheMavenRepoMockData.Name = apacheMavenRepoMockData.Name + "2" - err := client.MavenProxyRepositoryService.Add(apacheMavenRepoMockData) + newRepo := apacheMavenRepoMockData + newRepo.Name = newRepo.Name + "2" + err := client.MavenProxyRepositoryService.Add(newRepo) assert.NoError(t, err) assertRemote(t, func() error { // on remote testing we can check if the repository was correctly inserted repos, err := client.MavenProxyRepositoryService.List() assert.NotEmpty(t, repos) for _, repo := range repos { - if repo.Name == apacheMavenRepoMockData.Name { + if repo.Name == newRepo.Name { assert.Equal(t, "https://repo.maven.apache.org/maven2/", repo.Proxy.RemoteURL) return err } diff --git a/nexus/users.go b/nexus/users.go index cd1a2d7..b023eb7 100644 --- a/nexus/users.go +++ b/nexus/users.go @@ -37,10 +37,17 @@ type User struct { } // UserService contains all operations related to the User domain -type UserService service +type UserService interface { + List() ([]User, error) + Update(user User) error + GetUserByID(userID string) (*User, error) + Add(user User) error +} + +type userService service // List Retrieves all users from default source -func (u *UserService) List() ([]User, error) { +func (u *userService) List() ([]User, error) { req, err := u.client.get(u.client.appendVersion("/security/users"), "") if err != nil { return nil, err @@ -51,7 +58,7 @@ func (u *UserService) List() ([]User, error) { } // Update persists a new version of an existing user on the Nexus server -func (u *UserService) Update(user User) error { +func (u *userService) Update(user User) error { req, err := u.client.put(u.client.appendVersion(fmt.Sprintf("/security/users/%s", user.UserID)), "", user) if err != nil { return err @@ -61,7 +68,7 @@ func (u *UserService) Update(user User) error { } // GetUserByID Gets the user by it's id (authentication username) -func (u *UserService) GetUserByID(userID string) (*User, error) { +func (u *userService) GetUserByID(userID string) (*User, error) { parsedURL, err := url.ParseQuery("userId=" + userID) if err != nil { return nil, err @@ -79,7 +86,7 @@ func (u *UserService) GetUserByID(userID string) (*User, error) { } // Add adds a new user in the Nexus Server. It's worth calling `GetUserByID` to verify if the desired user is not present. -func (u *UserService) Add(user User) error { +func (u *userService) Add(user User) error { req, err := u.client.post(u.client.appendVersion("/security/users"), "", user) if err != nil { return err diff --git a/nexus/users_fake.go b/nexus/users_fake.go new file mode 100644 index 0000000..e174652 --- /dev/null +++ b/nexus/users_fake.go @@ -0,0 +1,47 @@ +// Copyright 2020 Aicura Nexus Client and/or its authors +// +// This file is part of Aicura Nexus Client. +// +// Aicura Nexus Client is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Aicura Nexus Client is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Aicura Nexus Client. If not, see . + +package nexus + +type userFakeService struct{} + +var usersFake = make(map[string]*User) + +func (u *userFakeService) List() ([]User, error) { + users := make([]User, 0) + for _, user := range usersFake { + users = append(users, *user) + } + return users, nil +} + +func (u *userFakeService) Update(user User) error { + if usersFake[user.UserID] == nil { + return nil + } + usersFake[user.UserID] = &user + return nil +} + +func (u *userFakeService) GetUserByID(userID string) (*User, error) { + return usersFake[userID], nil +} + +func (u *userFakeService) Add(user User) error { + usersFake[user.UserID] = &user + return nil +} diff --git a/nexus/users_fake_test.go b/nexus/users_fake_test.go new file mode 100644 index 0000000..61bb587 --- /dev/null +++ b/nexus/users_fake_test.go @@ -0,0 +1,40 @@ +// Copyright 2020 Aicura Nexus Client and/or its authors +// +// This file is part of Aicura Nexus Client. +// +// Aicura Nexus Client is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Aicura Nexus Client is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with Aicura Nexus Client. If not, see . + +package nexus + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUserFakeCheck(t *testing.T) { + user := defaultUser + client := NewFakeClient() + err := client.UserService.Add(user) + assert.NoError(t, err) + users, err := client.UserService.List() + assert.NoError(t, err) + assert.Len(t, users, 1) + user.Email = "user@fake.com" + err = client.UserService.Update(user) + assert.NoError(t, err) + newUser, err := client.UserService.GetUserByID(user.UserID) + assert.NoError(t, err) + assert.Equal(t, "user@fake.com", newUser.Email) +}