Skip to content

Commit

Permalink
Merge branch 'main' into justin/ci
Browse files Browse the repository at this point in the history
  • Loading branch information
jtieri authored Sep 16, 2024
2 parents a2efe59 + 3ca97c4 commit 9a8280c
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 11 deletions.
54 changes: 54 additions & 0 deletions dockerutil/container_lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package dockerutil
import (
"context"
"fmt"
"io"
"net"
"regexp"
"strings"
"time"

dockertypes "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
Expand All @@ -17,6 +20,9 @@ import (
"go.uber.org/zap"
)

// Example Go/Cosmos-SDK panic format is `panic: bad Duration: time: invalid duration "bad"\n`
var panicRe = regexp.MustCompile(`panic:.*\n`)

type ContainerLifecycle struct {
log *zap.Logger
client *dockerclient.Client
Expand Down Expand Up @@ -123,7 +129,55 @@ func (c *ContainerLifecycle) StartContainer(ctx context.Context) error {
return err
}

if err := c.CheckForFailedStart(ctx, time.Second*1); err != nil {
return err
}

c.log.Info("Container started", zap.String("container", c.containerName))
return nil
}

// CheckForFailedStart checks the logs of the container for a
// panic message after a wait period to allow the container to start.
func (c *ContainerLifecycle) CheckForFailedStart(ctx context.Context, wait time.Duration) error {
time.Sleep(wait)
containerLogs, err := c.client.ContainerLogs(ctx, c.id, dockertypes.ContainerLogsOptions{
ShowStdout: true,
ShowStderr: true,
})
if err != nil {
return fmt.Errorf("failed to read logs from container %s: %w", c.containerName, err)
}
defer containerLogs.Close()

logs := new(strings.Builder)
_, err = io.Copy(logs, containerLogs)
if err != nil {
return fmt.Errorf("failed to read logs from container %s: %w", c.containerName, err)
}

if err := ParseSDKPanicFromText(logs.String()); err != nil {
// Must use Println and not the logger as there are ascii escape codes in the logs.
fmt.Printf("\nContainer name: %s.\nerror: %s.\nlogs\n%s\n", c.containerName, err.Error(), logs.String())
return fmt.Errorf("container %s failed to start: %w", c.containerName, err)
}

return nil
}

// ParsePanicFromText returns a panic line if it exists in the logs so
// that it can be returned to the user in a proper error message instead of
// hanging.
func ParseSDKPanicFromText(text string) error {
if !strings.Contains(text, "panic: ") {
return nil
}

match := panicRe.FindString(text)
if match != "" {
panicMessage := strings.TrimSpace(match)
return fmt.Errorf("%s", panicMessage)
}

return nil
}
Expand Down
64 changes: 64 additions & 0 deletions examples/cosmos/bad_genesis_params_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cosmos_test

import (
"context"
"testing"

"github.com/strangelove-ventures/interchaintest/v8"
"github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
"github.com/strangelove-ventures/interchaintest/v8/ibc"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
)

var (
badGenesis = []cosmos.GenesisKV{
cosmos.NewGenesisKV("app_state.gov.params.voting_period", "bad"),
}
)

func TestBadInputParams(t *testing.T) {
cf := interchaintest.NewBuiltinChainFactory(zaptest.NewLogger(t), []*interchaintest.ChainSpec{
{
Name: "juno",
ChainName: "juno",
Version: "v19.0.0-alpha.3",
ChainConfig: ibc.ChainConfig{
Denom: "ujuno",
Bech32Prefix: "juno",
CoinType: "118",
ModifyGenesis: cosmos.ModifyGenesis(badGenesis),
GasPrices: "0ujuno",
},
NumValidators: &numValsOne,
NumFullNodes: &numFullNodesZero,
},
})

chains, err := cf.Chains(t.Name())
require.NoError(t, err)

chain := chains[0].(*cosmos.CosmosChain)

ic := interchaintest.NewInterchain().
AddChain(chain)

ctx := context.Background()
client, network := interchaintest.DockerSetup(t)

err = ic.Build(ctx, nil, interchaintest.InterchainBuildOptions{
TestName: t.Name(),
Client: client,
NetworkID: network,
SkipPathCreation: true,
})

// failed to start chains: failed to start chain juno: PANIC: container juno-1-val-0-TestBadInputParams failed to start: panic: bad Duration: time: invalid duration "bad"
require.Error(t, err)
require.ErrorContains(t, err, "bad Duration")
t.Log("err", err)

t.Cleanup(func() {
_ = ic.Close()
})
}
22 changes: 11 additions & 11 deletions local-interchain/interchain/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,9 @@ func StartChain(installDir, chainCfgFile string, ac *types.AppStartConfig) {
select {
case <-c:
fmt.Println("\nReceived signal to stop local-ic...")
removed := dockerutil.KillAllInterchaintestContainers(ctx)
for _, r := range removed {
fmt.Println(" - ", r)
}
cancel()
os.Exit(1)
killContainer(ctx)
case <-ctx.Done():
fmt.Println("Context is done")
killContainer(ctx)
}
}()

Expand Down Expand Up @@ -186,10 +181,7 @@ func StartChain(installDir, chainCfgFile string, ac *types.AppStartConfig) {
SkipPathCreation: false,
})
if err != nil {
// calls the KillAllInterchaintestContainers(...) above
<-ctx.Done()

logger.Fatal("ic.Build", zap.Error(err))
log.Fatalf("ic.Build: %v", err)
}

if relayer != nil && len(ibcpaths) > 0 {
Expand Down Expand Up @@ -299,3 +291,11 @@ func GetTestName(chainCfgFile string) string {

return name + "ic"
}

func killContainer(ctx context.Context) {
removed := dockerutil.KillAllInterchaintestContainers(ctx)
for _, r := range removed {
fmt.Println(" - ", r)
}
os.Exit(1)
}

0 comments on commit 9a8280c

Please sign in to comment.