package envtest
import (
"context"
"flag"
"fmt"
"os"
"path"
"path/filepath"
"strconv"
"sync"
"testing"
"time"
"github.com/cenkalti/backoff"
"github.com/stretchr/testify/require"
"github.com/ignite/cli/v29/ignite/pkg/cosmosfaucet"
"github.com/ignite/cli/v29/ignite/pkg/env"
"github.com/ignite/cli/v29/ignite/pkg/errors"
"github.com/ignite/cli/v29/ignite/pkg/gocmd"
"github.com/ignite/cli/v29/ignite/pkg/httpstatuschecker"
"github.com/ignite/cli/v29/ignite/pkg/xurl"
)
const (
envDoNotTrack = "DO_NOT_TRACK"
)
var (
IgniteApp = path.Join(os.TempDir(), "ignite-tests", "ignite")
IsCI, _ = strconv.ParseBool(os.Getenv("CI"))
compileBinaryOnce sync.Once
)
type Env struct {
t *testing.T
ctx context.Context
}
func New(t *testing.T) Env {
t.Helper()
ctx, cancel := context.WithCancel(t.Context())
e := Env{
t: t,
ctx: ctx,
}
cfgDir := path.Join(t.TempDir(), ".ignite")
env.SetConfigDir(cfgDir)
enableDoNotTrackEnv(t)
t.Cleanup(cancel)
compileBinaryOnce.Do(func() {
compileBinary(ctx)
})
return e
}
func compileBinary(ctx context.Context) {
wd, err := os.Getwd()
if err != nil {
panic(fmt.Sprintf("unable to get working dir: %v", err))
}
pkgs, err := gocmd.List(ctx, wd, []string{"-m", "-f={{.Dir}}", "github.com/ignite/cli/v29"})
if err != nil {
panic(fmt.Sprintf("unable to list ignite cli package: %v", err))
}
if len(pkgs) != 1 {
panic(fmt.Sprintf("expected only one package, got %d", len(pkgs)))
}
appPath := pkgs[0]
var (
output, binary = filepath.Split(IgniteApp)
path = path.Join(appPath, "ignite", "cmd", "ignite")
)
err = gocmd.BuildPath(ctx, output, binary, path, nil)
if err != nil {
panic(fmt.Sprintf("error while building binary: %v", err))
}
}
func (e Env) T() *testing.T {
return e.t
}
func (e Env) SetCleanup(f func()) {
e.t.Cleanup(f)
}
func (e Env) Ctx() context.Context {
return e.ctx
}
func (e Env) IsAppServed(ctx context.Context, apiAddr string) error {
checkAlive := func() error {
addr, err := xurl.HTTP(apiAddr)
if err != nil {
return err
}
ok, err := httpstatuschecker.Check(ctx, fmt.Sprintf("%s/cosmos/base/tendermint/v1beta1/node_info", addr))
if err == nil && !ok {
err = errors.New("waiting for app")
}
if HasTestVerboseFlag() {
fmt.Printf("IsAppServed at %s: %v\n", addr, err)
}
return err
}
return backoff.Retry(checkAlive, backoff.WithContext(backoff.NewConstantBackOff(time.Second), ctx))
}
func (e Env) IsFaucetServed(ctx context.Context, faucetClient cosmosfaucet.HTTPClient) error {
checkAlive := func() error {
_, err := faucetClient.FaucetInfo(ctx)
return err
}
return backoff.Retry(checkAlive, backoff.WithContext(backoff.NewConstantBackOff(time.Second), ctx))
}
func (e Env) TmpDir() (path string) {
return e.t.TempDir()
}
func (e Env) Home() string {
home, err := os.UserHomeDir()
require.NoError(e.t, err)
return home
}
func (e Env) AppHome(name string) string {
return filepath.Join(e.Home(), fmt.Sprintf(".%s", name))
}
func (e Env) Must(ok bool) {
if !ok {
e.t.FailNow()
}
}
func (e Env) HasFailed() bool {
return e.t.Failed()
}
func (e Env) RequireExpectations() {
e.Must(e.HasFailed())
}
func enableDoNotTrackEnv(t *testing.T) {
t.Helper()
t.Setenv(envDoNotTrack, "true")
}
func HasTestVerboseFlag() bool {
return flag.Lookup("test.v").Value.String() == "true"
}