Skip to content

Commit

Permalink
Test the backup:list and backup:create commands
Browse files Browse the repository at this point in the history
  • Loading branch information
pjcdawkins committed Oct 16, 2024
1 parent 52f22e4 commit 1f4be19
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 31 deletions.
3 changes: 3 additions & 0 deletions internal/mockapi/api_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ func NewHandler(t *testing.T) *Handler {
h.Mux.Get("/projects/{id}", h.handleGetProject)
h.Mux.Patch("/projects/{id}", h.handlePatchProject)
h.Mux.Get("/projects/{id}/environments", h.handleListEnvironments)
h.Mux.Get("/projects/{project_id}/environments/{environment_id}", h.handleGetEnvironment)
h.Mux.Get("/projects/{project_id}/environments/{environment_id}/backups", h.handleListBackups)
h.Mux.Post("/projects/{project_id}/environments/{environment_id}/backups", h.handleCreateBackup)
h.Mux.Get("/projects/{project_id}/environments/{environment_id}/deployments/current", h.handleGetCurrentDeployment)
h.Mux.Get("/projects/{project_id}/user-access", h.handleProjectUserAccess)
h.Mux.Get("/ref/projects", h.handleProjectRefs)
Expand Down
106 changes: 106 additions & 0 deletions internal/mockapi/environments.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package mockapi

import (
"crypto/rand"
"encoding/json"
"net/http"
"slices"
"time"

"github.com/go-chi/chi/v5"
"github.com/oklog/ulid/v2"
"github.com/stretchr/testify/require"
)

func (h *Handler) handleListEnvironments(w http.ResponseWriter, req *http.Request) {
h.store.RLock()
defer h.store.RUnlock()
projectID := chi.URLParam(req, "id")
var envs []*Environment
for _, e := range h.store.environments {
if e.Project == projectID {
envs = append(envs, e)
}
}
_ = json.NewEncoder(w).Encode(envs)
}

func (h *Handler) handleGetEnvironment(w http.ResponseWriter, req *http.Request) {
h.store.RLock()
defer h.store.RUnlock()
projectID := chi.URLParam(req, "project_id")
environmentID := chi.URLParam(req, "environment_id")
for id, e := range h.store.environments {
if e.Project == projectID && id == environmentID {
_ = json.NewEncoder(w).Encode(e)
break
}
}
w.WriteHeader(http.StatusNotFound)
}

func (h *Handler) handleGetCurrentDeployment(w http.ResponseWriter, req *http.Request) {
h.store.RLock()
defer h.store.RUnlock()
projectID := chi.URLParam(req, "project_id")
environmentID := chi.URLParam(req, "environment_id")
var d *Deployment
for _, e := range h.store.environments {
if e.Project == projectID && e.ID == environmentID {
d = e.currentDeployment
}
}
if d == nil {
w.WriteHeader(http.StatusNotFound)
return
}
_ = json.NewEncoder(w).Encode(d)
}

func (h *Handler) handleCreateBackup(w http.ResponseWriter, req *http.Request) {
projectID := chi.URLParam(req, "project_id")
environmentID := chi.URLParam(req, "environment_id")
var options = struct {
Safe bool `json:"safe"`
}{}
require.NoError(h.t, json.NewDecoder(req.Body).Decode(&options))
backup := &Backup{
ID: ulid.MustNew(ulid.Now(), rand.Reader).String(),
EnvironmentID: environmentID,
Status: "CREATED",
Safe: options.Safe,
Restorable: true,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
h.addProjectBackup(projectID, backup)
_ = json.NewEncoder(w).Encode(backup)
}

func (h *Handler) handleListBackups(w http.ResponseWriter, req *http.Request) {
h.store.RLock()
defer h.store.RUnlock()
projectID := chi.URLParam(req, "project_id")
environmentID := chi.URLParam(req, "environment_id")
var backups []*Backup
if projectBackups, ok := h.store.projectBackups[projectID]; ok {
for _, b := range projectBackups {
if b.EnvironmentID == environmentID {
backups = append(backups, b)
}
}
}
// Sort backups in descending order by created date.
slices.SortFunc(backups, func(a, b *Backup) int { return -timeCompare(a.CreatedAt, b.CreatedAt) })
_ = json.NewEncoder(w).Encode(backups)
}

func timeCompare(a, b time.Time) int {
if a.Equal(b) {
return 0
}
if a.Before(b) {
return -1
}
return 1
}
16 changes: 16 additions & 0 deletions internal/mockapi/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,19 @@ type User struct {
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

type Backup struct {
ID string `json:"id"`
EnvironmentID string `json:"environment"`
Status string `json:"status"`
Safe bool `json:"safe"`
Restorable bool `json:"restorable"`
Automated bool `json:"automated"`
CommitID string `json:"commit_id"`
ExpiresAt time.Time `json:"expires_at"`

Links HalLinks `json:"_links"`

CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
31 changes: 0 additions & 31 deletions internal/mockapi/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,37 +57,6 @@ func (h *Handler) handlePatchProject(w http.ResponseWriter, req *http.Request) {
_ = json.NewEncoder(w).Encode(&patched)
}

func (h *Handler) handleListEnvironments(w http.ResponseWriter, req *http.Request) {
h.store.RLock()
defer h.store.RUnlock()
projectID := chi.URLParam(req, "id")
var envs []*Environment
for _, e := range h.store.environments {
if e.Project == projectID {
envs = append(envs, e)
}
}
_ = json.NewEncoder(w).Encode(envs)
}

func (h *Handler) handleGetCurrentDeployment(w http.ResponseWriter, req *http.Request) {
h.store.RLock()
defer h.store.RUnlock()
projectID := chi.URLParam(req, "project_id")
environmentID := chi.URLParam(req, "environment_id")
var d *Deployment
for _, e := range h.store.environments {
if e.Project == projectID && e.ID == environmentID {
d = e.currentDeployment
}
}
if d == nil {
w.WriteHeader(http.StatusNotFound)
return
}
_ = json.NewEncoder(w).Encode(d)
}

func (h *Handler) handleListRegions(w http.ResponseWriter, _ *http.Request) {
type region struct {
ID string `json:"id"`
Expand Down
28 changes: 28 additions & 0 deletions internal/mockapi/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ type store struct {
environments map[string]*Environment
subscriptions map[string]*Subscription
userGrants []*UserGrant

projectBackups map[string]map[string]*Backup
}

func (s *store) SetEnvironments(envs []*Environment) {
Expand Down Expand Up @@ -50,3 +52,29 @@ func (s *store) SetUserGrants(grants []*UserGrant) {
func (s *store) SetMyUser(u *User) {
s.myUser = u
}

func (s *store) SetProjectBackups(projectID string, backups []*Backup) {
s.Lock()
defer s.Unlock()
if s.projectBackups == nil {
s.projectBackups = make(map[string]map[string]*Backup)
}
if s.projectBackups[projectID] == nil {
s.projectBackups[projectID] = make(map[string]*Backup)
}
for _, b := range backups {
s.projectBackups[projectID][b.ID] = b
}
}

func (s *store) addProjectBackup(projectID string, backup *Backup) {
s.Lock()
defer s.Unlock()
if s.projectBackups == nil {
s.projectBackups = make(map[string]map[string]*Backup)
}
if s.projectBackups[projectID] == nil {
s.projectBackups[projectID] = make(map[string]*Backup)
}
s.projectBackups[projectID][backup.ID] = backup
}
114 changes: 114 additions & 0 deletions tests/backup_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package tests

import (
"net/http/httptest"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/platformsh/cli/internal/mockapi"
)

func TestBackupList(t *testing.T) {
authServer := mockapi.NewAuthServer(t)
defer authServer.Close()

apiHandler := mockapi.NewHandler(t)
apiServer := httptest.NewServer(apiHandler)
defer apiServer.Close()

apiHandler.SetProjects([]*mockapi.Project{
{
ID: mockProjectID,
DefaultBranch: "main",
Links: mockapi.MakeHALLinks(
"self=/projects/"+mockProjectID,
"environments=/projects/"+mockProjectID+"/environments",
),
},
})
main := makeEnv(mockProjectID, "main", "production", "active", nil)
main.Links["backups"] = mockapi.HALLink{HREF: "/projects/" + mockProjectID + "//environments/main/backups"}
apiHandler.SetEnvironments([]*mockapi.Environment{main})

created1, err := time.Parse(time.RFC3339, "2014-04-01T10:00:00+01:00")
require.NoError(t, err)
created2, err := time.Parse(time.RFC3339, "2015-04-01T10:00:00+01:00")
require.NoError(t, err)

apiHandler.SetProjectBackups(mockProjectID, []*mockapi.Backup{
{
ID: "123",
EnvironmentID: "main",
Status: "CREATED",
Safe: true,
Restorable: true,
Automated: false,
CommitID: "foo",
CreatedAt: created1,
},
{
ID: "456",
EnvironmentID: "main",
Status: "CREATED",
Safe: false,
Restorable: true,
Automated: true,
CommitID: "bar",
CreatedAt: created2,
},
})

run := runnerWithAuth(t, apiServer.URL, authServer.URL)

assert.Equal(t, strings.TrimLeft(`
+---------------------------+-----------+------------+
| Created | Backup ID | Restorable |
+---------------------------+-----------+------------+
| 2015-04-01T09:00:00+00:00 | 456 | true |
| 2014-04-01T09:00:00+00:00 | 123 | true |
+---------------------------+-----------+------------+
`, "\n"), run("backups", "-p", mockProjectID, "-e", "."))

assert.Equal(t, strings.TrimLeft(`
+---------------------------+-----------+------------+-----------+-----------+
| Created | Backup ID | Restorable | Automated | Commit ID |
+---------------------------+-----------+------------+-----------+-----------+
| 2015-04-01T09:00:00+00:00 | 456 | true | true | bar |
| 2014-04-01T09:00:00+00:00 | 123 | true | false | foo |
+---------------------------+-----------+------------+-----------+-----------+
`, "\n"), run("backups", "-p", mockProjectID, "-e", ".", "--columns", "+automated,commit_id"))
}

func TestBackupCreate(t *testing.T) {
authServer := mockapi.NewAuthServer(t)
defer authServer.Close()

apiHandler := mockapi.NewHandler(t)
apiServer := httptest.NewServer(apiHandler)
defer apiServer.Close()

apiHandler.SetProjects([]*mockapi.Project{
{
ID: mockProjectID,
DefaultBranch: "main",
Links: mockapi.MakeHALLinks(
"self=/projects/"+mockProjectID,
"environments=/projects/"+mockProjectID+"/environments",
),
},
})
main := makeEnv(mockProjectID, "main", "production", "active", nil)
main.Links["backups"] = mockapi.HALLink{HREF: "/projects/" + mockProjectID + "/environments/main//backups"}
main.Links["#backup"] = mockapi.HALLink{HREF: "/projects/" + mockProjectID + "/environments/main/backups"}
apiHandler.SetEnvironments([]*mockapi.Environment{main})

run := runnerWithAuth(t, apiServer.URL, authServer.URL)

run("backup", "-p", mockProjectID, "-e", ".")

assert.NotEmpty(t, run("backups", "-p", mockProjectID, "-e", "."))
}

0 comments on commit 1f4be19

Please sign in to comment.