Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions checks/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ func (b *boundedBuffer) String() string {
return b.buffer.String()
}

func (b *boundedBuffer) Truncated() bool {
return b.truncated
}

func runCLICommand(command api.CLIStepCLICommand, variables map[string]string) (result api.CLICommandResult) {
return runCLICommandWithLimits(command, variables, cliCommandTimeout, maxCLIOutputBytesPerStream)
}
Expand Down
39 changes: 0 additions & 39 deletions checks/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,30 +74,6 @@ func TestRunCLICommandCapsOutput(t *testing.T) {
}
}

func TestBoundedBufferDiscardsExcessBytes(t *testing.T) {
truncations := 0
buffer := newBoundedBuffer(5, func() {
truncations++
})
written, err := buffer.Write([]byte("abcdefgh"))
if err != nil {
t.Fatalf("Write() error = %v", err)
}
if written != 8 {
t.Fatalf("Write() = %d, want 8", written)
}
if got := buffer.String(); got != "abcde" {
t.Fatalf("buffer = %q, want abcde", got)
}
if !buffer.Truncated() {
t.Fatal("buffer did not record truncation")
}
_, _ = buffer.Write([]byte("more"))
if truncations != 1 {
t.Fatalf("truncation callback invoked %d times, want once", truncations)
}
}

func TestRunCLICommandCapturesStdoutVariables(t *testing.T) {
variables := map[string]string{}
result := runCLICommand(api.CLIStepCLICommand{
Expand Down Expand Up @@ -178,21 +154,6 @@ func TestRunCLICommandInterpolatesCapturedStdoutVariables(t *testing.T) {
}
}

func TestParseStdoutVariablesRequiresOneCaptureGroup(t *testing.T) {
variables := map[string]string{}
err := parseStdoutVariables("token=abc123", []api.CLICommandStdoutVariable{{
Name: "token",
Regex: `token=([a-z]+)([0-9]+)`,
}}, variables)

if err == nil {
t.Fatal("expected parse error")
}
if err.Error() != "invalid stdout variable configuration" {
t.Fatalf("error = %q, want invalid stdout variable configuration", err.Error())
}
}

func TestParseStdoutVariablesUsesGenericConfigurationError(t *testing.T) {
tests := []struct {
name string
Expand Down
34 changes: 0 additions & 34 deletions checks/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"net/http/httptest"
"strings"
"testing"
"time"

api "github.com/bootdotdev/bootdev/client"
)
Expand Down Expand Up @@ -240,39 +239,6 @@ func TestRunHTTPRequestCapsResponseBodyRead(t *testing.T) {
}
}

func TestRunHTTPRequestHonorsClientTimeout(t *testing.T) {
const timeout = 20 * time.Millisecond
client := &http.Client{
Timeout: timeout,
Transport: httpRoundTripFunc(func(r *http.Request) (*http.Response, error) {
<-r.Context().Done()
return nil, r.Context().Err()
}),
}
requestStep := api.CLIStepHTTPRequest{
Request: api.HTTPRequest{
Method: http.MethodGet,
FullURL: "http://example.test",
},
}

start := time.Now()
result := runHTTPRequest(client, "", map[string]string{}, requestStep)
elapsed := time.Since(start)
if result.Err == "" {
t.Fatal("runHTTPRequest() unexpectedly succeeded")
}
if elapsed > time.Second {
t.Fatalf("runHTTPRequest() took %v, want a prompt timeout", elapsed)
}
}

func TestLessonHTTPClientUsesConfiguredTimeout(t *testing.T) {
if got := newLessonHTTPClient().Timeout; got != lessonHTTPRequestTimeout {
t.Fatalf("lesson HTTP client timeout = %v, want %v", got, lessonHTTPRequestTimeout)
}
}

func TestRunHTTPRequestCapturesResponseHeaderVariableAndDoesNotFollowRedirect(t *testing.T) {
followRedirects := false

Expand Down
41 changes: 6 additions & 35 deletions checks/jq_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package checks

import (
"reflect"
"strings"
"testing"

api "github.com/bootdotdev/bootdev/client"
Expand All @@ -15,7 +14,7 @@ func TestRunStdoutJqQuery(t *testing.T) {
test api.StdoutJqTest
variables map[string]string
want api.CLICommandJqOutput
wantError string
wantError bool
}{
{
name: "queries json with interpolated query",
Expand Down Expand Up @@ -52,7 +51,7 @@ func TestRunStdoutJqQuery(t *testing.T) {
want: api.CLICommandJqOutput{
Query: `.name`,
},
wantError: "invalid character",
wantError: true,
},
{
name: "returns jq error",
Expand All @@ -63,20 +62,20 @@ func TestRunStdoutJqQuery(t *testing.T) {
},
want: api.CLICommandJqOutput{
Query: `.name[`,
Error: "unexpected EOF",
},
wantError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := runStdoutJqQuery(tt.stdout, tt.test, tt.variables)
if tt.wantError != "" {
if tt.wantError {
if got.Query != tt.want.Query {
t.Fatalf("Query = %q, want %q", got.Query, tt.want.Query)
}
if !strings.Contains(got.Error, tt.wantError) {
t.Fatalf("expected error containing %q, got %q", tt.wantError, got.Error)
if got.Error == "" {
t.Fatal("expected an error")
}
return
}
Expand All @@ -97,34 +96,6 @@ func TestParseJqInputRejectsMultipleJSONValuesInJSONMode(t *testing.T) {
}
}

func TestFormatJqResults(t *testing.T) {
got := formatJqResults([]any{"hello", float64(42), true, nil, map[string]any{"id": float64(1)}})
want := []string{`"hello"`, `42`, `true`, `null`, `{"id":1}`}
if !reflect.DeepEqual(got, want) {
t.Fatalf("formatJqResults() = %#v, want %#v", got, want)
}
}

func TestFormatJqExpectedValueInterpolatesOnlyStrings(t *testing.T) {
variables := map[string]string{"name": "Allan"}

gotString := formatJqExpectedValue(api.JqExpectedResult{
Type: api.JqTypeString,
Value: "hello ${name}",
}, variables)
if gotString != `"hello Allan"` {
t.Fatalf("expected interpolated string value, got %q", gotString)
}

gotInt := formatJqExpectedValue(api.JqExpectedResult{
Type: api.JqTypeInt,
Value: "${name}",
}, variables)
if gotInt != `"${name}"` {
t.Fatalf("expected non-string jq type to avoid interpolation, got %q", gotInt)
}
}

func TestValFromJqPath(t *testing.T) {
tests := []struct {
name string
Expand Down
29 changes: 10 additions & 19 deletions checks/local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,28 +73,19 @@ func TestLocalSubmissionEventReportsFirstFailure(t *testing.T) {
}
}

func TestEvaluateCLICommandReportsStdoutVariableParseError(t *testing.T) {
cliData := api.CLIData{Steps: []api.CLIStep{
{CLICommand: &api.CLIStepCLICommand{Tests: []api.CLICommandTest{
{ExitCode: intPtr(0)},
}}},
}}
results := []api.CLIStepResult{
{CLICommandResult: &api.CLICommandResult{
ExitCode: 0,
Err: "invalid stdout variable configuration",
}},
}
func TestEvaluateCLICommandReportsExecutionError(t *testing.T) {
const message = "invalid stdout variable configuration"
failure := evaluateCLICommandTests(
0,
api.CLIStepCLICommand{},
api.CLICommandResult{Err: message},
)

event := LocalSubmissionEvent(cliData, results)
if event.ResultSlug != api.VerificationResultSlugFailure {
t.Fatalf("ResultSlug = %q, want failure", event.ResultSlug)
}
if event.StructuredErrCLI == nil {
if failure == nil {
t.Fatal("expected structured failure")
}
if event.StructuredErrCLI.ErrorMessage != "invalid stdout variable configuration" {
t.Fatalf("ErrorMessage = %q, want stdout variable error", event.StructuredErrCLI.ErrorMessage)
if failure.ErrorMessage != message {
t.Fatalf("ErrorMessage = %q, want %q", failure.ErrorMessage, message)
}
}

Expand Down
43 changes: 3 additions & 40 deletions checks/runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package checks
import (
"net/http"
"net/http/httptest"
"reflect"
"testing"

api "github.com/bootdotdev/bootdev/client"
Expand Down Expand Up @@ -155,64 +156,26 @@ func TestApplySubmissionResultsStopsAfterFailedHTTPTest(t *testing.T) {

func applySubmissionResultsMessages(cliData api.CLIData, failure *api.StructuredErrCLI) []tea.Msg {
ch := make(chan tea.Msg)
done := make(chan struct{})
go func() {
defer close(ch)
defer close(done)
ApplySubmissionResults(cliData, failure, ch)
}()

var msgs []tea.Msg
for msg := range ch {
msgs = append(msgs, msg)
}
<-done
return msgs
}

func assertMessages(t *testing.T, got []tea.Msg, want []tea.Msg) {
t.Helper()

if len(got) != len(want) {
t.Fatalf("got %d messages, want %d\ngot: %#v\nwant: %#v", len(got), len(want), got, want)
}
for i := range want {
assertMessage(t, i, got[i], want[i])
}
}

func assertMessage(t *testing.T, index int, got tea.Msg, want tea.Msg) {
t.Helper()

switch want := want.(type) {
case messages.ResolveStepMsg:
got, ok := got.(messages.ResolveStepMsg)
if !ok {
t.Fatalf("message %d = %T, want %T", index, got, want)
}
if got.Index != want.Index || !sameBoolPtr(got.Passed, want.Passed) {
t.Fatalf("message %d = %#v, want %#v", index, got, want)
}
case messages.ResolveTestMsg:
got, ok := got.(messages.ResolveTestMsg)
if !ok {
t.Fatalf("message %d = %T, want %T", index, got, want)
}
if got.StepIndex != want.StepIndex || got.TestIndex != want.TestIndex || !sameBoolPtr(got.Passed, want.Passed) {
t.Fatalf("message %d = %#v, want %#v", index, got, want)
}
default:
t.Fatalf("unsupported wanted message type %T", want)
if !reflect.DeepEqual(got, want) {
t.Fatalf("messages = %#v, want %#v", got, want)
}
}

func boolPtr(v bool) *bool {
return &v
}

func sameBoolPtr(a *bool, b *bool) bool {
if a == nil || b == nil {
return a == b
}
return *a == *b
}
60 changes: 0 additions & 60 deletions client/auth_test.go

This file was deleted.

6 changes: 0 additions & 6 deletions cmd/logout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,3 @@ func TestLogoutReturnsConfigWriteError(t *testing.T) {
t.Fatalf("logout() error = %q, want config write error", err)
}
}

func TestLogoutCommandDoesNotRequireAuthentication(t *testing.T) {
if logoutCmd.PreRun != nil {
t.Fatal("logout command unexpectedly requires authentication")
}
}
8 changes: 1 addition & 7 deletions render/variables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,7 @@ func TestHTTPVariableSections(t *testing.T) {
},
}

got := renderVariableSection("Variables Saved", savedVariablesForHTTPResult(result))
got += renderVariableSection("Variables Missing", missingSaveVariablesForHTTPResult(result))
available, expectsVariables := availableVariablesForHTTPResult(result)
if !expectsVariables {
t.Fatalf("expected HTTP request to use variables")
}
got += renderVariableSection("Variables Available", available)
got := printHTTPRequestResult(result)

wantContains := []string{
"Variables Saved:",
Expand Down
Loading