Skip to content

Commit

Permalink
Merge pull request #1253 from teamkeel/test-cmd
Browse files Browse the repository at this point in the history
chore: refactor test command to just pipe vitest output
  • Loading branch information
jonbretman authored Oct 24, 2023
2 parents ee8a839 + b7cb3ab commit 8a17c11
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 316 deletions.
84 changes: 1 addition & 83 deletions cmd/program/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"context"
"crypto/rsa"
"crypto/x509"
"database/sql"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
Expand All @@ -30,7 +28,6 @@ import (
"github.com/teamkeel/keel/proto"
"github.com/teamkeel/keel/schema"
"github.com/teamkeel/keel/schema/reader"
"github.com/teamkeel/keel/testing"
)

//go:embed default.pem
Expand Down Expand Up @@ -226,39 +223,8 @@ func StartDatabase(reset bool, mode int, projectDirectory string) tea.Cmd {
}
}

if mode != ModeTest {
return StartDatabaseMsg{
ConnInfo: connInfo,
}
}

mainDB, err := sql.Open("pgx/v5", connInfo.String())
if err != nil {
return StartDatabaseMsg{
Err: err,
}
}

_, err = mainDB.Exec(`
DROP DATABASE IF EXISTS keel_test
`)
if err != nil {
return StartDatabaseMsg{
Err: err,
}
}

_, err = mainDB.Exec(`
CREATE DATABASE keel_test
`)
if err != nil {
return StartDatabaseMsg{
Err: err,
}
}

return StartDatabaseMsg{
ConnInfo: connInfo.WithDatabase("keel_test"),
ConnInfo: connInfo,
}
}
}
Expand Down Expand Up @@ -391,9 +357,6 @@ type FunctionsOutputMsg struct {
func StartFunctions(m *Model) tea.Cmd {
return func() tea.Msg {
envType := "development"
if m.Mode == ModeTest {
envType = "test"
}

envVars := m.Config.GetEnvVars(envType)
envVars["KEEL_DB_CONN_TYPE"] = "pg"
Expand Down Expand Up @@ -535,50 +498,6 @@ func StartWatcher(dir string, ch chan tea.Msg) tea.Cmd {
}
}

type RunTestsMsg struct {
Err error
Output string
}

func RunTests(dir string, port string, cfg *config.ProjectConfig, conn *db.ConnectionInfo, pattern string) tea.Cmd {
return func() tea.Msg {
args := []string{
"vitest",
"run",
"--color",
"--reporter", "verbose",
"--config", "./.build/vitest.config.mjs",
}

if pattern != "" {
args = append(args, "--testNamePattern", pattern)
}

cmd := exec.Command("npx", args...)
cmd.Dir = dir
cmd.Env = os.Environ()

envVars := cfg.GetEnvVars("test")
envVars["KEEL_TESTING_ACTIONS_API_URL"] = fmt.Sprintf("http://localhost:%s/%s/json", port, testing.ActionApiPath)
envVars["KEEL_TESTING_JOBS_URL"] = fmt.Sprintf("http://localhost:%s/%s/json", port, testing.JobPath)
envVars["KEEL_TESTING_SUBSCRIBERS_URL"] = fmt.Sprintf("http://localhost:%s/%s/json", port, testing.SubscriberPath)
envVars["KEEL_DB_CONN_TYPE"] = "pg"
envVars["KEEL_DB_CONN"] = conn.String()
envVars["NODE_OPTIONS"] = "--no-warnings"
envVars["KEEL_DEFAULT_PK"] = base64.StdEncoding.EncodeToString(defaultPem)

for key, value := range envVars {
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value))
}

b, err := cmd.CombinedOutput()
return RunTestsMsg{
Output: string(b),
Err: err,
}
}
}

// LoadSecrets lists secrets from the given file and returns a command
func LoadSecrets(path, environment string) (map[string]string, error) {
projectPath, err := filepath.Abs(path)
Expand All @@ -593,7 +512,6 @@ func LoadSecrets(path, environment string) (map[string]string, error) {
secrets, err := config.GetSecrets(path, environment)
if err != nil {
return nil, err

}
return secrets, nil
}
Expand Down
128 changes: 20 additions & 108 deletions cmd/program/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/rs/cors"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
"github.com/teamkeel/keel/cmd/database"
"github.com/teamkeel/keel/codegen"
Expand All @@ -26,10 +25,8 @@ import (
"github.com/teamkeel/keel/node"
"github.com/teamkeel/keel/proto"
"github.com/teamkeel/keel/runtime"
"github.com/teamkeel/keel/runtime/apis/httpjson"
"github.com/teamkeel/keel/runtime/runtimectx"
"github.com/teamkeel/keel/schema/reader"
"github.com/teamkeel/keel/testing"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
Expand All @@ -40,7 +37,6 @@ import (

const (
ModeRun = iota
ModeTest
)

const (
Expand Down Expand Up @@ -180,15 +176,10 @@ func (m *Model) Init() tea.Cmd {
m.runtimeRequestsCh = make(chan tea.Msg, 1)
m.functionsLogCh = make(chan tea.Msg, 1)
m.watcherCh = make(chan tea.Msg, 1)
m.Environment = lo.Ternary(m.Mode == ModeTest, "test", "development")
m.Environment = "development"

switch m.Mode {
case ModeRun, ModeTest:
m.Status = StatusCheckingDependencies
return CheckDependencies()
default:
return nil
}
m.Status = StatusCheckingDependencies
return CheckDependencies()
}

func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
Expand Down Expand Up @@ -279,29 +270,9 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.Secrets = msg.Secrets

if m.Err != nil {
if m.Mode == ModeTest {
return m, tea.Quit
}
return m, nil
}

// For test mode inject a special API that contains all models
// This is so in tests we can invoke any action
if m.Mode == ModeTest {
testApi := &proto.Api{
Name: testing.ActionApiPath,
}
for _, m := range m.Schema.Models {
testApi.ApiModels = append(testApi.ApiModels, &proto.ApiModel{
ModelName: m.Name,
})
}

m.Schema.Apis = append(m.Schema.Apis, testApi)
m.JobHandler = runtime.NewJobHandler(m.Schema)
m.SubscriberHandler = runtime.NewSubscriberHandler(m.Schema)
}

cors := cors.New(cors.Options{
AllowOriginFunc: func(origin string) bool {
return true
Expand All @@ -326,9 +297,6 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.MigrationChanges = msg.Changes

if m.Err != nil {
if m.Mode == ModeTest {
return m, tea.Quit
}
return m, nil
}

Expand All @@ -343,17 +311,9 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case UpdateFunctionsMsg:
m.Err = msg.Err
if m.Err != nil {
if m.Mode == ModeTest {
return m, tea.Quit
}
return m, nil
}

if m.Mode == ModeTest && !node.HasFunctions(m.Schema) {
m.Status = StatusRunning
return m, RunTests(m.ProjectDir, m.Port, m.Config, m.DatabaseConnInfo, m.TestPattern)
}

// If functions already running nothing to do
if m.FunctionsServer != nil {
_ = m.FunctionsServer.Rebuild()
Expand All @@ -380,10 +340,6 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.Status = StatusRunning
}

if m.Mode == ModeTest {
return m, RunTests(m.ProjectDir, m.Port, m.Config, m.DatabaseConnInfo, m.TestPattern)
}

return m, nil
case FunctionsOutputMsg:
log := &FunctionLog{
Expand All @@ -396,7 +352,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
NextMsgCommand(m.functionsLogCh),
}

if m.Mode == ModeRun || m.Mode == ModeTest {
if m.Mode == ModeRun {
cmds = append(cmds, tea.Println(renderFunctionLog(log)))
}

Expand Down Expand Up @@ -459,66 +415,28 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
)
}

envVars := m.Config.GetEnvVars(lo.Ternary(m.Mode == ModeTest, "test", "development"))
envVars := m.Config.GetEnvVars("development")
for k, v := range envVars {
os.Setenv(k, v)
}

if m.Mode == ModeTest {
// Synchronous event handling for keel test.
ctx, err := events.WithEventHandler(ctx, func(ctx context.Context, subscriber string, event *events.Event, traceparent string) error {
return runtime.NewSubscriberHandler(m.Schema).RunSubscriber(ctx, subscriber, event)
})
if err != nil {
m.Err = err
return m, tea.Quit
}

pathParts := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
if len(pathParts) != 3 {
w.WriteHeader(http.StatusNotFound)
}

switch pathParts[0] {
case testing.ActionApiPath:
r = msg.r.WithContext(ctx)
m.RuntimeHandler.ServeHTTP(msg.w, r)
case testing.JobPath:
err := testing.HandleJobExecutorRequest(ctx, m.Schema, pathParts[2], r)
if err != nil {
response := httpjson.NewErrorResponse(ctx, err, nil)
w.WriteHeader(response.Status)
_, _ = w.Write(response.Body)
}
case testing.SubscriberPath:
err := testing.HandleSubscriberExecutorRequest(ctx, m.Schema, pathParts[2], r)
if err != nil {
response := httpjson.NewErrorResponse(ctx, err, nil)
w.WriteHeader(response.Status)
_, _ = w.Write(response.Body)
}
default:
w.WriteHeader(http.StatusNotFound)
}
} else {
// Synchronous event handling for keel run.
// TODO: make asynchronous
ctx, err := events.WithEventHandler(ctx, func(ctx context.Context, subscriber string, event *events.Event, traceparent string) error {
return runtime.NewSubscriberHandler(m.Schema).RunSubscriber(ctx, subscriber, event)
})
if err != nil {
m.Err = err
return m, tea.Quit
}
// Synchronous event handling for keel run.
// TODO: make asynchronous
ctx, err := events.WithEventHandler(ctx, func(ctx context.Context, subscriber string, event *events.Event, traceparent string) error {
return runtime.NewSubscriberHandler(m.Schema).RunSubscriber(ctx, subscriber, event)
})
if err != nil {
m.Err = err
return m, tea.Quit
}

// In run mode we accept any external issuers but the tokens need to be signed correctly
ctx = runtimectx.WithAuthConfig(ctx, runtimectx.AuthConfig{
AllowAnyIssuers: true,
})
// In run mode we accept any external issuers but the tokens need to be signed correctly
ctx = runtimectx.WithAuthConfig(ctx, runtimectx.AuthConfig{
AllowAnyIssuers: true,
})

r = msg.r.WithContext(ctx)
m.RuntimeHandler.ServeHTTP(msg.w, r)
}
r = msg.r.WithContext(ctx)
m.RuntimeHandler.ServeHTTP(msg.w, r)

for k := range envVars {
os.Unsetenv(k)
Expand All @@ -540,10 +458,6 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
LoadSchema(m.ProjectDir, m.Environment),
)

case RunTestsMsg:
m.Err = msg.Err
m.TestOutput = msg.Output
return m, tea.Quit
}

return m, nil
Expand All @@ -562,8 +476,6 @@ func (m *Model) View() string {
switch m.Mode {
case ModeRun:
b.WriteString(renderRun(m))
case ModeTest:
b.WriteString(renderTest(m))
}

if m.Err != nil {
Expand Down
17 changes: 0 additions & 17 deletions cmd/program/views.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,6 @@ import (
"github.com/teamkeel/keel/schema/validation/errorhandling"
)

func renderTest(m *Model) string {
b := strings.Builder{}

if m.TestOutput != "" {
b.WriteString(m.TestOutput)
} else {
switch m.Status {
case StatusRunning:
b.WriteString("🏃‍♂️ Running tests\n")
default:
b.WriteString("⏳ Setting up tests\n")
}
}

return b.String()
}

func renderRun(m *Model) string {
b := strings.Builder{}
if m.Status == StatusQuitting {
Expand Down
Loading

0 comments on commit 8a17c11

Please sign in to comment.