mukan-ignite/ignite/pkg/jsonfile/jsonfile_test.go
Mukan Erkin Törük 26b204bd04
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
feat: fork Ignite CLI v29 as Mukan Ignite — remove cosmos-sdk restrictions
2026-05-11 03:31:37 +03:00

413 lines
9.3 KiB
Go

package jsonfile
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"reflect"
"testing"
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
"github.com/ignite/cli/v29/ignite/pkg/errors"
"github.com/ignite/cli/v29/ignite/pkg/tarball"
)
type roundTripperFunc func(*http.Request) (*http.Response, error)
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}
func newTestClient(statusCode int, body []byte) *http.Client {
return &http.Client{
Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: statusCode,
Body: io.NopCloser(bytes.NewReader(body)),
Header: make(http.Header),
ContentLength: int64(len(body)),
Request: req,
}, nil
}),
}
}
func TestJSONFile_Field(t *testing.T) {
type (
invalidStruct struct {
name string
number int
}
evidence struct {
MaxAgeDuration string `json:"max_age_duration"`
MaxAgeNumBlocks string `json:"max_age_num_blocks"`
MaxBytes int64 `json:"max_bytes"`
}
)
tests := []struct {
name string
filepath string
key string
want interface{}
err error
}{
{
name: "get string parameter",
filepath: "testdata/jsonfile.json",
key: "consensus_params.block.max_bytes",
want: "22020096",
},
{
name: "get boolean parameter",
filepath: "testdata/jsonfile.json",
key: "launched",
want: true,
},
{
name: "get array parameter",
filepath: "testdata/jsonfile.json",
key: "consensus_params.block.best_blocks",
want: []int{100, 20, 11, 4, 2},
},
{
name: "get number parameter",
filepath: "testdata/jsonfile.json",
key: "consensus_params.block.time_iota_ms",
want: 1000,
},
{
name: "get coins parameter",
filepath: "testdata/jsonfile.json",
key: "app_state.bank.balances.[0].coins",
want: sdk.Coins{sdk.NewCoin("stake", math.NewInt(95000000))},
},
{
name: "get custom parameter",
filepath: "testdata/jsonfile.json",
key: "consensus_params.evidence",
want: evidence{
MaxAgeDuration: "172800000000000",
MaxAgeNumBlocks: "100000",
MaxBytes: 1048576,
},
},
{
name: "invalid coins parameter",
filepath: "testdata/jsonfile.json",
key: "app_state.bank.balances.[0].coins",
want: invalidStruct{name: "invalid", number: 110},
err: ErrInvalidValueType,
},
{
name: "invalid path",
filepath: "testdata/jsonfile.json",
key: "invalid.field.path",
want: invalidStruct{name: "invalid", number: 110},
err: ErrFieldNotFound,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := FromPath(tt.filepath)
require.NoError(t, err)
t.Cleanup(func() {
err = f.Close()
require.NoError(t, err)
})
out := reflect.New(reflect.TypeOf(tt.want))
err = f.Field(tt.key, out.Interface())
if tt.err != nil {
require.Error(t, err)
require.ErrorIs(t, err, tt.err)
return
}
require.NoError(t, err)
require.Equal(t, tt.want, out.Elem().Interface())
})
}
}
func TestJSONFile_Update(t *testing.T) {
coins := sdk.NewCoin("bar", math.NewInt(500))
jsonCoins, err := json.Marshal(coins)
require.NoError(t, err)
tests := []struct {
name string
filepath string
opts []UpdateFileOption
want []interface{}
err error
}{
{
name: "update string field",
filepath: "testdata/jsonfile.json",
opts: []UpdateFileOption{
WithKeyValue(
"consensus_params.block.max_bytes",
"22020096",
),
},
want: []interface{}{float64(22020096)},
},
{
name: "update string field to number",
filepath: "testdata/jsonfile.json",
opts: []UpdateFileOption{
WithKeyValueInt(
"consensus_params.block.max_bytes",
22020096,
),
},
want: []interface{}{float64(22020096)},
},
{
name: "update number field",
filepath: "testdata/jsonfile.json",
opts: []UpdateFileOption{
WithKeyValueInt(
"consensus_params.block.time_iota_ms",
1000,
),
},
want: []interface{}{float64(1000)},
},
{
name: "update timestamp field",
filepath: "testdata/jsonfile.json",
opts: []UpdateFileOption{
WithKeyValueTimestamp(
"genesis_time",
10000000,
),
},
want: nil, // TODO find a way to test timestamp values
},
{
name: "update two values type",
filepath: "testdata/jsonfile.json",
opts: []UpdateFileOption{
WithKeyValue(
"consensus_params.block.max_bytes",
"3000000",
),
WithKeyValueInt(
"consensus_params.block.time_iota_ms",
1000,
),
},
want: []interface{}{float64(3000000), float64(1000)},
},
{
name: "update coin field",
filepath: "testdata/jsonfile.json",
opts: []UpdateFileOption{
WithKeyValueByte(
"app_state.crisis.params.constant_fee",
jsonCoins,
),
},
want: []interface{}{map[string]interface{}{
"denom": coins.Denom,
"amount": coins.Amount.String(),
}},
},
{
name: "add non-existing field",
filepath: "testdata/jsonfile.json",
opts: []UpdateFileOption{
WithKeyValue(
"app_state.auth.params.sig_verify_cost_ed25519",
"111",
),
},
want: []interface{}{float64(111)},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := FromPath(tt.filepath)
require.NoError(t, err)
// Rollback files after change
b, err := f.Bytes()
require.NoError(t, err)
t.Cleanup(func() {
var prettyJSON bytes.Buffer
err := json.Indent(&prettyJSON, b, "", " ")
require.NoError(t, err)
err = truncate(f.file, 0)
require.NoError(t, err)
err = f.Reset()
require.NoError(t, err)
_, err = f.file.Write(prettyJSON.Bytes())
require.NoError(t, err)
err = f.Close()
require.NoError(t, err)
})
err = f.Update(tt.opts...)
if tt.err != nil {
require.Error(t, err)
require.ErrorIs(t, err, tt.err)
return
}
require.NoError(t, err)
updates := make(map[string][]byte)
for _, opt := range tt.opts {
opt(updates)
}
if tt.want != nil {
got := make([]interface{}, 0)
for key := range updates {
var newValue interface{}
err := f.Field(key, &newValue)
require.NoError(t, err)
got = append(got, newValue)
}
require.ElementsMatch(t, tt.want, got)
}
})
}
}
func TestJSONFile_Hash(t *testing.T) {
tests := []struct {
name string
filepath string
want string
err error
}{
{
name: "file hash",
filepath: "testdata/jsonfile.json",
want: "036dbc0020f4ab5604f46a8e5a05c368e4cba41f48fcac2864641902c1dfcad5",
},
{
name: "not found file",
filepath: "testdata/genesis_not_found.json",
err: errors.New(
"cannot open the file: open testdata/genesis_not_found.json: no such file or directory",
),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f, err := FromPath(tt.filepath)
if tt.err != nil {
require.Error(t, err)
require.Equal(t, err.Error(), tt.err.Error())
return
}
require.NoError(t, err)
t.Cleanup(func() {
err = f.Close()
require.NoError(t, err)
})
got, err := f.Hash()
if tt.err != nil {
require.Error(t, err)
require.ErrorIs(t, err, tt.err)
return
}
require.NoError(t, err)
require.Equal(t, tt.want, got)
})
}
}
func TestFromURL(t *testing.T) {
type args struct {
url string
filepath string
tarballFileName string
}
tests := []struct {
name string
args args
verifyField string
wantField string
err error
}{
{
name: "JSON URL",
args: args{
filepath: "testdata/jsonfile.json",
},
verifyField: "chain_id",
wantField: "earth-1",
},
{
name: "tarball URL",
args: args{
filepath: "testdata/example.tar.gz",
tarballFileName: "example.json",
},
verifyField: "chain_id",
wantField: "gaia-1",
},
{
name: "invalid tarball file name",
args: args{
filepath: "testdata/example.tar.gz",
tarballFileName: "invalid.json",
},
err: tarball.ErrGzipFileNotFound,
},
{
name: "invalid link",
args: args{
url: "https://google.com/invalid_example.json",
},
err: ErrInvalidURL,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
url := tt.args.url
if url == "" {
url = "https://example.com/testdata"
}
var body []byte
if tt.args.filepath != "" {
var err error
body, err = os.ReadFile(tt.args.filepath)
require.NoError(t, err)
}
statusCode := http.StatusOK
if tt.err == ErrInvalidURL {
statusCode = http.StatusNotFound
}
client := newTestClient(statusCode, body)
filepath := fmt.Sprintf("%s/jsonfile.json", t.TempDir())
got, err := FromURLWithClient(context.TODO(), url, filepath, tt.args.tarballFileName, client)
if tt.err != nil {
require.Error(t, err)
require.ErrorIs(t, err, tt.err)
return
}
require.NoError(t, err)
t.Cleanup(func() {
err = got.Close()
require.NoError(t, err)
})
var verificationField string
err = got.Field(tt.verifyField, &verificationField)
require.NoError(t, err)
require.Equal(t, tt.wantField, verificationField)
})
}
}