Some checks are pending
Docs Deploy / build_and_deploy (push) Waiting to run
Generate Docs / cli (push) Waiting to run
Generate Config Doc / cli (push) Waiting to run
Go formatting / go-formatting (push) Waiting to run
Check links / markdown-link-check (push) Waiting to run
Integration / pre-test (push) Waiting to run
Integration / test on (push) Blocked by required conditions
Integration / status (push) Blocked by required conditions
Lint / Lint Go code (push) Waiting to run
Test / test (ubuntu-latest) (push) Waiting to run
508 lines
9.7 KiB
Go
508 lines
9.7 KiB
Go
package chain_test
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"gopkg.in/yaml.v3"
|
|
|
|
chainconfig "github.com/ignite/cli/v29/ignite/config/chain"
|
|
"github.com/ignite/cli/v29/ignite/config/chain/version"
|
|
"github.com/ignite/cli/v29/ignite/config/testdata"
|
|
"github.com/ignite/cli/v29/ignite/pkg/availableport"
|
|
"github.com/ignite/cli/v29/ignite/pkg/errors"
|
|
)
|
|
|
|
func TestReadConfigVersion(t *testing.T) {
|
|
// Arrange
|
|
r := strings.NewReader("version: 42")
|
|
want := version.Version(42)
|
|
|
|
// Act
|
|
v, err := chainconfig.ReadConfigVersion(r)
|
|
|
|
// Assert
|
|
require.NoError(t, err)
|
|
require.Equal(t, want, v)
|
|
}
|
|
|
|
func TestParse(t *testing.T) {
|
|
// Arrange: Initialize a reader with the previous version
|
|
ver := chainconfig.LatestVersion - 1
|
|
r := bytes.NewReader(testdata.Versions[ver])
|
|
|
|
// Act
|
|
cfg, err := chainconfig.Parse(r)
|
|
|
|
// Assert
|
|
require.NoError(t, err)
|
|
|
|
// Assert: Parse must return the latest version
|
|
require.Equal(t, chainconfig.LatestVersion, cfg.Version)
|
|
require.Equal(t, testdata.GetLatestConfig(t), cfg)
|
|
}
|
|
|
|
func TestParseWithCurrentVersion(t *testing.T) {
|
|
// Arrange
|
|
r := bytes.NewReader(testdata.Versions[chainconfig.LatestVersion])
|
|
|
|
// Act
|
|
cfg, err := chainconfig.Parse(r)
|
|
|
|
// Assert
|
|
require.NoError(t, err)
|
|
require.Equal(t, chainconfig.LatestVersion, cfg.Version)
|
|
require.Equal(t, testdata.GetLatestConfig(t), cfg)
|
|
}
|
|
|
|
func TestParseWithUnknownVersion(t *testing.T) {
|
|
// Arrange
|
|
version := version.Version(9999)
|
|
r := strings.NewReader(fmt.Sprintf("version: %d", version))
|
|
|
|
var want *chainconfig.UnsupportedVersionError
|
|
|
|
// Act
|
|
_, err := chainconfig.Parse(r)
|
|
|
|
// Assert
|
|
require.ErrorAs(t, err, &want)
|
|
require.NotNil(t, want)
|
|
require.Equal(t, want.Version, version)
|
|
}
|
|
|
|
func TestParseNetworkWithCurrentVersion(t *testing.T) {
|
|
// Arrange
|
|
r := bytes.NewReader(testdata.NetworkConfig)
|
|
|
|
// Act
|
|
cfg, err := chainconfig.ParseNetwork(r)
|
|
|
|
// Assert
|
|
require.NoError(t, err)
|
|
|
|
// Assert: Parse must return the latest version
|
|
require.Equal(t, chainconfig.LatestVersion, cfg.Version)
|
|
require.Equal(t, testdata.GetLatestNetworkConfig(t).Accounts, cfg.Accounts)
|
|
require.Equal(t, testdata.GetLatestNetworkConfig(t).Genesis, cfg.Genesis)
|
|
}
|
|
|
|
func TestParseNetworkWithInvalidData(t *testing.T) {
|
|
// Arrange
|
|
r := bytes.NewReader(testdata.Versions[chainconfig.LatestVersion])
|
|
|
|
// Act
|
|
_, err := chainconfig.ParseNetwork(r)
|
|
|
|
// Assert error
|
|
require.True(
|
|
t,
|
|
strings.Contains(
|
|
err.Error(),
|
|
"config is not valid: no validators can be used in config for network genesis",
|
|
),
|
|
)
|
|
}
|
|
|
|
func TestHandleIncludes(t *testing.T) {
|
|
server := startTestServer(t)
|
|
|
|
tests := []struct {
|
|
name string
|
|
baseConfig string
|
|
expected string
|
|
err error
|
|
}{
|
|
{
|
|
name: "Single valid include",
|
|
baseConfig: `
|
|
version: 1
|
|
client:
|
|
typescript:
|
|
path: original
|
|
include:
|
|
- "./testdata/include1.yml"
|
|
`,
|
|
|
|
expected: `
|
|
include:
|
|
- ./testdata/include1.yml
|
|
validation: sovereign
|
|
version: 1
|
|
build:
|
|
proto:
|
|
path: proto
|
|
accounts:
|
|
- name: bob
|
|
coins:
|
|
- 10000token
|
|
- 100000000stake
|
|
faucet:
|
|
name: danilo
|
|
coins:
|
|
- 5token
|
|
- 100000stake
|
|
host: 0.0.0.0:4500
|
|
client:
|
|
typescript:
|
|
path: override-1
|
|
openapi:
|
|
path: docs/static/include1.yml
|
|
exclude_list: []
|
|
validators:
|
|
- name: alice
|
|
bonded: 100000000stake`,
|
|
},
|
|
{
|
|
name: "Multiple valid includes",
|
|
baseConfig: `
|
|
version: 1
|
|
client:
|
|
typescript:
|
|
path: original
|
|
include:
|
|
- "./testdata/include1.yml"
|
|
- "./testdata/include2.yml"
|
|
`,
|
|
expected: `
|
|
include:
|
|
- ./testdata/include1.yml
|
|
- ./testdata/include2.yml
|
|
validation: sovereign
|
|
version: 1
|
|
build:
|
|
proto:
|
|
path: proto
|
|
accounts:
|
|
- name: bob
|
|
coins:
|
|
- 10000token
|
|
- 100000000stake
|
|
- name: alice
|
|
coins:
|
|
- 20000token
|
|
- 200000000stake
|
|
faucet:
|
|
name: alice
|
|
coins:
|
|
- 5token
|
|
- 100000stake
|
|
- 5token
|
|
- 100000stake
|
|
host: 0.0.0.0:4500
|
|
client:
|
|
typescript:
|
|
path: override-2
|
|
openapi:
|
|
path: docs/static/include2.yml
|
|
exclude_list: []
|
|
validators:
|
|
- name: alice
|
|
bonded: 100000000stake
|
|
- name: validator1
|
|
bonded: 100000000stake`,
|
|
},
|
|
{
|
|
name: "Invalid include file path",
|
|
baseConfig: `
|
|
version: 1
|
|
client:
|
|
typescript:
|
|
path: original
|
|
include:
|
|
- "./testdata/nonexistent.yml"`,
|
|
err: errors.New("error parsing config file: failed to open included file './testdata/nonexistent.yml'"),
|
|
},
|
|
{
|
|
name: "Empty include list",
|
|
baseConfig: `
|
|
version: 1
|
|
validation: sovereign
|
|
accounts:
|
|
- name: alice
|
|
coins:
|
|
- 10000token
|
|
include: []
|
|
faucet:
|
|
name: alice
|
|
coins:
|
|
- 5token
|
|
client:
|
|
typescript:
|
|
path: override-1
|
|
openapi:
|
|
path: docs/static/include1.yml
|
|
validators:
|
|
- name: alice
|
|
bonded: 100stake`,
|
|
expected: `
|
|
validation: sovereign
|
|
version: 1
|
|
build:
|
|
proto:
|
|
path: proto
|
|
accounts:
|
|
- name: alice
|
|
coins:
|
|
- 10000token
|
|
faucet:
|
|
name: alice
|
|
coins:
|
|
- 5token
|
|
host: 0.0.0.0:4500
|
|
client:
|
|
typescript:
|
|
path: override-1
|
|
openapi:
|
|
path: docs/static/include1.yml
|
|
exclude_list: []
|
|
validators:
|
|
- name: alice
|
|
bonded: 100stake`,
|
|
},
|
|
{
|
|
name: "Empty values include",
|
|
baseConfig: `
|
|
version: 1
|
|
include:
|
|
- "./testdata/include1.yml"
|
|
- "./testdata/include2.yml"
|
|
`,
|
|
expected: `
|
|
include:
|
|
- ./testdata/include1.yml
|
|
- ./testdata/include2.yml
|
|
validation: sovereign
|
|
version: 1
|
|
build:
|
|
proto:
|
|
path: proto
|
|
accounts:
|
|
- name: bob
|
|
coins:
|
|
- 10000token
|
|
- 100000000stake
|
|
- name: alice
|
|
coins:
|
|
- 20000token
|
|
- 200000000stake
|
|
faucet:
|
|
name: alice
|
|
coins:
|
|
- 5token
|
|
- 100000stake
|
|
- 5token
|
|
- 100000stake
|
|
host: 0.0.0.0:4500
|
|
client:
|
|
typescript:
|
|
path: override-2
|
|
openapi:
|
|
path: docs/static/include2.yml
|
|
exclude_list: []
|
|
validators:
|
|
- name: alice
|
|
bonded: 100000000stake
|
|
- name: validator1
|
|
bonded: 100000000stake`,
|
|
},
|
|
{
|
|
name: "HTTP include",
|
|
baseConfig: fmt.Sprintf(`
|
|
version: 1
|
|
validation: sovereign
|
|
accounts:
|
|
- name: alice
|
|
coins:
|
|
- 10000token
|
|
include:
|
|
- %[1]v/include1.yml
|
|
- %[1]v/include2.yml
|
|
faucet:
|
|
name: alice
|
|
coins:
|
|
- 5token
|
|
client:
|
|
typescript:
|
|
path: original
|
|
openapi:
|
|
path: docs/static/include1.yml
|
|
validators:
|
|
- name: alice
|
|
bonded: 100stake
|
|
`, server),
|
|
expected: fmt.Sprintf(`
|
|
include:
|
|
- %[1]v/include1.yml
|
|
- %[1]v/include2.yml
|
|
validation: sovereign
|
|
version: 1
|
|
build:
|
|
proto:
|
|
path: proto
|
|
accounts:
|
|
- name: alice
|
|
coins:
|
|
- 10000token
|
|
- name: bob
|
|
coins:
|
|
- 10000token
|
|
- 100000000stake
|
|
- name: alice
|
|
coins:
|
|
- 20000token
|
|
- 200000000stake
|
|
faucet:
|
|
name: alice
|
|
coins:
|
|
- 5token
|
|
- 5token
|
|
- 100000stake
|
|
- 5token
|
|
- 100000stake
|
|
host: 0.0.0.0:4500
|
|
client:
|
|
typescript:
|
|
path: override-2
|
|
openapi:
|
|
path: docs/static/include2.yml
|
|
exclude_list: []
|
|
validators:
|
|
- name: alice
|
|
bonded: 100stake
|
|
- name: alice
|
|
bonded: 100000000stake
|
|
- name: validator1
|
|
bonded: 100000000stake`, server),
|
|
},
|
|
{
|
|
name: "HTTP and local include",
|
|
baseConfig: fmt.Sprintf(`
|
|
version: 1
|
|
validation: sovereign
|
|
accounts:
|
|
- name: alice
|
|
coins:
|
|
- 10000token
|
|
include:
|
|
- %[1]v/include1.yml
|
|
- testdata/include2.yml
|
|
faucet:
|
|
name: alice
|
|
coins:
|
|
- 5token
|
|
client:
|
|
typescript:
|
|
path: original
|
|
openapi:
|
|
path: docs/static/include1.yml
|
|
validators:
|
|
- name: alice
|
|
bonded: 100stake
|
|
`, server),
|
|
expected: fmt.Sprintf(`
|
|
include:
|
|
- %[1]v/include1.yml
|
|
- testdata/include2.yml
|
|
validation: sovereign
|
|
version: 1
|
|
build:
|
|
proto:
|
|
path: proto
|
|
accounts:
|
|
- name: alice
|
|
coins:
|
|
- 10000token
|
|
- name: bob
|
|
coins:
|
|
- 10000token
|
|
- 100000000stake
|
|
- name: alice
|
|
coins:
|
|
- 20000token
|
|
- 200000000stake
|
|
faucet:
|
|
name: alice
|
|
coins:
|
|
- 5token
|
|
- 5token
|
|
- 100000stake
|
|
- 5token
|
|
- 100000stake
|
|
host: 0.0.0.0:4500
|
|
client:
|
|
typescript:
|
|
path: override-2
|
|
openapi:
|
|
path: docs/static/include2.yml
|
|
exclude_list: []
|
|
validators:
|
|
- name: alice
|
|
bonded: 100stake
|
|
- name: alice
|
|
bonded: 100000000stake
|
|
- name: validator1
|
|
bonded: 100000000stake`, server),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
baseReader := bytes.NewReader([]byte(tt.baseConfig))
|
|
baseConfig, err := chainconfig.Parse(baseReader)
|
|
if tt.err != nil {
|
|
require.Error(t, err)
|
|
require.Equal(t, tt.err.Error(), err.Error())
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
|
|
finalConfigYaml, err := yaml.Marshal(baseConfig)
|
|
require.NoError(t, err)
|
|
require.Equal(t, strings.TrimSpace(tt.expected), strings.TrimSpace(string(finalConfigYaml)))
|
|
})
|
|
}
|
|
}
|
|
|
|
func startTestServer(t *testing.T) string {
|
|
t.Helper()
|
|
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/include1.yml", func(w http.ResponseWriter, r *http.Request) {
|
|
content, err := os.ReadFile("testdata/include1.yml")
|
|
require.NoError(t, err)
|
|
_, err = w.Write(content)
|
|
require.NoError(t, err)
|
|
})
|
|
mux.HandleFunc("/include2.yml", func(w http.ResponseWriter, r *http.Request) {
|
|
content, err := os.ReadFile("testdata/include2.yml")
|
|
require.NoError(t, err)
|
|
_, err = w.Write(content)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
ports, err := availableport.Find(1)
|
|
require.NoError(t, err)
|
|
|
|
server := &http.Server{
|
|
Addr: fmt.Sprintf(":%d", ports[0]),
|
|
Handler: mux,
|
|
}
|
|
|
|
listener, err := net.Listen("tcp", server.Addr)
|
|
require.NoError(t, err)
|
|
|
|
go server.Serve(listener)
|
|
|
|
t.Cleanup(func() {
|
|
server.Close()
|
|
})
|
|
|
|
return fmt.Sprintf("http://localhost:%d", ports[0])
|
|
}
|