gitlabhq/gitlab-shell

View on GitHub
internal/command/personalaccesstoken/personalaccesstoken_test.go

Summary

Maintainability
B
4 hrs
Test Coverage
package personalaccesstoken

import (
    "bytes"
    "context"
    "encoding/json"
    "io"
    "net/http"
    "strings"
    "testing"

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

    "gitlab.com/gitlab-org/gitlab-shell/v14/client/testserver"
    "gitlab.com/gitlab-org/gitlab-shell/v14/internal/command/commandargs"
    "gitlab.com/gitlab-org/gitlab-shell/v14/internal/command/readwriter"
    "gitlab.com/gitlab-org/gitlab-shell/v14/internal/config"
    "gitlab.com/gitlab-org/gitlab-shell/v14/internal/gitlabnet/personalaccesstoken"
)

var requests []testserver.TestRequestHandler

func setup(t *testing.T) {
    requests = []testserver.TestRequestHandler{
        {
            Path: "/api/v4/internal/personal_access_token",
            Handler: func(w http.ResponseWriter, r *http.Request) {
                b, err := io.ReadAll(r.Body)
                defer r.Body.Close()

                assert.NoError(t, err)

                var requestBody *personalaccesstoken.RequestBody
                json.Unmarshal(b, &requestBody)

                switch requestBody.KeyID {
                case "forbidden":
                    body := map[string]interface{}{
                        "success": false,
                        "message": "Forbidden!",
                    }
                    json.NewEncoder(w).Encode(body)
                case "broken":
                    w.WriteHeader(http.StatusInternalServerError)
                case "invalidscope":
                    message := "Invalid scope: '" + strings.Join(requestBody.Scopes, ",") + "'."
                    message += " Valid scopes are: [\"api\", \"create_runner\", \"k8s_proxy\", \"read_api\", \"read_registry\", \"read_repository\", \"read_user\", \"write_registry\", \"write_repository\"]"
                    body := map[string]interface{}{
                        "success": false,
                        "message": message,
                    }
                    json.NewEncoder(w).Encode(body)
                case "badresponse":
                default:
                    var expiresAt interface{}
                    if requestBody.ExpiresAt == "" {
                        expiresAt = nil
                    } else {
                        expiresAt = "9001-11-17"
                    }
                    body := map[string]interface{}{
                        "success":    true,
                        "token":      "YXuxvUgCEmeePY3G1YAa",
                        "scopes":     requestBody.Scopes,
                        "expires_at": expiresAt,
                    }
                    json.NewEncoder(w).Encode(body)
                }
            },
        },
    }
}

const (
    cmdname = "personal_access_token"
)

func TestExecute(t *testing.T) {
    setup(t)

    url := testserver.StartSocketHTTPServer(t, requests)

    testCases := []struct {
        desc           string
        PATConfig      config.PATConfig
        arguments      *commandargs.Shell
        expectedOutput string
        expectedError  string
    }{
        {
            desc:          "Without any arguments",
            arguments:     &commandargs.Shell{},
            expectedError: usageText,
        },
        {
            desc: "With too few arguments",
            arguments: &commandargs.Shell{
                SSHArgs: []string{cmdname, "newtoken"},
            },
            expectedError: usageText,
        },
        {
            desc: "With too many arguments",
            arguments: &commandargs.Shell{
                SSHArgs: []string{cmdname, "newtoken", "api", "bad_ttl", "toomany"},
            },
            expectedError: usageText,
        },
        {
            desc: "With a bad ttl_days argument",
            arguments: &commandargs.Shell{
                SSHArgs: []string{cmdname, "newtoken", "api", "bad_ttl"},
            },
            expectedError: "Invalid value for days_ttl: 'bad_ttl'",
        },
        {
            desc: "Without a ttl argument",
            arguments: &commandargs.Shell{
                GitlabKeyID: "default",
                SSHArgs:     []string{cmdname, "newtoken", "read_api,read_repository"},
            },
            expectedOutput: "Token:   YXuxvUgCEmeePY3G1YAa\n" +
                "Scopes:  read_api,read_repository\n" +
                "Expires: 9001-11-17\n",
        },
        {
            desc: "With a ttl argument",
            arguments: &commandargs.Shell{
                GitlabKeyID: "default",
                SSHArgs:     []string{cmdname, "newtoken", "api", "30"},
            },
            expectedOutput: "Token:   YXuxvUgCEmeePY3G1YAa\n" +
                "Scopes:  api\n" +
                "Expires: 9001-11-17\n",
        },
        {
            desc: "With bad response",
            arguments: &commandargs.Shell{
                GitlabKeyID: "badresponse",
                SSHArgs:     []string{cmdname, "newtoken", "read_api,read_repository"},
            },
            expectedError: "parsing failed",
        },
        {
            desc: "when API returns an error",
            arguments: &commandargs.Shell{
                GitlabKeyID: "forbidden",
                SSHArgs:     []string{cmdname, "newtoken", "read_api,read_repository"},
            },
            expectedError: "Forbidden!",
        },
        {
            desc: "When API fails",
            arguments: &commandargs.Shell{
                GitlabKeyID: "broken",
                SSHArgs:     []string{cmdname, "newtoken", "read_api,read_repository"},
            },
            expectedError: "Internal API unreachable",
        },
        {
            desc: "Without KeyID or User",
            arguments: &commandargs.Shell{
                SSHArgs: []string{cmdname, "newtoken", "read_api,read_repository"},
            },
            expectedError: "who='' is invalid",
        },
        {
            desc:      "With restricted scopes",
            PATConfig: config.PATConfig{AllowedScopes: []string{"read_api"}},
            arguments: &commandargs.Shell{
                GitlabKeyID: "default",
                SSHArgs:     []string{cmdname, "newtoken", "read_api,read_repository"},
            },
            expectedOutput: "Token:   YXuxvUgCEmeePY3G1YAa\n" +
                "Scopes:  read_api\n" +
                "Expires: 9001-11-17\n",
        },
        {
            desc:      "With unknown configured scopes",
            PATConfig: config.PATConfig{AllowedScopes: []string{"read_reposotory"}}, //nolint:misspell //testing purpose
            arguments: &commandargs.Shell{
                GitlabKeyID: "default",
                SSHArgs:     []string{cmdname, "newtoken", "read_api,read_repository"},
            },
            expectedOutput: "Token:   YXuxvUgCEmeePY3G1YAa\n" +
                "Scopes:  \n" +
                "Expires: 9001-11-17\n",
        },
        {
            desc:      "With unknown requested scopes",
            PATConfig: config.PATConfig{AllowedScopes: []string{"read_api", "read_repository"}},
            arguments: &commandargs.Shell{
                GitlabKeyID: "default",
                SSHArgs:     []string{cmdname, "newtoken", "read_api,read_reposotory"}, //nolint:misspell //testing purpose
            },
            expectedOutput: "Token:   YXuxvUgCEmeePY3G1YAa\n" +
                "Scopes:  read_api\n" +
                "Expires: 9001-11-17\n",
        },
        {
            desc:      "With matching unknown requested scopes",
            PATConfig: config.PATConfig{AllowedScopes: []string{"read_api", "read_reposotory"}}, //nolint:misspell //testing purpose
            arguments: &commandargs.Shell{
                GitlabKeyID: "invalidscope",
                SSHArgs:     []string{cmdname, "newtoken", "read_reposotory"}, //nolint:misspell //testing purpose
            },
            expectedError: "Invalid scope: 'read_reposotory'. Valid scopes are: [\"api\", \"create_runner\", \"k8s_proxy\", \"read_api\", \"read_registry\", \"read_repository\", \"read_user\", \"write_registry\", \"write_repository\"]",
        },
    }

    for _, tc := range testCases {
        t.Run(tc.desc, func(t *testing.T) {
            output := &bytes.Buffer{}
            input := bytes.NewBufferString("")

            cmd := &Command{
                Config:     &config.Config{GitlabUrl: url, PATConfig: tc.PATConfig},
                Args:       tc.arguments,
                ReadWriter: &readwriter.ReadWriter{Out: output, In: input},
            }

            _, err := cmd.Execute(context.Background())

            if tc.expectedError == "" {
                require.NoError(t, err)
            } else {
                require.EqualError(t, err, tc.expectedError)
            }

            if tc.expectedOutput != "" {
                require.Equal(t, tc.expectedOutput, output.String())
            }
        })
    }
}