796 lines
20 KiB
Go
796 lines
20 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"reflect"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/cli/cli/v2/internal/config"
|
|
"github.com/cli/cli/v2/internal/gh"
|
|
ghmock "github.com/cli/cli/v2/internal/gh/mock"
|
|
"github.com/cli/cli/v2/pkg/cmdutil"
|
|
)
|
|
|
|
func generateCodespaceList(start int, end int) []*Codespace {
|
|
codespacesList := []*Codespace{}
|
|
for i := start; i < end; i++ {
|
|
codespacesList = append(codespacesList, &Codespace{
|
|
Name: fmt.Sprintf("codespace-%d", i),
|
|
})
|
|
}
|
|
return codespacesList
|
|
}
|
|
|
|
func createFakeListEndpointServer(t *testing.T, initialTotal int, finalTotal int) *httptest.Server {
|
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/user/codespaces" {
|
|
t.Fatal("Incorrect path")
|
|
}
|
|
|
|
page := 1
|
|
if r.URL.Query().Get("page") != "" {
|
|
page, _ = strconv.Atoi(r.URL.Query().Get("page"))
|
|
}
|
|
|
|
per_page := 0
|
|
if r.URL.Query().Get("per_page") != "" {
|
|
per_page, _ = strconv.Atoi(r.URL.Query().Get("per_page"))
|
|
}
|
|
|
|
response := struct {
|
|
Codespaces []*Codespace `json:"codespaces"`
|
|
TotalCount int `json:"total_count"`
|
|
}{
|
|
Codespaces: []*Codespace{},
|
|
TotalCount: finalTotal,
|
|
}
|
|
|
|
switch page {
|
|
case 1:
|
|
response.Codespaces = generateCodespaceList(0, per_page)
|
|
response.TotalCount = initialTotal
|
|
w.Header().Set("Link", fmt.Sprintf(`<http://%[1]s/user/codespaces?page=3&per_page=%[2]d>; rel="last", <http://%[1]s/user/codespaces?page=2&per_page=%[2]d>; rel="next"`, r.Host, per_page))
|
|
case 2:
|
|
response.Codespaces = generateCodespaceList(per_page, per_page*2)
|
|
response.TotalCount = finalTotal
|
|
w.Header().Set("Link", fmt.Sprintf(`<http://%s/user/codespaces?page=3&per_page=%d>; rel="next"`, r.Host, per_page))
|
|
case 3:
|
|
response.Codespaces = generateCodespaceList(per_page*2, per_page*3-per_page/2)
|
|
response.TotalCount = finalTotal
|
|
default:
|
|
t.Fatal("Should not check extra page")
|
|
}
|
|
|
|
data, _ := json.Marshal(response)
|
|
fmt.Fprint(w, string(data))
|
|
}))
|
|
}
|
|
|
|
func createFakeCreateEndpointServer(t *testing.T, wantStatus int) *httptest.Server {
|
|
t.Helper()
|
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
// create endpoint
|
|
if r.URL.Path == "/user/codespaces" {
|
|
body := r.Body
|
|
if body == nil {
|
|
t.Fatal("No body")
|
|
}
|
|
defer body.Close()
|
|
|
|
var params startCreateRequest
|
|
err := json.NewDecoder(body).Decode(¶ms)
|
|
if err != nil {
|
|
t.Fatal("error:", err)
|
|
}
|
|
|
|
if params.RepositoryID != 1 {
|
|
t.Fatal("Expected RepositoryID to be 1. Got: ", params.RepositoryID)
|
|
}
|
|
|
|
if params.IdleTimeoutMinutes != 10 {
|
|
t.Fatal("Expected IdleTimeoutMinutes to be 10. Got: ", params.IdleTimeoutMinutes)
|
|
}
|
|
|
|
if *params.RetentionPeriodMinutes != 0 {
|
|
t.Fatal("Expected RetentionPeriodMinutes to be 0. Got: ", *params.RetentionPeriodMinutes)
|
|
}
|
|
|
|
response := Codespace{
|
|
Name: "codespace-1",
|
|
DisplayName: params.DisplayName,
|
|
}
|
|
|
|
if wantStatus == 0 {
|
|
wantStatus = http.StatusCreated
|
|
}
|
|
|
|
w.WriteHeader(wantStatus)
|
|
enc := json.NewEncoder(w)
|
|
_ = enc.Encode(&response)
|
|
return
|
|
}
|
|
|
|
// get endpoint hit for testing pending status
|
|
if r.URL.Path == "/user/codespaces/codespace-1" {
|
|
response := Codespace{
|
|
Name: "codespace-1",
|
|
State: CodespaceStateAvailable,
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
enc := json.NewEncoder(w)
|
|
_ = enc.Encode(&response)
|
|
return
|
|
}
|
|
|
|
t.Fatal("Incorrect path")
|
|
}))
|
|
}
|
|
|
|
func createHttpClient() (*http.Client, error) {
|
|
return &http.Client{}, nil
|
|
}
|
|
|
|
func TestNew_APIURL_dotcomConfig(t *testing.T) {
|
|
t.Setenv("GITHUB_API_URL", "")
|
|
t.Setenv("GITHUB_SERVER_URL", "https://github.com")
|
|
cfg := &ghmock.ConfigMock{
|
|
AuthenticationFunc: func() gh.AuthConfig {
|
|
return &config.AuthConfig{}
|
|
},
|
|
}
|
|
f := &cmdutil.Factory{
|
|
Config: func() (gh.Config, error) {
|
|
return cfg, nil
|
|
},
|
|
}
|
|
api := New(f)
|
|
|
|
if api.githubAPI != "https://api.github.com" {
|
|
t.Fatalf("expected https://api.github.com, got %s", api.githubAPI)
|
|
}
|
|
if len(cfg.AuthenticationCalls()) != 1 {
|
|
t.Fatalf("API url was not pulled from the config")
|
|
}
|
|
}
|
|
|
|
func TestNew_APIURL_customConfig(t *testing.T) {
|
|
t.Setenv("GITHUB_API_URL", "")
|
|
t.Setenv("GITHUB_SERVER_URL", "https://github.mycompany.com")
|
|
cfg := &ghmock.ConfigMock{
|
|
AuthenticationFunc: func() gh.AuthConfig {
|
|
authCfg := &config.AuthConfig{}
|
|
authCfg.SetDefaultHost("github.mycompany.com", "GH_HOST")
|
|
return authCfg
|
|
},
|
|
}
|
|
f := &cmdutil.Factory{
|
|
Config: func() (gh.Config, error) {
|
|
return cfg, nil
|
|
},
|
|
}
|
|
api := New(f)
|
|
|
|
if api.githubAPI != "https://github.mycompany.com/api/v3" {
|
|
t.Fatalf("expected https://github.mycompany.com/api/v3, got %s", api.githubAPI)
|
|
}
|
|
if len(cfg.AuthenticationCalls()) != 1 {
|
|
t.Fatalf("API url was not pulled from the config")
|
|
}
|
|
}
|
|
|
|
func TestNew_APIURL_env(t *testing.T) {
|
|
t.Setenv("GITHUB_API_URL", "https://api.mycompany.com")
|
|
t.Setenv("GITHUB_SERVER_URL", "https://mycompany.com")
|
|
cfg := &ghmock.ConfigMock{
|
|
AuthenticationFunc: func() gh.AuthConfig {
|
|
return &config.AuthConfig{}
|
|
},
|
|
}
|
|
f := &cmdutil.Factory{
|
|
Config: func() (gh.Config, error) {
|
|
return cfg, nil
|
|
},
|
|
}
|
|
api := New(f)
|
|
|
|
if api.githubAPI != "https://api.mycompany.com" {
|
|
t.Fatalf("expected https://api.mycompany.com, got %s", api.githubAPI)
|
|
}
|
|
if len(cfg.AuthenticationCalls()) != 0 {
|
|
t.Fatalf("Configuration was checked instead of using the GITHUB_API_URL environment variable")
|
|
}
|
|
}
|
|
|
|
func TestNew_APIURL_dotcomFallback(t *testing.T) {
|
|
t.Setenv("GITHUB_API_URL", "")
|
|
f := &cmdutil.Factory{
|
|
Config: func() (gh.Config, error) {
|
|
return nil, errors.New("Failed to load")
|
|
},
|
|
}
|
|
api := New(f)
|
|
|
|
if api.githubAPI != "https://api.github.com" {
|
|
t.Fatalf("expected https://api.github.com, got %s", api.githubAPI)
|
|
}
|
|
}
|
|
|
|
func TestNew_ServerURL_dotcomConfig(t *testing.T) {
|
|
t.Setenv("GITHUB_SERVER_URL", "")
|
|
t.Setenv("GITHUB_API_URL", "https://api.github.com")
|
|
cfg := &ghmock.ConfigMock{
|
|
AuthenticationFunc: func() gh.AuthConfig {
|
|
return &config.AuthConfig{}
|
|
},
|
|
}
|
|
f := &cmdutil.Factory{
|
|
Config: func() (gh.Config, error) {
|
|
return cfg, nil
|
|
},
|
|
}
|
|
api := New(f)
|
|
|
|
if api.githubServer != "https://github.com" {
|
|
t.Fatalf("expected https://github.com, got %s", api.githubServer)
|
|
}
|
|
if len(cfg.AuthenticationCalls()) != 1 {
|
|
t.Fatalf("Server url was not pulled from the config")
|
|
}
|
|
}
|
|
|
|
func TestNew_ServerURL_customConfig(t *testing.T) {
|
|
t.Setenv("GITHUB_SERVER_URL", "")
|
|
t.Setenv("GITHUB_API_URL", "https://github.mycompany.com/api/v3")
|
|
cfg := &ghmock.ConfigMock{
|
|
AuthenticationFunc: func() gh.AuthConfig {
|
|
authCfg := &config.AuthConfig{}
|
|
authCfg.SetDefaultHost("github.mycompany.com", "GH_HOST")
|
|
return authCfg
|
|
},
|
|
}
|
|
f := &cmdutil.Factory{
|
|
Config: func() (gh.Config, error) {
|
|
return cfg, nil
|
|
},
|
|
}
|
|
api := New(f)
|
|
|
|
if api.githubServer != "https://github.mycompany.com" {
|
|
t.Fatalf("expected https://github.mycompany.com, got %s", api.githubServer)
|
|
}
|
|
if len(cfg.AuthenticationCalls()) != 1 {
|
|
t.Fatalf("Server url was not pulled from the config")
|
|
}
|
|
}
|
|
|
|
func TestNew_ServerURL_env(t *testing.T) {
|
|
t.Setenv("GITHUB_SERVER_URL", "https://mycompany.com")
|
|
t.Setenv("GITHUB_API_URL", "https://api.mycompany.com")
|
|
cfg := &ghmock.ConfigMock{
|
|
AuthenticationFunc: func() gh.AuthConfig {
|
|
return &config.AuthConfig{}
|
|
},
|
|
}
|
|
f := &cmdutil.Factory{
|
|
Config: func() (gh.Config, error) {
|
|
return cfg, nil
|
|
},
|
|
}
|
|
api := New(f)
|
|
|
|
if api.githubServer != "https://mycompany.com" {
|
|
t.Fatalf("expected https://mycompany.com, got %s", api.githubServer)
|
|
}
|
|
if len(cfg.AuthenticationCalls()) != 0 {
|
|
t.Fatalf("Configuration was checked instead of using the GITHUB_SERVER_URL environment variable")
|
|
}
|
|
}
|
|
|
|
func TestNew_ServerURL_dotcomFallback(t *testing.T) {
|
|
t.Setenv("GITHUB_SERVER_URL", "")
|
|
f := &cmdutil.Factory{
|
|
Config: func() (gh.Config, error) {
|
|
return nil, errors.New("Failed to load")
|
|
},
|
|
}
|
|
api := New(f)
|
|
|
|
if api.githubServer != "https://github.com" {
|
|
t.Fatalf("expected https://github.com, got %s", api.githubServer)
|
|
}
|
|
}
|
|
|
|
func TestCreateCodespaces(t *testing.T) {
|
|
svr := createFakeCreateEndpointServer(t, http.StatusCreated)
|
|
defer svr.Close()
|
|
|
|
api := API{
|
|
githubAPI: svr.URL,
|
|
client: createHttpClient,
|
|
}
|
|
|
|
ctx := context.TODO()
|
|
retentionPeriod := 0
|
|
params := &CreateCodespaceParams{
|
|
RepositoryID: 1,
|
|
IdleTimeoutMinutes: 10,
|
|
RetentionPeriodMinutes: &retentionPeriod,
|
|
}
|
|
codespace, err := api.CreateCodespace(ctx, params)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if codespace.Name != "codespace-1" {
|
|
t.Fatalf("expected codespace-1, got %s", codespace.Name)
|
|
}
|
|
if codespace.DisplayName != "" {
|
|
t.Fatalf("expected display name empty, got %q", codespace.DisplayName)
|
|
}
|
|
}
|
|
|
|
func TestCreateCodespaces_displayName(t *testing.T) {
|
|
svr := createFakeCreateEndpointServer(t, http.StatusCreated)
|
|
defer svr.Close()
|
|
|
|
api := API{
|
|
githubAPI: svr.URL,
|
|
client: createHttpClient,
|
|
}
|
|
|
|
retentionPeriod := 0
|
|
codespace, err := api.CreateCodespace(context.Background(), &CreateCodespaceParams{
|
|
RepositoryID: 1,
|
|
IdleTimeoutMinutes: 10,
|
|
RetentionPeriodMinutes: &retentionPeriod,
|
|
DisplayName: "clucky cuckoo",
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if codespace.DisplayName != "clucky cuckoo" {
|
|
t.Fatalf("expected display name %q, got %q", "clucky cuckoo", codespace.DisplayName)
|
|
}
|
|
}
|
|
|
|
func TestCreateCodespaces_Pending(t *testing.T) {
|
|
svr := createFakeCreateEndpointServer(t, http.StatusAccepted)
|
|
defer svr.Close()
|
|
|
|
api := API{
|
|
githubAPI: svr.URL,
|
|
client: createHttpClient,
|
|
retryBackoff: 0,
|
|
}
|
|
|
|
ctx := context.TODO()
|
|
retentionPeriod := 0
|
|
params := &CreateCodespaceParams{
|
|
RepositoryID: 1,
|
|
IdleTimeoutMinutes: 10,
|
|
RetentionPeriodMinutes: &retentionPeriod,
|
|
}
|
|
codespace, err := api.CreateCodespace(ctx, params)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if codespace.Name != "codespace-1" {
|
|
t.Fatalf("expected codespace-1, got %s", codespace.Name)
|
|
}
|
|
}
|
|
|
|
func TestListCodespaces_limited(t *testing.T) {
|
|
svr := createFakeListEndpointServer(t, 200, 200)
|
|
defer svr.Close()
|
|
|
|
api := API{
|
|
githubAPI: svr.URL,
|
|
client: createHttpClient,
|
|
}
|
|
ctx := context.TODO()
|
|
codespaces, err := api.ListCodespaces(ctx, ListCodespacesOptions{Limit: 200})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(codespaces) != 200 {
|
|
t.Fatalf("expected 200 codespace, got %d", len(codespaces))
|
|
}
|
|
if codespaces[0].Name != "codespace-0" {
|
|
t.Fatalf("expected codespace-0, got %s", codespaces[0].Name)
|
|
}
|
|
if codespaces[199].Name != "codespace-199" {
|
|
t.Fatalf("expected codespace-199, got %s", codespaces[0].Name)
|
|
}
|
|
}
|
|
|
|
func TestListCodespaces_unlimited(t *testing.T) {
|
|
svr := createFakeListEndpointServer(t, 200, 200)
|
|
defer svr.Close()
|
|
|
|
api := API{
|
|
githubAPI: svr.URL,
|
|
client: createHttpClient,
|
|
}
|
|
ctx := context.TODO()
|
|
codespaces, err := api.ListCodespaces(ctx, ListCodespacesOptions{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(codespaces) != 250 {
|
|
t.Fatalf("expected 250 codespace, got %d", len(codespaces))
|
|
}
|
|
if codespaces[0].Name != "codespace-0" {
|
|
t.Fatalf("expected codespace-0, got %s", codespaces[0].Name)
|
|
}
|
|
if codespaces[249].Name != "codespace-249" {
|
|
t.Fatalf("expected codespace-249, got %s", codespaces[0].Name)
|
|
}
|
|
}
|
|
|
|
func TestGetRepoSuggestions(t *testing.T) {
|
|
tests := []struct {
|
|
searchText string // The input search string
|
|
queryText string // The wanted query string (based off searchText)
|
|
sort string // (Optional) The RepoSearchParameters.Sort param
|
|
maxRepos string // (Optional) The RepoSearchParameters.MaxRepos param
|
|
}{
|
|
{
|
|
searchText: "test",
|
|
queryText: "test",
|
|
},
|
|
{
|
|
searchText: "org/repo",
|
|
queryText: "repo user:org",
|
|
},
|
|
{
|
|
searchText: "org/repo/extra",
|
|
queryText: "repo/extra user:org",
|
|
},
|
|
{
|
|
searchText: "test",
|
|
queryText: "test",
|
|
sort: "stars",
|
|
maxRepos: "1000",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
runRepoSearchTest(t, tt.searchText, tt.queryText, tt.sort, tt.maxRepos)
|
|
}
|
|
}
|
|
|
|
func createFakeSearchReposServer(t *testing.T, wantSearchText string, wantSort string, wantPerPage string, responseRepos []*Repository) *httptest.Server {
|
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/search/repositories" {
|
|
t.Error("Incorrect path")
|
|
return
|
|
}
|
|
|
|
query := r.URL.Query()
|
|
got := fmt.Sprintf("q=%q sort=%s per_page=%s", query.Get("q"), query.Get("sort"), query.Get("per_page"))
|
|
want := fmt.Sprintf("q=%q sort=%s per_page=%s", wantSearchText+" in:name", wantSort, wantPerPage)
|
|
if got != want {
|
|
t.Errorf("for query, got %s, want %s", got, want)
|
|
return
|
|
}
|
|
|
|
response := struct {
|
|
Items []*Repository `json:"items"`
|
|
}{
|
|
responseRepos,
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(response); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}))
|
|
}
|
|
|
|
func runRepoSearchTest(t *testing.T, searchText, wantQueryText, wantSort, wantMaxRepos string) {
|
|
wantRepoNames := []string{"repo1", "repo2"}
|
|
|
|
apiResponseRepositories := make([]*Repository, 0)
|
|
for _, name := range wantRepoNames {
|
|
apiResponseRepositories = append(apiResponseRepositories, &Repository{FullName: name})
|
|
}
|
|
|
|
svr := createFakeSearchReposServer(t, wantQueryText, wantSort, wantMaxRepos, apiResponseRepositories)
|
|
defer svr.Close()
|
|
|
|
api := API{
|
|
githubAPI: svr.URL,
|
|
client: createHttpClient,
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
searchParameters := RepoSearchParameters{}
|
|
if len(wantSort) > 0 {
|
|
searchParameters.Sort = wantSort
|
|
}
|
|
if len(wantMaxRepos) > 0 {
|
|
searchParameters.MaxRepos, _ = strconv.Atoi(wantMaxRepos)
|
|
}
|
|
|
|
gotRepoNames, err := api.GetCodespaceRepoSuggestions(ctx, searchText, searchParameters)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
gotNamesStr := fmt.Sprintf("%v", gotRepoNames)
|
|
wantNamesStr := fmt.Sprintf("%v", wantRepoNames)
|
|
if gotNamesStr != wantNamesStr {
|
|
t.Fatalf("got repo names %s, want %s", gotNamesStr, wantNamesStr)
|
|
}
|
|
}
|
|
|
|
func TestRetries(t *testing.T) {
|
|
var callCount int
|
|
csName := "test_codespace"
|
|
handler := func(w http.ResponseWriter, r *http.Request) {
|
|
if callCount == 3 {
|
|
err := json.NewEncoder(w).Encode(Codespace{
|
|
Name: csName,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return
|
|
}
|
|
callCount++
|
|
w.WriteHeader(502)
|
|
}
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handler(w, r) }))
|
|
t.Cleanup(srv.Close)
|
|
a := &API{
|
|
githubAPI: srv.URL,
|
|
client: createHttpClient,
|
|
}
|
|
cs, err := a.GetCodespace(context.Background(), "test", false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if callCount != 3 {
|
|
t.Fatalf("expected at least 2 retries but got %d", callCount)
|
|
}
|
|
if cs.Name != csName {
|
|
t.Fatalf("expected codespace name to be %q but got %q", csName, cs.Name)
|
|
}
|
|
callCount = 0
|
|
handler = func(w http.ResponseWriter, _ *http.Request) {
|
|
callCount++
|
|
err := json.NewEncoder(w).Encode(Codespace{
|
|
Name: csName,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
cs, err = a.GetCodespace(context.Background(), "test", false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if callCount != 1 {
|
|
t.Fatalf("expected no retries but got %d calls", callCount)
|
|
}
|
|
if cs.Name != csName {
|
|
t.Fatalf("expected codespace name to be %q but got %q", csName, cs.Name)
|
|
}
|
|
}
|
|
|
|
func TestCodespace_ExportData(t *testing.T) {
|
|
type fields struct {
|
|
Name string
|
|
CreatedAt string
|
|
DisplayName string
|
|
LastUsedAt string
|
|
Owner User
|
|
Repository Repository
|
|
State string
|
|
GitStatus CodespaceGitStatus
|
|
Connection CodespaceConnection
|
|
Machine CodespaceMachine
|
|
}
|
|
type args struct {
|
|
fields []string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want map[string]interface{}
|
|
}{
|
|
{
|
|
name: "just name",
|
|
fields: fields{
|
|
Name: "test",
|
|
},
|
|
args: args{
|
|
fields: []string{"name"},
|
|
},
|
|
want: map[string]interface{}{
|
|
"name": "test",
|
|
},
|
|
},
|
|
{
|
|
name: "just owner",
|
|
fields: fields{
|
|
Owner: User{
|
|
Login: "test",
|
|
},
|
|
},
|
|
args: args{
|
|
fields: []string{"owner"},
|
|
},
|
|
want: map[string]interface{}{
|
|
"owner": "test",
|
|
},
|
|
},
|
|
{
|
|
name: "just machine",
|
|
fields: fields{
|
|
Machine: CodespaceMachine{
|
|
Name: "test",
|
|
},
|
|
},
|
|
args: args{
|
|
fields: []string{"machineName"},
|
|
},
|
|
want: map[string]interface{}{
|
|
"machineName": "test",
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := &Codespace{
|
|
Name: tt.fields.Name,
|
|
CreatedAt: tt.fields.CreatedAt,
|
|
DisplayName: tt.fields.DisplayName,
|
|
LastUsedAt: tt.fields.LastUsedAt,
|
|
Owner: tt.fields.Owner,
|
|
Repository: tt.fields.Repository,
|
|
State: tt.fields.State,
|
|
GitStatus: tt.fields.GitStatus,
|
|
Connection: tt.fields.Connection,
|
|
Machine: tt.fields.Machine,
|
|
}
|
|
if got := c.ExportData(tt.args.fields); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("Codespace.ExportData() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func createFakeEditServer(t *testing.T, codespaceName string) *httptest.Server {
|
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
checkPath := "/user/codespaces/" + codespaceName
|
|
|
|
if r.URL.Path != checkPath {
|
|
t.Fatal("Incorrect path")
|
|
}
|
|
|
|
if r.Method != http.MethodPatch {
|
|
t.Fatal("Incorrect method")
|
|
}
|
|
|
|
body := r.Body
|
|
if body == nil {
|
|
t.Fatal("No body")
|
|
}
|
|
defer body.Close()
|
|
|
|
var data map[string]interface{}
|
|
err := json.NewDecoder(body).Decode(&data)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if data["display_name"] != "changeTo" {
|
|
t.Fatal("Incorrect display name")
|
|
}
|
|
|
|
response := Codespace{
|
|
DisplayName: "changeTo",
|
|
}
|
|
|
|
responseData, _ := json.Marshal(response)
|
|
fmt.Fprint(w, string(responseData))
|
|
}))
|
|
}
|
|
|
|
func TestAPI_EditCodespace(t *testing.T) {
|
|
type args struct {
|
|
ctx context.Context
|
|
codespaceName string
|
|
params *EditCodespaceParams
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *Codespace
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "success",
|
|
args: args{
|
|
ctx: context.Background(),
|
|
codespaceName: "test",
|
|
params: &EditCodespaceParams{
|
|
DisplayName: "changeTo",
|
|
},
|
|
},
|
|
want: &Codespace{
|
|
DisplayName: "changeTo",
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
svr := createFakeEditServer(t, tt.args.codespaceName)
|
|
defer svr.Close()
|
|
|
|
a := &API{
|
|
client: createHttpClient,
|
|
githubAPI: svr.URL,
|
|
}
|
|
got, err := a.EditCodespace(tt.args.ctx, tt.args.codespaceName, tt.args.params)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("API.EditCodespace() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("API.EditCodespace() = %v, want %v", got.DisplayName, tt.want.DisplayName)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func createFakeEditPendingOpServer() *httptest.Server {
|
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == http.MethodPatch {
|
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
return
|
|
}
|
|
|
|
if r.Method == http.MethodGet {
|
|
response := Codespace{
|
|
PendingOperation: true,
|
|
PendingOperationDisabledReason: "Some pending operation",
|
|
}
|
|
|
|
responseData, _ := json.Marshal(response)
|
|
fmt.Fprint(w, string(responseData))
|
|
return
|
|
}
|
|
}))
|
|
}
|
|
|
|
func TestAPI_EditCodespacePendingOperation(t *testing.T) {
|
|
svr := createFakeEditPendingOpServer()
|
|
defer svr.Close()
|
|
|
|
a := &API{
|
|
client: createHttpClient,
|
|
githubAPI: svr.URL,
|
|
}
|
|
|
|
_, err := a.EditCodespace(context.Background(), "disabledCodespace", &EditCodespaceParams{DisplayName: "some silly name"})
|
|
if err == nil {
|
|
t.Error("Expected pending operation error, but got nothing")
|
|
}
|
|
if err.Error() != "codespace is disabled while it has a pending operation: Some pending operation" {
|
|
t.Errorf("Expected pending operation error, but got %v", err)
|
|
}
|
|
}
|