Commit 40728a8b authored by Yann Hodique's avatar Yann Hodique Committed by GitHub

fix(kurtosis-devnet): make main tests self-contained (#13605)

parent 3d577f8e
......@@ -54,16 +54,21 @@ type staticServer struct {
*serve.Server
}
func launchStaticServer(ctx context.Context, cfg *config) (*staticServer, func(), error) {
type Main struct {
cfg *config
newDeployer func(opts ...kurtosis.KurtosisDeployerOptions) (deployer, error)
}
func (m *Main) launchStaticServer(ctx context.Context) (*staticServer, func(), error) {
// we will serve content from this tmpDir for the duration of the devnet creation
tmpDir, err := os.MkdirTemp("", cfg.enclave)
tmpDir, err := os.MkdirTemp("", m.cfg.enclave)
if err != nil {
return nil, nil, fmt.Errorf("error creating temporary directory: %w", err)
}
server := serve.NewServer(
serve.WithStaticDir(tmpDir),
serve.WithHostname(cfg.localHostName),
serve.WithHostname(m.cfg.localHostName),
)
if err := server.Start(ctx); err != nil {
return nil, nil, fmt.Errorf("error starting server: %w", err)
......@@ -82,14 +87,14 @@ func launchStaticServer(ctx context.Context, cfg *config) (*staticServer, func()
}, nil
}
func localDockerImageOption(cfg *config) tmpl.TemplateContextOptions {
func (m *Main) localDockerImageOption() tmpl.TemplateContextOptions {
dockerBuilder := build.NewDockerBuilder(
build.WithDockerBaseDir(cfg.baseDir),
build.WithDockerDryRun(cfg.dryRun),
build.WithDockerBaseDir(m.cfg.baseDir),
build.WithDockerDryRun(m.cfg.dryRun),
)
imageTag := func(projectName string) string {
return fmt.Sprintf("%s:%s", projectName, cfg.enclave)
return fmt.Sprintf("%s:%s", projectName, m.cfg.enclave)
}
return tmpl.WithFunction("localDockerImage", func(projectName string) (string, error) {
......@@ -97,15 +102,15 @@ func localDockerImageOption(cfg *config) tmpl.TemplateContextOptions {
})
}
func localContractArtifactsOption(cfg *config, server *staticServer) tmpl.TemplateContextOptions {
contractsBundle := fmt.Sprintf("contracts-bundle-%s.tar.gz", cfg.enclave)
func (m *Main) localContractArtifactsOption(server *staticServer) tmpl.TemplateContextOptions {
contractsBundle := fmt.Sprintf("contracts-bundle-%s.tar.gz", m.cfg.enclave)
contractsBundlePath := func(_ string) string {
return filepath.Join(server.dir, contractsBundle)
}
contractBuilder := build.NewContractBuilder(
build.WithContractBaseDir(cfg.baseDir),
build.WithContractDryRun(cfg.dryRun),
build.WithContractBaseDir(m.cfg.baseDir),
build.WithContractDryRun(m.cfg.dryRun),
)
return tmpl.WithFunction("localContractArtifacts", func(layer string) (string, error) {
......@@ -125,10 +130,10 @@ func localContractArtifactsOption(cfg *config, server *staticServer) tmpl.Templa
})
}
func localPrestateOption(cfg *config, server *staticServer) tmpl.TemplateContextOptions {
func (m *Main) localPrestateOption(server *staticServer) tmpl.TemplateContextOptions {
prestateBuilder := build.NewPrestateBuilder(
build.WithPrestateBaseDir(cfg.baseDir),
build.WithPrestateDryRun(cfg.dryRun),
build.WithPrestateBaseDir(m.cfg.baseDir),
build.WithPrestateDryRun(m.cfg.dryRun),
)
return tmpl.WithFunction("localPrestate", func() (string, error) {
......@@ -146,7 +151,7 @@ func localPrestateOption(cfg *config, server *staticServer) tmpl.TemplateContext
url := fmt.Sprintf("%s/%s", server.URL(), relPath)
if cfg.dryRun {
if m.cfg.dryRun {
return url, nil
}
......@@ -194,16 +199,16 @@ func localPrestateOption(cfg *config, server *staticServer) tmpl.TemplateContext
})
}
func renderTemplate(cfg *config, server *staticServer) (*bytes.Buffer, error) {
func (m *Main) renderTemplate(server *staticServer) (*bytes.Buffer, error) {
opts := []tmpl.TemplateContextOptions{
localDockerImageOption(cfg),
localContractArtifactsOption(cfg, server),
localPrestateOption(cfg, server),
m.localDockerImageOption(),
m.localContractArtifactsOption(server),
m.localPrestateOption(server),
}
// Read and parse the data file if provided
if cfg.dataFile != "" {
data, err := os.ReadFile(cfg.dataFile)
if m.cfg.dataFile != "" {
data, err := os.ReadFile(m.cfg.dataFile)
if err != nil {
return nil, fmt.Errorf("error reading data file: %w", err)
}
......@@ -217,7 +222,7 @@ func renderTemplate(cfg *config, server *staticServer) (*bytes.Buffer, error) {
}
// Open template file
tmplFile, err := os.Open(cfg.templateFile)
tmplFile, err := os.Open(m.cfg.templateFile)
if err != nil {
return nil, fmt.Errorf("error opening template file: %w", err)
}
......@@ -235,7 +240,7 @@ func renderTemplate(cfg *config, server *staticServer) (*bytes.Buffer, error) {
return buf, nil
}
func deploy(ctx context.Context, cfg *config, r io.Reader) error {
func (m *Main) deploy(ctx context.Context, r io.Reader) error {
// Create a multi reader to output deployment input to stdout
buf := bytes.NewBuffer(nil)
tee := io.TeeReader(r, buf)
......@@ -246,33 +251,46 @@ func deploy(ctx context.Context, cfg *config, r io.Reader) error {
return fmt.Errorf("error copying deployment input: %w", err)
}
kurtosisDeployer, err := kurtosis.NewKurtosisDeployer(
kurtosis.WithKurtosisBaseDir(cfg.baseDir),
kurtosis.WithKurtosisDryRun(cfg.dryRun),
kurtosis.WithKurtosisPackageName(cfg.kurtosisPackage),
kurtosis.WithKurtosisEnclave(cfg.enclave),
)
opts := []kurtosis.KurtosisDeployerOptions{
kurtosis.WithKurtosisBaseDir(m.cfg.baseDir),
kurtosis.WithKurtosisDryRun(m.cfg.dryRun),
kurtosis.WithKurtosisPackageName(m.cfg.kurtosisPackage),
kurtosis.WithKurtosisEnclave(m.cfg.enclave),
}
d, err := m.newDeployer(opts...)
if err != nil {
return fmt.Errorf("error creating kurtosis deployer: %w", err)
}
env, err := kurtosisDeployer.Deploy(ctx, buf)
env, err := d.Deploy(ctx, buf)
if err != nil {
return fmt.Errorf("error deploying kurtosis: %w", err)
return fmt.Errorf("error deploying kurtosis package: %w", err)
}
if err := writeEnvironment(m.cfg.environment, env); err != nil {
return fmt.Errorf("error writing environment: %w", err)
}
envOutput := os.Stdout
if cfg.environment != "" {
envOutput, err = os.Create(cfg.environment)
return nil
}
type deployer interface {
Deploy(ctx context.Context, input io.Reader) (*kurtosis.KurtosisEnvironment, error)
}
func writeEnvironment(path string, env *kurtosis.KurtosisEnvironment) error {
out := os.Stdout
if path != "" {
var err error
out, err = os.Create(path)
if err != nil {
return fmt.Errorf("error creating environment file: %w", err)
}
defer envOutput.Close()
} else {
log.Println("\nEnvironment description:")
defer out.Close()
}
enc := json.NewEncoder(envOutput)
enc := json.NewEncoder(out)
enc.SetIndent("", " ")
if err := enc.Encode(env); err != nil {
return fmt.Errorf("error encoding environment: %w", err)
......@@ -281,22 +299,22 @@ func deploy(ctx context.Context, cfg *config, r io.Reader) error {
return nil
}
func mainFunc(cfg *config) error {
func (m *Main) run() error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
server, cleanup, err := launchStaticServer(ctx, cfg)
server, cleanup, err := m.launchStaticServer(ctx)
if err != nil {
return fmt.Errorf("error launching static server: %w", err)
}
defer cleanup()
buf, err := renderTemplate(cfg, server)
buf, err := m.renderTemplate(server)
if err != nil {
return fmt.Errorf("error rendering template: %w", err)
}
return deploy(ctx, cfg, buf)
return m.deploy(ctx, buf)
}
func mainAction(c *cli.Context) error {
......@@ -304,7 +322,13 @@ func mainAction(c *cli.Context) error {
if err != nil {
return fmt.Errorf("error parsing config: %w", err)
}
return mainFunc(cfg)
m := &Main{
cfg: cfg,
newDeployer: func(opts ...kurtosis.KurtosisDeployerOptions) (deployer, error) {
return kurtosis.NewKurtosisDeployer(opts...)
},
}
return m.run()
}
func getFlags() []cli.Flag {
......
......@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
"io"
"os"
"path/filepath"
"testing"
......@@ -15,6 +16,18 @@ import (
"github.com/urfave/cli/v2"
)
type mockDeployer struct {
dryRun bool
}
func (m *mockDeployer) Deploy(ctx context.Context, input io.Reader) (*kurtosis.KurtosisEnvironment, error) {
return &kurtosis.KurtosisEnvironment{}, nil
}
func newMockDeployer(...kurtosis.KurtosisDeployerOptions) (deployer, error) {
return &mockDeployer{dryRun: true}, nil
}
func TestParseFlags(t *testing.T) {
tests := []struct {
name string
......@@ -93,13 +106,23 @@ func TestParseFlags(t *testing.T) {
}
}
func newTestMain(cfg *config) *Main {
return &Main{
cfg: cfg,
newDeployer: func(opts ...kurtosis.KurtosisDeployerOptions) (deployer, error) {
return newMockDeployer(opts...)
},
}
}
func TestLaunchStaticServer(t *testing.T) {
cfg := &config{
localHostName: "test.local",
}
m := newTestMain(cfg)
ctx := context.Background()
server, cleanup, err := launchStaticServer(ctx, cfg)
server, cleanup, err := m.launchStaticServer(ctx)
require.NoError(t, err)
defer cleanup()
......@@ -142,12 +165,13 @@ artifacts: {{localContractArtifacts "l1"}}`
dryRun: true, // Important for tests
}
m := newTestMain(cfg)
ctx := context.Background()
server, cleanup, err := launchStaticServer(ctx, cfg)
server, cleanup, err := m.launchStaticServer(ctx)
require.NoError(t, err)
defer cleanup()
buf, err := renderTemplate(cfg, server)
buf, err := m.renderTemplate(server)
require.NoError(t, err)
// Verify template rendering
......@@ -174,7 +198,8 @@ func TestDeploy(t *testing.T) {
// Create a simple deployment configuration
deployConfig := bytes.NewBufferString(`{"test": "config"}`)
err = deploy(ctx, cfg, deployConfig)
m := newTestMain(cfg)
err = m.deploy(ctx, deployConfig)
require.NoError(t, err)
// Verify the environment file was created
......@@ -189,7 +214,6 @@ func TestDeploy(t *testing.T) {
require.NoError(t, err)
}
// TestMainFunc performs an integration test of the main function
func TestMainFunc(t *testing.T) {
// Create a temporary directory for test files
tmpDir, err := os.MkdirTemp("", "main-test")
......@@ -210,7 +234,8 @@ func TestMainFunc(t *testing.T) {
dryRun: true,
}
err = mainFunc(cfg)
m := newTestMain(cfg)
err = m.run()
require.NoError(t, err)
// Verify the environment file was created
......@@ -254,13 +279,14 @@ _prestate-build target:
dryRun: tt.dryRun,
}
m := newTestMain(cfg)
ctx := context.Background()
server, cleanup, err := launchStaticServer(ctx, cfg)
server, cleanup, err := m.launchStaticServer(ctx)
require.NoError(t, err)
defer cleanup()
// Create template context with just the prestate function
tmplCtx := tmpl.NewTemplateContext(localPrestateOption(cfg, server))
tmplCtx := tmpl.NewTemplateContext(m.localPrestateOption(server))
// Test template
template := `{"prestate": "{{localPrestate}}"}`
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment