diff --git a/cmd/swarm/swarm-snapshot/create.go b/cmd/swarm/swarm-snapshot/create.go index 72a1446f11..e5236b865d 100644 --- a/cmd/swarm/swarm-snapshot/create.go +++ b/cmd/swarm/swarm-snapshot/create.go @@ -38,8 +38,9 @@ import ( cli "gopkg.in/urfave/cli.v1" ) -const noConnectionTimeout = 2 * time.Second +const noConnectionTimeout = 1 * time.Second +// create is used as the entry function for "create" app command. func create(ctx *cli.Context) error { log.PrintOrigins(true) log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(ctx.Int("verbosity")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) @@ -51,14 +52,16 @@ func create(ctx *cli.Context) error { if err != nil { return err } - return createSnapshot(filename, ctx.Int("nodes"), ctx.String("services")) + return createSnapshot(filename, ctx.Int("nodes"), strings.Split(ctx.String("services"), ",")) } -func createSnapshot(filename string, nodes int, services string) (err error) { +// createSnapshot creates a new snapshot on filesystem with provided filename, +// number of nodes and service names. +func createSnapshot(filename string, nodes int, services []string) (err error) { log.Debug("create snapshot", "filename", filename, "nodes", nodes, "services", services) sim := simulation.New(map[string]simulation.ServiceFunc{ - bzzServiceName: func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { + "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { addr := network.NewAddr(ctx.Config.Node()) kad := network.NewKademlia(addr.Over(), network.NewKadParams()) hp := network.NewHiveParams() @@ -80,6 +83,8 @@ func createSnapshot(filename string, nodes int, services string) (err error) { return fmt.Errorf("add nodes: %v", err) } + // wait for two some time to ensure no connections + // are established events := make(chan *simulations.Event) sub := sim.Net.Events().Subscribe(events) select { @@ -109,19 +114,21 @@ func createSnapshot(filename string, nodes int, services string) (err error) { var snap *simulations.Snapshot if len(services) > 0 { - addServices := strings.Split(services, ",") + // If service names are provided, include them in the snapshot. + // But, check if "bzz" service is not among them to remove it + // form the snapshot as it exists on snapshot creation. var removeServices []string - var hasBzz bool - for _, s := range addServices { - if s == bzzServiceName { - hasBzz = true + var wantBzz bool + for _, s := range services { + if s == "bzz" { + wantBzz = true break } } - if !hasBzz { - removeServices = append(removeServices, bzzServiceName) + if !wantBzz { + removeServices = []string{"bzz"} } - snap, err = sim.Net.SnapshotWithServices(addServices, removeServices) + snap, err = sim.Net.SnapshotWithServices(services, removeServices) } else { snap, err = sim.Net.Snapshot() } @@ -135,6 +142,8 @@ func createSnapshot(filename string, nodes int, services string) (err error) { return ioutil.WriteFile(filename, jsonsnapshot, 0666) } +// touchPath creates an empty file and all subdirectories +// that are missing. func touchPath(filename string) (string, error) { if path.IsAbs(filename) { if _, err := os.Stat(filename); err == nil { @@ -164,6 +173,5 @@ func touchPath(filename string) (string, error) { } } - filename = filePath - return filename, nil + return filePath, nil } diff --git a/cmd/swarm/swarm-snapshot/create_test.go b/cmd/swarm/swarm-snapshot/create_test.go index e8f419376a..603a5f4100 100644 --- a/cmd/swarm/swarm-snapshot/create_test.go +++ b/cmd/swarm/swarm-snapshot/create_test.go @@ -29,7 +29,9 @@ import ( "github.com/ethereum/go-ethereum/p2p/simulations" ) -//TestSnapshotCreate is a high level e2e test that tests for snapshot generation +// TestSnapshotCreate is a high level e2e test that tests for snapshot generation. +// It runs a few "create" commands with different flag values and loads generated +// snapshot files to validate their content. func TestSnapshotCreate(t *testing.T) { for _, v := range []struct { name string @@ -48,8 +50,8 @@ func TestSnapshotCreate(t *testing.T) { services: "stream,pss,zorglub", }, { - name: "services with " + bzzServiceName, - services: bzzServiceName + ",pss", + name: "services with bzz", + services: "bzz,pss", }, } { t.Run(v.name, func(t *testing.T) { @@ -75,8 +77,8 @@ func TestSnapshotCreate(t *testing.T) { testCmd := runSnapshot(t, append(args, file.Name())...) testCmd.ExpectExit() - if testCmd.ExitStatus() != 0 { - t.Fatal("expected exit code 0") + if code := testCmd.ExitStatus(); code != 0 { + t.Fatalf("command exit code %v, expected 0", code) } f, err := os.Open(file.Name()) @@ -117,8 +119,10 @@ func TestSnapshotCreate(t *testing.T) { if v.services != "" { wantServices = strings.Split(v.services, ",") } else { - wantServices = []string{bzzServiceName} + wantServices = []string{"bzz"} } + // sort service names so they can be comparable + // as strings to every node sorted services sort.Strings(wantServices) for i, n := range snap.Nodes { diff --git a/cmd/swarm/swarm-snapshot/main.go b/cmd/swarm/swarm-snapshot/main.go index 238e1d991d..6bf9e76b9e 100644 --- a/cmd/swarm/swarm-snapshot/main.go +++ b/cmd/swarm/swarm-snapshot/main.go @@ -26,10 +26,8 @@ import ( var gitCommit string // Git SHA1 commit hash of the release (set via linker flags) -const ( - defaultNodes = 10 - bzzServiceName = "bzz" -) +// default value for "create" command --nodes flag +const defaultNodes = 10 func main() { err := newApp().Run(os.Args) @@ -39,12 +37,15 @@ func main() { } } +// newApp construct a new instance of Swarm Snapshot Utility. +// Method Run is called on it in the main function and in tests. func newApp() (app *cli.App) { app = utils.NewApp(gitCommit, "Swarm Snapshot Utility") app.Name = "swarm-snapshot" app.Usage = "" + // app flags (for all commands) app.Flags = []cli.Flag{ cli.IntFlag{ Name: "verbosity", @@ -59,6 +60,9 @@ func newApp() (app *cli.App) { Aliases: []string{"c"}, Usage: "create a swarm snapshot", Action: create, + // Flags only for "create" command. + // Allow app flags to be specified after the + // command argument. Flags: append(app.Flags, cli.IntFlag{ Name: "nodes", @@ -67,7 +71,7 @@ func newApp() (app *cli.App) { }, cli.StringFlag{ Name: "services", - Value: bzzServiceName, + Value: "bzz", Usage: "comma separated list of services to boot the nodes with", }, ), @@ -77,7 +81,9 @@ func newApp() (app *cli.App) { Aliases: []string{"v"}, Usage: "verify a swarm snapshot", Action: verify, - Flags: app.Flags, + // Allow app flags to be specified after the + // command argument. + Flags: app.Flags, }, } diff --git a/cmd/swarm/swarm-snapshot/verify.go b/cmd/swarm/swarm-snapshot/verify.go index 398335b423..43bde1fdc1 100644 --- a/cmd/swarm/swarm-snapshot/verify.go +++ b/cmd/swarm/swarm-snapshot/verify.go @@ -32,6 +32,7 @@ import ( cli "gopkg.in/urfave/cli.v1" ) +// verify is used as the entry function for "verify" app command. func verify(ctx *cli.Context) error { log.PrintOrigins(true) log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(ctx.Int("verbosity")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) @@ -42,9 +43,11 @@ func verify(ctx *cli.Context) error { return verifySnapshot(ctx.Args()[0]) } +// verifySnapshot constructs a simulation, uploads a snapshot from +// a file with provided filename and validates that kademlia is healthy. func verifySnapshot(filename string) (err error) { sim := simulation.New(map[string]simulation.ServiceFunc{ - bzzServiceName: func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { + "bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { addr := network.NewAddr(ctx.Config.Node()) kad := network.NewKademlia(addr.Over(), network.NewKadParams()) hp := network.NewHiveParams() diff --git a/cmd/swarm/swarm-snapshot/verify_test.go b/cmd/swarm/swarm-snapshot/verify_test.go index 2cdedee01b..f8c615bf84 100644 --- a/cmd/swarm/swarm-snapshot/verify_test.go +++ b/cmd/swarm/swarm-snapshot/verify_test.go @@ -20,6 +20,8 @@ import ( "testing" ) +// TestSnapshotVerify executes "verify" command with a +// pregenerated snapshot file that is valid. func TestSnapshotVerify(t *testing.T) { snap := runSnapshot(t, "verify", @@ -27,7 +29,7 @@ func TestSnapshotVerify(t *testing.T) { ) snap.ExpectExit() - if snap.ExitStatus() != 0 { - t.Fatal("expected exit code 0") + if code := snap.ExitStatus(); code != 0 { + t.Fatalf("command exit code %v, expected 0", code) } }