Refactor actions.Client with options to help extensibility (#2193)
This commit is contained in:
parent
282f2dd09c
commit
3327f620fb
|
|
@ -84,7 +84,13 @@ func run(rc RunnerScaleSetListenerConfig, logger logr.Logger) error {
|
|||
}
|
||||
}
|
||||
|
||||
actionsServiceClient, err := actions.NewClient(ctx, rc.ConfigureUrl, creds, fmt.Sprintf("actions-runner-controller/%s", build.Version), logger)
|
||||
actionsServiceClient, err := actions.NewClient(
|
||||
ctx,
|
||||
rc.ConfigureUrl,
|
||||
creds,
|
||||
actions.WithUserAgent(fmt.Sprintf("actions-runner-controller/%s", build.Version)),
|
||||
actions.WithLogger(logger),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create an Actions Service client: %w", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
package actions_test
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// newActionsServer returns a new httptest.Server that handles the
|
||||
// authentication requests neeeded to create a new client. Any requests not
|
||||
// made to the /actions/runners/registration-token or
|
||||
// /actions/runner-registration endpoints will be handled by the provided
|
||||
// handler. The returned server is started and will be automatically closed
|
||||
// when the test ends.
|
||||
func newActionsServer(t *testing.T, handler http.Handler) *actionsServer {
|
||||
var u string
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// handle getRunnerRegistrationToken
|
||||
if strings.HasSuffix(r.URL.Path, "/runners/registration-token") {
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte(`{"token":"token"}`))
|
||||
return
|
||||
}
|
||||
|
||||
// handle getActionsServiceAdminConnection
|
||||
if strings.HasSuffix(r.URL.Path, "/actions/runner-registration") {
|
||||
claims := &jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now().Add(-1 * time.Minute)),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(1 * time.Minute)),
|
||||
Issuer: "123",
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||
privateKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(samplePrivateKey))
|
||||
require.NoError(t, err)
|
||||
tokenString, err := token.SignedString(privateKey)
|
||||
require.NoError(t, err)
|
||||
w.Write([]byte(`{"url":"` + u + `","token":"` + tokenString + `"}`))
|
||||
return
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}))
|
||||
|
||||
u = server.URL
|
||||
|
||||
t.Cleanup(func() {
|
||||
server.Close()
|
||||
})
|
||||
|
||||
return &actionsServer{server}
|
||||
}
|
||||
|
||||
type actionsServer struct {
|
||||
*httptest.Server
|
||||
}
|
||||
|
||||
func (s *actionsServer) configURLForOrg(org string) string {
|
||||
return s.URL + "/" + org
|
||||
}
|
||||
|
||||
const samplePrivateKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICWgIBAAKBgHXfRT9cv9UY9fAAD4+1RshpfSSZe277urfEmPfX3/Og9zJYRk//
|
||||
CZrJVD1CaBZDiIyQsNEzjta7r4UsqWdFOggiNN2E7ZTFQjMSaFkVgrzHqWuiaCBf
|
||||
/BjbKPn4SMDmTzHvIe7Nel76hBdCaVgu6mYCW5jmuSH5qz/yR1U1J/WJAgMBAAEC
|
||||
gYARWGWsSU3BYgbu5lNj5l0gKMXNmPhdAJYdbMTF0/KUu18k/XB7XSBgsre+vALt
|
||||
I8r4RGKApoGif8P4aPYUyE8dqA1bh0X3Fj1TCz28qoUL5//dA+pigCRS20H7HM3C
|
||||
ojoqF7+F+4F2sXmzFNd1NgY5RxFPYosTT7OnUiFuu2IisQJBALnMLe09LBnjuHXR
|
||||
xxR65DDNxWPQLBjW3dL+ubLcwr7922l6ZIQsVjdeE0ItEUVRjjJ9/B/Jq9VJ/Lw4
|
||||
g9LCkkMCQQCiaM2f7nYmGivPo9hlAbq5lcGJ5CCYFfeeYzTxMqum7Mbqe4kk5lgb
|
||||
X6gWd0Izg2nGdAEe/97DClO6VpKcPbpDAkBTR/JOJN1fvXMxXJaf13XxakrQMr+R
|
||||
Yr6LlSInykyAz8lJvlLP7A+5QbHgN9NF/wh+GXqpxPwA3ukqdSqhjhWBAkBn6mDv
|
||||
HPgR5xrzL6XM8y9TgaOlJAdK6HtYp6d/UOmN0+Butf6JUq07TphRT5tXNJVgemch
|
||||
O5x/9UKfbrc+KyzbAkAo97TfFC+mZhU1N5fFelaRu4ikPxlp642KRUSkOh8GEkNf
|
||||
jQ97eJWiWtDcsMUhcZgoB5ydHcFlrBIn6oBcpge5
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
|
|
@ -62,8 +63,8 @@ type Client struct {
|
|||
ActionsServiceAdminTokenExpiresAt *time.Time
|
||||
ActionsServiceURL *string
|
||||
|
||||
RetryMax *int
|
||||
RetryWaitMax *time.Duration
|
||||
retryMax int
|
||||
retryWaitMax time.Duration
|
||||
|
||||
creds *ActionsAuth
|
||||
githubConfigURL string
|
||||
|
|
@ -71,14 +72,57 @@ type Client struct {
|
|||
userAgent string
|
||||
}
|
||||
|
||||
func NewClient(ctx context.Context, githubConfigURL string, creds *ActionsAuth, userAgent string, logger logr.Logger) (ActionsService, error) {
|
||||
type ClientOption func(*Client)
|
||||
|
||||
func WithUserAgent(userAgent string) ClientOption {
|
||||
return func(c *Client) {
|
||||
c.userAgent = userAgent
|
||||
}
|
||||
}
|
||||
|
||||
func WithLogger(logger logr.Logger) ClientOption {
|
||||
return func(c *Client) {
|
||||
c.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func WithRetryMax(retryMax int) ClientOption {
|
||||
return func(c *Client) {
|
||||
c.retryMax = retryMax
|
||||
}
|
||||
}
|
||||
|
||||
func WithRetryWaitMax(retryWaitMax time.Duration) ClientOption {
|
||||
return func(c *Client) {
|
||||
c.retryWaitMax = retryWaitMax
|
||||
}
|
||||
}
|
||||
|
||||
func NewClient(ctx context.Context, githubConfigURL string, creds *ActionsAuth, options ...ClientOption) (ActionsService, error) {
|
||||
ac := &Client{
|
||||
creds: creds,
|
||||
githubConfigURL: githubConfigURL,
|
||||
logger: logger,
|
||||
userAgent: userAgent,
|
||||
logger: logr.Discard(),
|
||||
|
||||
// retryablehttp defaults
|
||||
retryMax: 4,
|
||||
retryWaitMax: 30 * time.Second,
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
option(ac)
|
||||
}
|
||||
|
||||
retryClient := retryablehttp.NewClient()
|
||||
|
||||
// TODO: this silences retryclient default logger, do we want to provide one
|
||||
// instead? by default retryablehttp logs all requests to stderr
|
||||
retryClient.Logger = log.New(io.Discard, "", log.LstdFlags)
|
||||
|
||||
retryClient.RetryMax = ac.retryMax
|
||||
retryClient.RetryWaitMax = ac.retryWaitMax
|
||||
ac.Client = retryClient.StandardClient()
|
||||
|
||||
rt, err := ac.getRunnerRegistrationToken(ctx, githubConfigURL, *creds)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get runner registration token: %w", err)
|
||||
|
|
@ -121,9 +165,7 @@ func (c *Client) GetRunnerScaleSet(ctx context.Context, runnerScaleSetName strin
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -165,9 +207,7 @@ func (c *Client) GetRunnerScaleSetById(ctx context.Context, runnerScaleSetId int
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -182,7 +222,6 @@ func (c *Client) GetRunnerScaleSetById(ctx context.Context, runnerScaleSetId int
|
|||
return nil, err
|
||||
}
|
||||
return runnerScaleSet, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *Client) GetRunnerGroupByName(ctx context.Context, runnerGroup string) (*RunnerGroup, error) {
|
||||
|
|
@ -204,9 +243,7 @@ func (c *Client) GetRunnerGroupByName(ctx context.Context, runnerGroup string) (
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -260,9 +297,7 @@ func (c *Client) CreateRunnerScaleSet(ctx context.Context, runnerScaleSet *Runne
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -278,49 +313,6 @@ func (c *Client) CreateRunnerScaleSet(ctx context.Context, runnerScaleSet *Runne
|
|||
return createdRunnerScaleSet, nil
|
||||
}
|
||||
|
||||
func (c *Client) UpdateRunnerScaleSet(ctx context.Context, runnerScaleSetId int, runnerScaleSet *RunnerScaleSet) (*RunnerScaleSet, error) {
|
||||
u := fmt.Sprintf("%s/%s/%d?api-version=6.0-preview", *c.ActionsServiceURL, scaleSetEndpoint, runnerScaleSetId)
|
||||
|
||||
if err := c.refreshTokenIfNeeded(ctx); err != nil {
|
||||
return nil, fmt.Errorf("failed to refresh admin token if needed: %w", err)
|
||||
}
|
||||
|
||||
body, err := json.Marshal(runnerScaleSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPut, u, bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", *c.ActionsServiceAdminToken))
|
||||
|
||||
if c.userAgent != "" {
|
||||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, ParseActionsErrorFromResponse(resp)
|
||||
}
|
||||
|
||||
var createdRunnerScaleSet *RunnerScaleSet
|
||||
err = unmarshalBody(resp, &createdRunnerScaleSet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return createdRunnerScaleSet, nil
|
||||
}
|
||||
|
||||
func (c *Client) DeleteRunnerScaleSet(ctx context.Context, runnerScaleSetId int) error {
|
||||
u := fmt.Sprintf("%s/%s/%d?api-version=6.0-preview", *c.ActionsServiceURL, scaleSetEndpoint, runnerScaleSetId)
|
||||
|
||||
|
|
@ -340,9 +332,7 @@ func (c *Client) DeleteRunnerScaleSet(ctx context.Context, runnerScaleSetId int)
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -372,9 +362,7 @@ func (c *Client) GetMessage(ctx context.Context, messageQueueUrl, messageQueueAc
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -425,9 +413,7 @@ func (c *Client) DeleteMessage(ctx context.Context, messageQueueUrl, messageQueu
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -497,9 +483,7 @@ func (c *Client) doSessionRequest(ctx context.Context, method, url string, reque
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -542,9 +526,7 @@ func (c *Client) AcquireJobs(ctx context.Context, runnerScaleSetId int, messageQ
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -581,9 +563,7 @@ func (c *Client) GetAcquirableJobs(ctx context.Context, runnerScaleSetId int) (*
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -629,9 +609,7 @@ func (c *Client) GenerateJitRunnerConfig(ctx context.Context, jitRunnerSetting *
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -667,9 +645,7 @@ func (c *Client) GetRunner(ctx context.Context, runnerId int64) (*RunnerReferenc
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -705,9 +681,7 @@ func (c *Client) GetRunnerByName(ctx context.Context, runnerName string) (*Runne
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -752,9 +726,7 @@ func (c *Client) RemoveRunner(ctx context.Context, runnerId int64) error {
|
|||
req.Header.Set("User-Agent", c.userAgent)
|
||||
}
|
||||
|
||||
httpClient := c.getHTTPClient()
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1012,24 +984,6 @@ func createJWTForGitHubApp(appAuth *GitHubAppAuth) (string, error) {
|
|||
return token.SignedString(privateKey)
|
||||
}
|
||||
|
||||
func (c *Client) getHTTPClient() *http.Client {
|
||||
if c.Client != nil {
|
||||
return c.Client
|
||||
}
|
||||
|
||||
retryClient := retryablehttp.NewClient()
|
||||
|
||||
if c.RetryMax != nil {
|
||||
retryClient.RetryMax = *c.RetryMax
|
||||
}
|
||||
|
||||
if c.RetryWaitMax != nil {
|
||||
retryClient.RetryWaitMax = *c.RetryWaitMax
|
||||
}
|
||||
|
||||
return retryClient.StandardClient()
|
||||
}
|
||||
|
||||
func unmarshalBody(response *http.Response, v interface{}) (err error) {
|
||||
if response != nil && response.Body != nil {
|
||||
var err error
|
||||
|
|
|
|||
|
|
@ -3,73 +3,60 @@ package actions_test
|
|||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/actions/actions-runner-controller/github/actions"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGenerateJitRunnerConfig(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
t.Run("Get JIT Config for Runner", func(t *testing.T) {
|
||||
name := "Get JIT Config for Runner"
|
||||
want := &actions.RunnerScaleSetJitRunnerConfig{}
|
||||
response := []byte(`{"count":1,"value":[{"id":1,"name":"scale-set-name"}]}`)
|
||||
|
||||
runnerSettings := &actions.RunnerScaleSetJitRunnerSetting{}
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Write(response)
|
||||
}))
|
||||
defer s.Close()
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
|
||||
got, err := actionsClient.GenerateJitRunnerConfig(context.Background(), runnerSettings, 1)
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateJitRunnerConfig got unexepected error, %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("GenerateJitRunnerConfig(%v) mismatch (-want +got):\n%s", name, diff)
|
||||
}
|
||||
got, err := client.GenerateJitRunnerConfig(ctx, runnerSettings, 1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, want, got)
|
||||
})
|
||||
|
||||
t.Run("Default retries on server error", func(t *testing.T) {
|
||||
runnerSettings := &actions.RunnerScaleSetJitRunnerSetting{}
|
||||
|
||||
retryClient := retryablehttp.NewClient()
|
||||
retryClient.RetryWaitMax = 1 * time.Millisecond
|
||||
retryClient.RetryMax = 1
|
||||
|
||||
retryMax := 1
|
||||
actualRetry := 0
|
||||
expectedRetry := retryClient.RetryMax + 1
|
||||
expectedRetry := retryMax + 1
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
actualRetry++
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
httpClient := retryClient.StandardClient()
|
||||
actionsClient := actions.Client{
|
||||
Client: httpClient,
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
|
||||
_, _ = actionsClient.GenerateJitRunnerConfig(context.Background(), runnerSettings, 1)
|
||||
client, err := actions.NewClient(
|
||||
ctx,
|
||||
server.configURLForOrg("my-org"),
|
||||
auth,
|
||||
actions.WithRetryMax(1),
|
||||
actions.WithRetryWaitMax(1*time.Millisecond),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.GenerateJitRunnerConfig(ctx, runnerSettings, 1)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equalf(t, actualRetry, expectedRetry, "A retry was expected after the first request but got: %v", actualRetry)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,22 +3,21 @@ package actions_test
|
|||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/actions/actions-runner-controller/github/actions"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAcquireJobs(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
t.Run("Acquire Job", func(t *testing.T) {
|
||||
name := "Acquire Job"
|
||||
|
||||
want := []int64{1}
|
||||
response := []byte(`{"value": [1]}`)
|
||||
|
||||
|
|
@ -28,24 +27,16 @@ func TestAcquireJobs(t *testing.T) {
|
|||
}
|
||||
requestIDs := want
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Write(response)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
}
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := actionsClient.AcquireJobs(context.Background(), session.RunnerScaleSet.Id, session.MessageQueueAccessToken, requestIDs)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateRunnerScaleSet got unexepected error, %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("GetRunnerScaleSet(%v) mismatch (-want +got):\n%s", name, diff)
|
||||
}
|
||||
got, err := client.AcquireJobs(ctx, session.RunnerScaleSet.Id, session.MessageQueueAccessToken, requestIDs)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, want, got)
|
||||
})
|
||||
|
||||
t.Run("Default retries on server error", func(t *testing.T) {
|
||||
|
|
@ -55,90 +46,78 @@ func TestAcquireJobs(t *testing.T) {
|
|||
}
|
||||
var requestIDs []int64 = []int64{1}
|
||||
|
||||
retryClient := retryablehttp.NewClient()
|
||||
retryClient.RetryWaitMax = 1 * time.Millisecond
|
||||
retryClient.RetryMax = 1
|
||||
|
||||
retryMax := 1
|
||||
actualRetry := 0
|
||||
expectedRetry := retryClient.RetryMax + 1
|
||||
expectedRetry := retryMax + 1
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
actualRetry++
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
httpClient := retryClient.StandardClient()
|
||||
actionsClient := actions.Client{
|
||||
Client: httpClient,
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
}
|
||||
|
||||
_, _ = actionsClient.AcquireJobs(context.Background(), session.RunnerScaleSet.Id, session.MessageQueueAccessToken, requestIDs)
|
||||
client, err := actions.NewClient(
|
||||
ctx,
|
||||
server.configURLForOrg("my-org"),
|
||||
auth,
|
||||
actions.WithRetryMax(retryMax),
|
||||
actions.WithRetryWaitMax(1*time.Millisecond),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.AcquireJobs(context.Background(), session.RunnerScaleSet.Id, session.MessageQueueAccessToken, requestIDs)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equalf(t, actualRetry, expectedRetry, "A retry was expected after the first request but got: %v", actualRetry)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetAcquirableJobs(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
t.Run("Acquire Job", func(t *testing.T) {
|
||||
name := "Acquire Job"
|
||||
|
||||
want := &actions.AcquirableJobList{}
|
||||
response := []byte(`{"count": 0}`)
|
||||
|
||||
runnerScaleSet := &actions.RunnerScaleSet{Id: 1}
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Write(response)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := actionsClient.GetAcquirableJobs(context.Background(), runnerScaleSet.Id)
|
||||
if err != nil {
|
||||
t.Fatalf("GetAcquirableJobs got unexepected error, %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("GetAcquirableJobs(%v) mismatch (-want +got):\n%s", name, diff)
|
||||
}
|
||||
got, err := client.GetAcquirableJobs(context.Background(), runnerScaleSet.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, want, got)
|
||||
})
|
||||
|
||||
t.Run("Default retries on server error", func(t *testing.T) {
|
||||
runnerScaleSet := &actions.RunnerScaleSet{Id: 1}
|
||||
|
||||
retryClient := retryablehttp.NewClient()
|
||||
retryClient.RetryWaitMax = 1 * time.Millisecond
|
||||
retryClient.RetryMax = 1
|
||||
retryMax := 1
|
||||
|
||||
actualRetry := 0
|
||||
expectedRetry := retryClient.RetryMax + 1
|
||||
expectedRetry := retryMax + 1
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
actualRetry++
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
httpClient := retryClient.StandardClient()
|
||||
actionsClient := actions.Client{
|
||||
Client: httpClient,
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
|
||||
_, _ = actionsClient.GetAcquirableJobs(context.Background(), runnerScaleSet.Id)
|
||||
client, err := actions.NewClient(
|
||||
context.Background(),
|
||||
server.configURLForOrg("my-org"),
|
||||
auth,
|
||||
actions.WithRetryMax(retryMax),
|
||||
actions.WithRetryWaitMax(1*time.Millisecond),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.GetAcquirableJobs(context.Background(), runnerScaleSet.Id)
|
||||
require.Error(t, err)
|
||||
assert.Equalf(t, actualRetry, expectedRetry, "A retry was expected after the first request but got: %v", actualRetry)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,18 +5,20 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/actions/actions-runner-controller/github/actions"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetMessage(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
runnerScaleSetMessage := &actions.RunnerScaleSetMessage{
|
||||
MessageId: 1,
|
||||
|
|
@ -26,89 +28,54 @@ func TestGetMessage(t *testing.T) {
|
|||
t.Run("Get Runner Scale Set Message", func(t *testing.T) {
|
||||
want := runnerScaleSetMessage
|
||||
response := []byte(`{"messageId":1,"messageType":"rssType"}`)
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
s := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Write(response)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
client, err := actions.NewClient(ctx, s.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := actionsClient.GetMessage(context.Background(), s.URL, token, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("GetMessage got unexepected error, %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("GetMessage mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
got, err := client.GetMessage(ctx, s.URL, token, 0)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, want, got)
|
||||
})
|
||||
|
||||
t.Run("Default retries on server error", func(t *testing.T) {
|
||||
retryClient := retryablehttp.NewClient()
|
||||
retryClient.RetryWaitMax = 1 * time.Nanosecond
|
||||
retryClient.RetryMax = 1
|
||||
retryMax := 1
|
||||
|
||||
actualRetry := 0
|
||||
expectedRetry := retryClient.RetryMax + 1
|
||||
expectedRetry := retryMax + 1
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
actualRetry++
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
httpClient := retryClient.StandardClient()
|
||||
actionsClient := actions.Client{
|
||||
Client: httpClient,
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
|
||||
_, _ = actionsClient.GetMessage(context.Background(), s.URL, token, 0)
|
||||
client, err := actions.NewClient(
|
||||
ctx,
|
||||
server.configURLForOrg("my-org"),
|
||||
auth,
|
||||
actions.WithRetryMax(retryMax),
|
||||
actions.WithRetryWaitMax(1*time.Millisecond),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.GetMessage(ctx, server.URL, token, 0)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equalf(t, actualRetry, expectedRetry, "A retry was expected after the first request but got: %v", actualRetry)
|
||||
})
|
||||
|
||||
t.Run("Custom retries on server error", func(t *testing.T) {
|
||||
actualRetry := 0
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
actualRetry++
|
||||
}))
|
||||
defer s.Close()
|
||||
retryMax := 1
|
||||
retryWaitMax := 1 * time.Nanosecond
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
RetryMax: &retryMax,
|
||||
RetryWaitMax: &retryWaitMax,
|
||||
}
|
||||
_, _ = actionsClient.GetMessage(context.Background(), s.URL, token, 0)
|
||||
expectedRetry := retryMax + 1
|
||||
assert.Equalf(t, actualRetry, expectedRetry, "A retry was expected after the first request but got: %v", actualRetry)
|
||||
},
|
||||
)
|
||||
|
||||
t.Run("Message token expired", func(t *testing.T) {
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
}))
|
||||
defer s.Close()
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
_, err := actionsClient.GetMessage(context.Background(), s.URL, token, 0)
|
||||
if err == nil {
|
||||
t.Fatalf("GetMessage did not get exepected error, ")
|
||||
}
|
||||
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.GetMessage(ctx, server.URL, token, 0)
|
||||
require.NotNil(t, err)
|
||||
|
||||
var expectedErr *actions.MessageQueueTokenExpiredError
|
||||
require.True(t, errors.As(err, &expectedErr))
|
||||
},
|
||||
|
|
@ -119,45 +86,38 @@ func TestGetMessage(t *testing.T) {
|
|||
Message: "Request returned status: 404 Not Found",
|
||||
StatusCode: 404,
|
||||
}
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}))
|
||||
defer s.Close()
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
_, err := actionsClient.GetMessage(context.Background(), s.URL, token, 0)
|
||||
if err == nil {
|
||||
t.Fatalf("GetMessage did not get exepected error, ")
|
||||
}
|
||||
if diff := cmp.Diff(want.Error(), err.Error()); diff != "" {
|
||||
t.Errorf("GetMessage mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.GetMessage(ctx, server.URL, token, 0)
|
||||
require.NotNil(t, err)
|
||||
assert.Equal(t, want.Error(), err.Error())
|
||||
})
|
||||
|
||||
t.Run("Error when Content-Type is text/plain", func(t *testing.T) {
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
}))
|
||||
defer s.Close()
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
_, err := actionsClient.GetMessage(context.Background(), s.URL, token, 0)
|
||||
if err == nil {
|
||||
t.Fatalf("GetMessage did not get exepected error,")
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.GetMessage(ctx, server.URL, token, 0)
|
||||
assert.NotNil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteMessage(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
runnerScaleSetMessage := &actions.RunnerScaleSetMessage{
|
||||
MessageId: 1,
|
||||
|
|
@ -165,105 +125,83 @@ func TestDeleteMessage(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run("Delete existing message", func(t *testing.T) {
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
err := actionsClient.DeleteMessage(context.Background(), s.URL, token, runnerScaleSetMessage.MessageId)
|
||||
if err != nil {
|
||||
t.Fatalf("DeleteMessage got unexepected error, %v", err)
|
||||
}
|
||||
},
|
||||
)
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.DeleteMessage(ctx, server.URL, token, runnerScaleSetMessage.MessageId)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("Message token expired", func(t *testing.T) {
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
}))
|
||||
defer s.Close()
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
err := actionsClient.DeleteMessage(context.Background(), s.URL, token, 0)
|
||||
if err == nil {
|
||||
t.Fatalf("DeleteMessage did not get exepected error, ")
|
||||
}
|
||||
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.DeleteMessage(ctx, server.URL, token, 0)
|
||||
require.NotNil(t, err)
|
||||
var expectedErr *actions.MessageQueueTokenExpiredError
|
||||
require.True(t, errors.As(err, &expectedErr))
|
||||
},
|
||||
)
|
||||
assert.True(t, errors.As(err, &expectedErr))
|
||||
})
|
||||
|
||||
t.Run("Error when Content-Type is text/plain", func(t *testing.T) {
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
}))
|
||||
defer s.Close()
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
err := actionsClient.DeleteMessage(context.Background(), s.URL, token, runnerScaleSetMessage.MessageId)
|
||||
if err == nil {
|
||||
t.Fatalf("DeleteMessage did not get exepected error")
|
||||
}
|
||||
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.DeleteMessage(ctx, server.URL, token, runnerScaleSetMessage.MessageId)
|
||||
require.NotNil(t, err)
|
||||
var expectedErr *actions.ActionsError
|
||||
require.True(t, errors.As(err, &expectedErr))
|
||||
assert.True(t, errors.As(err, &expectedErr))
|
||||
},
|
||||
)
|
||||
|
||||
t.Run("Default retries on server error", func(t *testing.T) {
|
||||
actualRetry := 0
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
actualRetry++
|
||||
}))
|
||||
defer s.Close()
|
||||
retryClient := retryablehttp.NewClient()
|
||||
|
||||
retryMax := 1
|
||||
retryClient.RetryWaitMax = time.Nanosecond
|
||||
retryClient.RetryMax = retryMax
|
||||
httpClient := retryClient.StandardClient()
|
||||
actionsClient := actions.Client{
|
||||
Client: httpClient,
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
_ = actionsClient.DeleteMessage(context.Background(), s.URL, token, runnerScaleSetMessage.MessageId)
|
||||
client, err := actions.NewClient(
|
||||
ctx,
|
||||
server.configURLForOrg("my-org"),
|
||||
auth,
|
||||
actions.WithRetryMax(retryMax),
|
||||
actions.WithRetryWaitMax(1*time.Nanosecond),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
err = client.DeleteMessage(ctx, server.URL, token, runnerScaleSetMessage.MessageId)
|
||||
assert.NotNil(t, err)
|
||||
expectedRetry := retryMax + 1
|
||||
assert.Equalf(t, actualRetry, expectedRetry, "A retry was expected after the first request but got: %v", actualRetry)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("No message found", func(t *testing.T) {
|
||||
want := (*actions.RunnerScaleSetMessage)(nil)
|
||||
rsl, err := json.Marshal(want)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
require.NoError(t, err)
|
||||
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Write(rsl)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
err = actionsClient.DeleteMessage(context.Background(), s.URL, token, runnerScaleSetMessage.MessageId+1)
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.DeleteMessage(ctx, server.URL, token, runnerScaleSetMessage.MessageId+1)
|
||||
var expectedErr *actions.ActionsError
|
||||
require.True(t, errors.As(err, &expectedErr))
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,19 +4,22 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/actions/actions-runner-controller/github/actions"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCreateMessageSession(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
t.Run("CreateMessageSession unmarshals correctly", func(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
owner := "foo"
|
||||
runnerScaleSet := actions.RunnerScaleSet{
|
||||
Id: 1,
|
||||
|
|
@ -35,7 +38,7 @@ func TestCreateMessageSession(t *testing.T) {
|
|||
MessageQueueAccessToken: "fake.jwt.here",
|
||||
}
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
resp := []byte(`{
|
||||
"ownerName": "foo",
|
||||
"runnerScaleSet": {
|
||||
|
|
@ -47,31 +50,16 @@ func TestCreateMessageSession(t *testing.T) {
|
|||
}`)
|
||||
w.Write(resp)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
retryMax := 1
|
||||
retryWaitMax := 1 * time.Microsecond
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &srv.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
RetryMax: &retryMax,
|
||||
RetryWaitMax: &retryWaitMax,
|
||||
}
|
||||
|
||||
got, err := actionsClient.CreateMessageSession(context.Background(), runnerScaleSet.Id, owner)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateMessageSession got unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(got, want); diff != "" {
|
||||
t.Fatalf("CreateMessageSession got unexpected diff: -want +got: %v", diff)
|
||||
}
|
||||
got, err := client.CreateMessageSession(ctx, runnerScaleSet.Id, owner)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, want, got)
|
||||
})
|
||||
|
||||
t.Run("CreateMessageSession unmarshals errors into ActionsError", func(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
owner := "foo"
|
||||
runnerScaleSet := actions.RunnerScaleSet{
|
||||
Id: 1,
|
||||
|
|
@ -86,44 +74,32 @@ func TestCreateMessageSession(t *testing.T) {
|
|||
StatusCode: http.StatusBadRequest,
|
||||
}
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
resp := []byte(`{"typeName": "CSharpExceptionNameHere","message": "could not do something"}`)
|
||||
w.Write(resp)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
retryMax := 1
|
||||
retryWaitMax := 1 * time.Microsecond
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &srv.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
RetryMax: &retryMax,
|
||||
RetryWaitMax: &retryWaitMax,
|
||||
}
|
||||
|
||||
got, err := actionsClient.CreateMessageSession(context.Background(), runnerScaleSet.Id, owner)
|
||||
if err == nil {
|
||||
t.Fatalf("CreateMessageSession did not get expected error: %v", got)
|
||||
}
|
||||
_, err = client.CreateMessageSession(ctx, runnerScaleSet.Id, owner)
|
||||
require.NotNil(t, err)
|
||||
|
||||
errorTypeForComparison := &actions.ActionsError{}
|
||||
if isActionsError := errors.As(err, &errorTypeForComparison); !isActionsError {
|
||||
t.Fatalf("CreateMessageSession expected to be able to parse the error into ActionsError type: %v", err)
|
||||
}
|
||||
assert.True(
|
||||
t,
|
||||
errors.As(err, &errorTypeForComparison),
|
||||
"CreateMessageSession expected to be able to parse the error into ActionsError type: %v",
|
||||
err,
|
||||
)
|
||||
|
||||
gotErr := err.(*actions.ActionsError)
|
||||
|
||||
if diff := cmp.Diff(want, gotErr); diff != "" {
|
||||
t.Fatalf("CreateMessageSession got unexpected diff: -want +got: %v", diff)
|
||||
}
|
||||
assert.Equal(t, want, gotErr)
|
||||
})
|
||||
|
||||
t.Run("CreateMessageSession call is retried the correct amount of times", func(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
owner := "foo"
|
||||
runnerScaleSet := actions.RunnerScaleSet{
|
||||
Id: 1,
|
||||
|
|
@ -133,37 +109,38 @@ func TestCreateMessageSession(t *testing.T) {
|
|||
}
|
||||
|
||||
gotRetries := 0
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
gotRetries++
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
retryMax := 3
|
||||
retryWaitMax, err := time.ParseDuration("1µs")
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
retryWaitMax := 1 * time.Microsecond
|
||||
|
||||
wantRetries := retryMax + 1
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &srv.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
RetryMax: &retryMax,
|
||||
RetryWaitMax: &retryWaitMax,
|
||||
}
|
||||
|
||||
_, _ = actionsClient.CreateMessageSession(context.Background(), runnerScaleSet.Id, owner)
|
||||
client, err := actions.NewClient(
|
||||
ctx,
|
||||
server.configURLForOrg("my-org"),
|
||||
auth,
|
||||
actions.WithRetryMax(retryMax),
|
||||
actions.WithRetryWaitMax(retryWaitMax),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.CreateMessageSession(ctx, runnerScaleSet.Id, owner)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equalf(t, gotRetries, wantRetries, "CreateMessageSession got unexpected retry count: got=%v, want=%v", gotRetries, wantRetries)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteMessageSession(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
t.Run("DeleteMessageSession call is retried the correct amount of times", func(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
runnerScaleSet := actions.RunnerScaleSet{
|
||||
Id: 1,
|
||||
Name: "ScaleSet",
|
||||
|
|
@ -172,39 +149,40 @@ func TestDeleteMessageSession(t *testing.T) {
|
|||
}
|
||||
|
||||
gotRetries := 0
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
gotRetries++
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
retryMax := 3
|
||||
retryWaitMax, err := time.ParseDuration("1µs")
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
retryWaitMax := 1 * time.Microsecond
|
||||
|
||||
wantRetries := retryMax + 1
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &srv.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
RetryMax: &retryMax,
|
||||
RetryWaitMax: &retryWaitMax,
|
||||
}
|
||||
client, err := actions.NewClient(
|
||||
ctx,
|
||||
server.configURLForOrg("my-org"),
|
||||
auth,
|
||||
actions.WithRetryMax(retryMax),
|
||||
actions.WithRetryWaitMax(retryWaitMax),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionId := uuid.New()
|
||||
|
||||
_ = actionsClient.DeleteMessageSession(context.Background(), runnerScaleSet.Id, &sessionId)
|
||||
|
||||
err = client.DeleteMessageSession(ctx, runnerScaleSet.Id, &sessionId)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equalf(t, gotRetries, wantRetries, "CreateMessageSession got unexpected retry count: got=%v, want=%v", gotRetries, wantRetries)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRefreshMessageSession(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
t.Run("RefreshMessageSession call is retried the correct amount of times", func(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
runnerScaleSet := actions.RunnerScaleSet{
|
||||
Id: 1,
|
||||
Name: "ScaleSet",
|
||||
|
|
@ -213,32 +191,29 @@ func TestRefreshMessageSession(t *testing.T) {
|
|||
}
|
||||
|
||||
gotRetries := 0
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
gotRetries++
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
retryMax := 3
|
||||
retryWaitMax, err := time.ParseDuration("1µs")
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
retryWaitMax := 1 * time.Microsecond
|
||||
|
||||
wantRetries := retryMax + 1
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &srv.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
RetryMax: &retryMax,
|
||||
RetryWaitMax: &retryWaitMax,
|
||||
}
|
||||
client, err := actions.NewClient(
|
||||
ctx,
|
||||
server.configURLForOrg("my-org"),
|
||||
auth,
|
||||
actions.WithRetryMax(retryMax),
|
||||
actions.WithRetryWaitMax(retryWaitMax),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
sessionId := uuid.New()
|
||||
|
||||
_, _ = actionsClient.RefreshMessageSession(context.Background(), runnerScaleSet.Id, &sessionId)
|
||||
|
||||
_, err = client.RefreshMessageSession(context.Background(), runnerScaleSet.Id, &sessionId)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equalf(t, gotRetries, wantRetries, "CreateMessageSession got unexpected retry count: got=%v, want=%v", gotRetries, wantRetries)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -3,23 +3,21 @@ package actions_test
|
|||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/actions/actions-runner-controller/github/actions"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var tokenExpireAt = time.Now().Add(10 * time.Minute)
|
||||
|
||||
func TestGetRunner(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
t.Run("Get Runner", func(t *testing.T) {
|
||||
name := "Get Runner"
|
||||
var runnerID int64 = 1
|
||||
want := &actions.RunnerReference{
|
||||
Id: int(runnerID),
|
||||
|
|
@ -27,59 +25,45 @@ func TestGetRunner(t *testing.T) {
|
|||
}
|
||||
response := []byte(`{"id": 1, "name": "self-hosted-ubuntu"}`)
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(response)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := actionsClient.GetRunner(context.Background(), runnerID)
|
||||
if err != nil {
|
||||
t.Fatalf("GetRunner got unexepected error, %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("GetRunner(%v) mismatch (-want +got):\n%s", name, diff)
|
||||
}
|
||||
got, err := client.GetRunner(ctx, runnerID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, want, got)
|
||||
})
|
||||
|
||||
t.Run("Default retries on server error", func(t *testing.T) {
|
||||
var runnerID int64 = 1
|
||||
retryClient := retryablehttp.NewClient()
|
||||
retryClient.RetryWaitMax = 1 * time.Millisecond
|
||||
retryClient.RetryMax = 1
|
||||
retryWaitMax := 1 * time.Millisecond
|
||||
retryMax := 1
|
||||
|
||||
actualRetry := 0
|
||||
expectedRetry := retryClient.RetryMax + 1
|
||||
expectedRetry := retryMax + 1
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
actualRetry++
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
httpClient := retryClient.StandardClient()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
Client: httpClient,
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
|
||||
_, _ = actionsClient.GetRunner(context.Background(), runnerID)
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth, actions.WithRetryMax(retryMax), actions.WithRetryWaitMax(retryWaitMax))
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.GetRunner(ctx, runnerID)
|
||||
require.Error(t, err)
|
||||
assert.Equalf(t, actualRetry, expectedRetry, "A retry was expected after the first request but got: %v", actualRetry)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetRunnerByName(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
t.Run("Get Runner by Name", func(t *testing.T) {
|
||||
var runnerID int64 = 1
|
||||
|
|
@ -90,130 +74,102 @@ func TestGetRunnerByName(t *testing.T) {
|
|||
}
|
||||
response := []byte(`{"count": 1, "value": [{"id": 1, "name": "self-hosted-ubuntu"}]}`)
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(response)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := actionsClient.GetRunnerByName(context.Background(), runnerName)
|
||||
if err != nil {
|
||||
t.Fatalf("GetRunnerByName got unexepected error, %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("GetRunnerByName(%v) mismatch (-want +got):\n%s", runnerName, diff)
|
||||
}
|
||||
got, err := client.GetRunnerByName(ctx, runnerName)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, want, got)
|
||||
})
|
||||
|
||||
t.Run("Get Runner by name with not exist runner", func(t *testing.T) {
|
||||
var runnerName string = "self-hosted-ubuntu"
|
||||
response := []byte(`{"count": 0, "value": []}`)
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(response)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := actionsClient.GetRunnerByName(context.Background(), runnerName)
|
||||
if err != nil {
|
||||
t.Fatalf("GetRunnerByName got unexepected error, %v", err)
|
||||
}
|
||||
|
||||
if diff := cmp.Diff((*actions.RunnerReference)(nil), got); diff != "" {
|
||||
t.Errorf("GetRunnerByName(%v) mismatch (-want +got):\n%s", runnerName, diff)
|
||||
}
|
||||
got, err := client.GetRunnerByName(ctx, runnerName)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, got)
|
||||
})
|
||||
|
||||
t.Run("Default retries on server error", func(t *testing.T) {
|
||||
var runnerName string = "self-hosted-ubuntu"
|
||||
retryClient := retryablehttp.NewClient()
|
||||
retryClient.RetryWaitMax = 1 * time.Millisecond
|
||||
retryClient.RetryMax = 1
|
||||
|
||||
retryWaitMax := 1 * time.Millisecond
|
||||
retryMax := 1
|
||||
|
||||
actualRetry := 0
|
||||
expectedRetry := retryClient.RetryMax + 1
|
||||
expectedRetry := retryMax + 1
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
actualRetry++
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
httpClient := retryClient.StandardClient()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
Client: httpClient,
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
|
||||
_, _ = actionsClient.GetRunnerByName(context.Background(), runnerName)
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth, actions.WithRetryMax(retryMax), actions.WithRetryWaitMax(retryWaitMax))
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = client.GetRunnerByName(ctx, runnerName)
|
||||
require.Error(t, err)
|
||||
assert.Equalf(t, actualRetry, expectedRetry, "A retry was expected after the first request but got: %v", actualRetry)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteRunner(t *testing.T) {
|
||||
token := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjI1MTYyMzkwMjJ9.tlrHslTmDkoqnc4Kk9ISoKoUNDfHo-kjlH-ByISBqzE"
|
||||
ctx := context.Background()
|
||||
auth := &actions.ActionsAuth{
|
||||
Token: "token",
|
||||
}
|
||||
|
||||
t.Run("Delete Runner", func(t *testing.T) {
|
||||
var runnerID int64 = 1
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
actionsClient := actions.Client{
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
client, err := actions.NewClient(ctx, server.configURLForOrg("my-org"), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := actionsClient.RemoveRunner(context.Background(), runnerID); err != nil {
|
||||
t.Fatalf("RemoveRunner got unexepected error, %v", err)
|
||||
}
|
||||
err = client.RemoveRunner(ctx, runnerID)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Default retries on server error", func(t *testing.T) {
|
||||
var runnerID int64 = 1
|
||||
|
||||
retryClient := retryablehttp.NewClient()
|
||||
retryClient.RetryWaitMax = 1 * time.Millisecond
|
||||
retryClient.RetryMax = 1
|
||||
retryWaitMax := 1 * time.Millisecond
|
||||
retryMax := 1
|
||||
|
||||
actualRetry := 0
|
||||
expectedRetry := retryClient.RetryMax + 1
|
||||
expectedRetry := retryMax + 1
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
server := newActionsServer(t, http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
actualRetry++
|
||||
}))
|
||||
defer s.Close()
|
||||
|
||||
httpClient := retryClient.StandardClient()
|
||||
actionsClient := actions.Client{
|
||||
Client: httpClient,
|
||||
ActionsServiceURL: &s.URL,
|
||||
ActionsServiceAdminToken: &token,
|
||||
ActionsServiceAdminTokenExpiresAt: &tokenExpireAt,
|
||||
}
|
||||
|
||||
_ = actionsClient.RemoveRunner(context.Background(), runnerID)
|
||||
client, err := actions.NewClient(
|
||||
ctx,
|
||||
server.configURLForOrg("my-org"),
|
||||
auth,
|
||||
actions.WithRetryMax(retryMax),
|
||||
actions.WithRetryWaitMax(retryWaitMax),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = client.RemoveRunner(ctx, runnerID)
|
||||
require.Error(t, err)
|
||||
assert.Equalf(t, actualRetry, expectedRetry, "A retry was expected after the first request but got: %v", actualRetry)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,13 @@ func (m *multiClient) GetClientFor(ctx context.Context, githubConfigURL string,
|
|||
|
||||
m.logger.Info("creating new client", "githubConfigURL", githubConfigURL, "namespace", namespace)
|
||||
|
||||
client, err := NewClient(ctx, githubConfigURL, &creds, m.userAgent, m.logger)
|
||||
client, err := NewClient(
|
||||
ctx,
|
||||
githubConfigURL,
|
||||
&creds,
|
||||
WithUserAgent(m.userAgent),
|
||||
WithLogger(m.logger),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,20 +6,15 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/actions/actions-runner-controller/logging"
|
||||
"github.com/go-logr/logr"
|
||||
)
|
||||
|
||||
func TestAddClient(t *testing.T) {
|
||||
logger, err := logging.NewLogger(logging.LogLevelDebug, logging.LogFormatText)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: creating logger: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
logger := logr.Discard()
|
||||
multiClient := NewMultiClient("test-user-agent", logger).(*multiClient)
|
||||
|
||||
ctx := context.Background()
|
||||
|
|
|
|||
Loading…
Reference in New Issue