Skip to content

Commit

Permalink
test: add tests to Github API usage (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
jamestelfer authored Apr 25, 2024
1 parent 253c141 commit a268770
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 3 deletions.
3 changes: 2 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ type AuthorizationConfig struct {
}

type BuildkiteConfig struct {
Token string `env:"BUILDKITE_API_TOKEN, required"`
ApiURL string // internal only
Token string `env:"BUILDKITE_API_TOKEN, required"`
}

type GithubConfig struct {
ApiURL string // internal only
PrivateKey string `env:"GITHUB_APP_PRIVATE_KEY, required"`
ApplicationID int64 `env:"GITHUB_APP_ID, required"`
InstallationID int64 `env:"GITHUB_APP_INSTALLATION_ID, required"`
Expand Down
18 changes: 16 additions & 2 deletions internal/github/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ func New(cfg config.GithubConfig) (Client, error) {
},
)

// for testing use
if cfg.ApiURL != "" {
apiURL := cfg.ApiURL
if !strings.HasSuffix(apiURL, "/") {
apiURL += "/"
}

appInstallationTransport.BaseURL = cfg.ApiURL
u, _ := url.Parse(apiURL)
client.BaseURL = u
}

return Client{
client,
cfg.InstallationID,
Expand All @@ -52,8 +64,10 @@ func (c Client) CreateAccessToken(ctx context.Context, repositoryURL string) (st
return "", time.Time{}, err
}

qualifiedIdentifier, _ := strings.CutSuffix(u.Path, ".git")
_, repoName, _ := strings.Cut(qualifiedIdentifier[1:], "/")
// qualifiedIdentifier, _ := strings.CutSuffix(u.Path, ".git")
// _, repoName, _ := strings.Cut(qualifiedIdentifier[1:], "/")

_, repoName := RepoForURL(*u)

tok, r, err := c.client.Apps.CreateInstallationToken(ctx, c.installationID,
&github.InstallationTokenOptions{
Expand Down
134 changes: 134 additions & 0 deletions internal/github/token_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package github_test

import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"net/http"
"net/http/httptest"
"testing"
"time"

api "github.com/google/go-github/v61/github"
"github.com/jamestelfer/ghauth/internal/config"
"github.com/jamestelfer/ghauth/internal/github"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestCreateAccessToken_Succeeds(t *testing.T) {
router := http.NewServeMux()

expectedExpiry := time.Date(1980, 01, 01, 0, 0, 0, 0, time.UTC)
actualInstallation := "unknown"

router.HandleFunc("/app/installations/{installationID}/access_tokens", func(w http.ResponseWriter, r *http.Request) {
actualInstallation = r.PathValue("installationID")

JSON(w, &api.InstallationToken{
Token: api.String("expected-token"),
ExpiresAt: &api.Timestamp{Time: expectedExpiry},
})
})

svr := httptest.NewServer(router)
defer svr.Close()

// generate valid key for testing
key := generateKey(t)

gh, err := github.New(config.GithubConfig{
ApiURL: svr.URL,
PrivateKey: key,
ApplicationID: 10,
InstallationID: 20,
})
require.NoError(t, err)

token, expiry, err := gh.CreateAccessToken(context.Background(), "https://github.com/organization/repository")

require.NoError(t, err)
assert.Equal(t, "expected-token", token)
assert.Equal(t, expectedExpiry, expiry)
assert.Equal(t, "20", actualInstallation)
}

func TestCreateAccessToken_Fails_On_Invalid_URL(t *testing.T) {
router := http.NewServeMux()

router.HandleFunc("/app/installations/{installationID}/access_tokens", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTeapot)
})

svr := httptest.NewServer(router)
defer svr.Close()

// generate valid key for testing
key := generateKey(t)

gh, err := github.New(config.GithubConfig{
ApiURL: svr.URL,
PrivateKey: key,
ApplicationID: 10,
InstallationID: 20,
})
require.NoError(t, err)

_, _, err = gh.CreateAccessToken(context.Background(), "sch_eme://invalid_url/")

require.Error(t, err)
assert.ErrorContains(t, err, "first path segment in URL")
}

func TestCreateAccessToken_Fails_On_Failed_Request(t *testing.T) {
router := http.NewServeMux()

router.HandleFunc("/app/installations/{installationID}/access_tokens", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTeapot)
})

svr := httptest.NewServer(router)
defer svr.Close()

// generate valid key for testing
key := generateKey(t)

gh, err := github.New(config.GithubConfig{
ApiURL: svr.URL,
PrivateKey: key,
ApplicationID: 10,
InstallationID: 20,
})
require.NoError(t, err)

_, _, err = gh.CreateAccessToken(context.Background(), "https://dodgey")

require.Error(t, err)
assert.ErrorContains(t, err, ": 418")
}

func JSON(w http.ResponseWriter, payload any) {
w.Header().Set("Content-Type", "application/json")
res, _ := json.Marshal(payload)
_, _ = w.Write(res)
}

// generateKey creates and PEM encodes a valid RSA private key for testing.
func generateKey(t *testing.T) string {
t.Helper()

privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)

privateKeyPEM := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
}

key := pem.EncodeToMemory(privateKeyPEM)

return string(key)
}

0 comments on commit a268770

Please sign in to comment.