Skip to content

Commit 888881d

Browse files
Merge branch 'main' into carlos/add-deprecated-option-msgsubmitmisbehaviour
2 parents 472681a + 2e44243 commit 888881d

File tree

4 files changed

+221
-56
lines changed

4 files changed

+221
-56
lines changed

modules/apps/27-interchain-accounts/host/keeper/msg_server_test.go

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,19 @@ import (
66
)
77

88
func (suite *KeeperTestSuite) TestUpdateParams() {
9-
msg := types.MsgUpdateParams{}
10-
119
testCases := []struct {
12-
name string
13-
malleate func(authority string)
14-
expPass bool
10+
name string
11+
msg *types.MsgUpdateParams
12+
expPass bool
1513
}{
1614
{
1715
"success",
18-
func(authority string) {
19-
msg.Authority = authority
20-
msg.Params = types.DefaultParams()
21-
},
16+
types.NewMsgUpdateParams(suite.chainA.GetSimApp().ICAHostKeeper.GetAuthority(), types.DefaultParams()),
2217
true,
2318
},
2419
{
2520
"invalid authority address",
26-
func(authority string) {
27-
msg.Authority = "authority"
28-
msg.Params = types.DefaultParams()
29-
},
21+
types.NewMsgUpdateParams("authority", types.DefaultParams()),
3022
false,
3123
},
3224
}
@@ -37,12 +29,9 @@ func (suite *KeeperTestSuite) TestUpdateParams() {
3729
suite.Run(tc.name, func() {
3830
suite.SetupTest()
3931

40-
ICAHostKeeper := &suite.chainA.GetSimApp().ICAHostKeeper
41-
tc.malleate(ICAHostKeeper.GetAuthority()) // malleate mutates test data
42-
4332
ctx := suite.chainA.GetContext()
44-
msgServer := keeper.NewMsgServerImpl(ICAHostKeeper)
45-
res, err := msgServer.UpdateParams(ctx, &msg)
33+
msgServer := keeper.NewMsgServerImpl(&suite.chainA.GetSimApp().ICAHostKeeper)
34+
res, err := msgServer.UpdateParams(ctx, tc.msg)
4635

4736
if tc.expPass {
4837
suite.Require().NoError(err)

modules/apps/27-interchain-accounts/host/types/msgs.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ import (
99

1010
var _ sdk.Msg = (*MsgUpdateParams)(nil)
1111

12+
// NewMsgUpdateParams creates a new MsgUpdateParams instance
13+
func NewMsgUpdateParams(authority string, params Params) *MsgUpdateParams {
14+
return &MsgUpdateParams{
15+
Authority: authority,
16+
Params: params,
17+
}
18+
}
19+
1220
// ValidateBasic implements sdk.Msg
1321
func (msg MsgUpdateParams) ValidateBasic() error {
1422
_, err := sdk.AccAddressFromBech32(msg.Authority)

modules/apps/27-interchain-accounts/host/types/msgs_test.go

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,57 +11,37 @@ import (
1111
)
1212

1313
func TestMsgUpdateParamsValidateBasic(t *testing.T) {
14-
var msg *types.MsgUpdateParams
15-
1614
testCases := []struct {
17-
name string
18-
malleate func()
19-
expPass bool
15+
name string
16+
msg *types.MsgUpdateParams
17+
expPass bool
2018
}{
2119
{
2220
"success: valid authority address",
23-
func() {
24-
msg = &types.MsgUpdateParams{
25-
Authority: ibctesting.TestAccAddress,
26-
Params: types.DefaultParams(),
27-
}
28-
},
21+
types.NewMsgUpdateParams(sdk.AccAddress(ibctesting.TestAccAddress).String(), types.DefaultParams()),
2922
true,
3023
},
3124
{
3225
"failure: invalid authority address",
33-
func() {
34-
msg = &types.MsgUpdateParams{
35-
Authority: "authority",
36-
}
37-
},
26+
types.NewMsgUpdateParams("authority", types.DefaultParams()),
3827
false,
3928
},
4029
{
4130
"failure: invalid allowed message",
42-
func() {
43-
msg = &types.MsgUpdateParams{
44-
Authority: ibctesting.TestAccAddress,
45-
Params: types.Params{
46-
AllowMessages: []string{""},
47-
},
48-
}
49-
},
31+
types.NewMsgUpdateParams("authority", types.Params{
32+
AllowMessages: []string{""},
33+
}),
5034
false,
5135
},
5236
}
5337

5438
for _, tc := range testCases {
55-
t.Run(tc.name, func(t *testing.T) {
56-
tc.malleate()
57-
58-
err := msg.ValidateBasic()
59-
if tc.expPass {
60-
require.NoError(t, err)
61-
} else {
62-
require.Error(t, err)
63-
}
64-
})
39+
err := tc.msg.ValidateBasic()
40+
if tc.expPass {
41+
require.NoError(t, err)
42+
} else {
43+
require.Error(t, err)
44+
}
6545
}
6646
}
6747

@@ -76,10 +56,7 @@ func TestMsgUpdateParamsGetSigners(t *testing.T) {
7656
}
7757

7858
for _, tc := range testCases {
79-
msg := types.MsgUpdateParams{
80-
Authority: tc.address.String(),
81-
Params: types.DefaultParams(),
82-
}
59+
msg := types.NewMsgUpdateParams(tc.address.String(), types.DefaultParams())
8360
if tc.expPass {
8461
require.Equal(t, []sdk.AccAddress{tc.address}, msg.GetSigners())
8562
} else {
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#!/usr/bin/python3
2+
"""
3+
The following script takes care of adding new/removing versions or
4+
replacing a version in the compatibility-test-matrices JSON files.
5+
6+
To use this script, you'll need to have Python 3.9+ installed.
7+
8+
Invocation:
9+
10+
By default, the script assumes that adding a new version is the desired operation.
11+
Furthermore, it assumes that the compatibility-test-matrices directory is located
12+
in the .github directory and the script is invoked from the root of the repository.
13+
14+
If any of the above is not true, you can use the '--type' and '--directory' flags
15+
to specify the operation and the directory respectively.
16+
17+
Typically, an invocation would look like:
18+
19+
scripts/update_compatibility_tests.py --recent_version v4.3.0 --new_version v4.4.0
20+
21+
The three operations currently added are:
22+
23+
- ADD: Add a new version to the JSON files. Requires both '--recent_version' and
24+
'--new_version' options to be set.
25+
- REPLACE: Replace an existing version with a new one. Requires both '--recent_version'
26+
and '--new_version' options to be set.
27+
- REMOVE: Remove an existing version from the JSON files. Requires only the
28+
'--recent_version' options to be set.
29+
30+
For more information, use the '--help' flag to see the available options.
31+
"""
32+
import argparse
33+
import os
34+
import json
35+
import enum
36+
from collections import defaultdict
37+
from typing import Tuple, Generator, Optional, Dict, List, Any
38+
39+
# Directory to operate in
40+
DIRECTORY: str = ".github/compatibility-test-matrices"
41+
# JSON keys to search in.
42+
KEYS: Tuple[str, str] = ("chain-a", "chain-b")
43+
# Toggle if required. Indent = 2 matches our current formatting.
44+
DUMP_ARGS: Dict[Any, Any] = {
45+
"indent": 2,
46+
"sort_keys": False,
47+
"ensure_ascii": False,
48+
}
49+
# Suggestions for recent and new versions.
50+
SUGGESTION: str = "for example, v4.3.0 or 4.3.0"
51+
# Supported Operations.
52+
Operation = enum.Enum("Operation", ["ADD", "REMOVE", "REPLACE"])
53+
54+
55+
def find_json_files(
56+
directory: str, ignores: Tuple[str] = (".",)
57+
) -> Generator[str, None, None]:
58+
"""Find JSON files in a directory. By default, ignore hidden directories."""
59+
for root, dirs, files in os.walk(directory):
60+
dirs[:] = (d for d in dirs if not d.startswith(ignores))
61+
for file_ in files:
62+
if file_.endswith(".json"):
63+
yield os.path.join(root, file_)
64+
65+
66+
def has_release_version(json_file: Any, keys: Tuple[str, str], version: str) -> bool:
67+
"""Check if the json file has the version in question."""
68+
rows = (json_file[key] for key in keys)
69+
return any(version in row for row in rows)
70+
71+
72+
def sorter(key: str) -> str:
73+
"""Since 'main' < 'vX.X.X' and we want to have 'main' as the first entry
74+
in the list, we return a version that is considerably large. If ibc-go
75+
reaches this version I'll wear my dunce hat and go sit in the corner.
76+
"""
77+
return "v99999.9.9" if key == "main" else key
78+
79+
80+
def update_version(json_file: Any, keys: Tuple[str, str], args: argparse.Namespace):
81+
"""Update the versions as required in the json file."""
82+
recent, new, op = args.recent, args.new, args.type
83+
for row in (json_file[key] for key in keys):
84+
if recent not in row:
85+
continue
86+
if op == Operation.ADD:
87+
row.append(new)
88+
row.sort(key=sorter, reverse=True)
89+
else:
90+
index = row.index(recent)
91+
if op == Operation.REPLACE:
92+
row[index] = new
93+
elif op == Operation.REMOVE:
94+
del row[index]
95+
96+
97+
def version_input(prompt: str, version: Optional[str]) -> str:
98+
"""Input version if not supplied, make it start with a 'v' if it doesn't."""
99+
if version is None:
100+
version = input(prompt)
101+
return version if version.startswith(("v", "V")) else f"v{version}"
102+
103+
104+
def require_version(args: argparse.Namespace):
105+
"""Allow non-required version in argparse but request it if not provided."""
106+
args.recent = version_input(f"Recent version ({SUGGESTION}): ", args.recent)
107+
if args.type == Operation.REMOVE:
108+
return
109+
args.new = version_input(f"New version ({SUGGESTION}): ", args.new)
110+
111+
112+
def parse_args() -> argparse.Namespace:
113+
"""Parse command line arguments."""
114+
parser = argparse.ArgumentParser(description="Update JSON files.")
115+
parser.add_argument(
116+
"--type",
117+
choices=[Operation.ADD.name, Operation.REPLACE.name, Operation.REMOVE.name],
118+
default=Operation.ADD,
119+
help="Type of version update: add a version, replace one or remove one.",
120+
)
121+
parser.add_argument(
122+
"--directory",
123+
default=DIRECTORY,
124+
help="Directory path where JSON files are located",
125+
)
126+
parser.add_argument(
127+
"--recent_version",
128+
dest="recent",
129+
help=f"Recent version to search in JSON files ({SUGGESTION})",
130+
)
131+
parser.add_argument(
132+
"--new_version",
133+
dest="new",
134+
help=f"New version to add in JSON files ({SUGGESTION})",
135+
)
136+
parser.add_argument(
137+
"--verbose",
138+
"-v",
139+
action="store_true",
140+
help="Allow for verbose output",
141+
default=False,
142+
)
143+
144+
args = parser.parse_args()
145+
require_version(args)
146+
return args
147+
148+
149+
def print_logs(logs: Dict[str, List[str]], verbose: bool):
150+
"""Print the logs. Verbosity controls if each individual
151+
file is printed or not.
152+
"""
153+
updated, skipped = logs["updated"], logs["skipped"]
154+
if updated:
155+
if verbose:
156+
print("Updated files:", *updated, sep="\n - ")
157+
else:
158+
print("No files were updated.")
159+
if skipped:
160+
if verbose:
161+
print("The following files were skipped:", *skipped, sep="\n - ")
162+
else:
163+
print("No files skipped.")
164+
165+
166+
def main(args: argparse.Namespace):
167+
""" Main driver function."""
168+
# Hold logs for 'updated' and 'skipped' files.
169+
logs = defaultdict(list)
170+
171+
# Go through each file and operate on it, if applicable.
172+
for file_ in find_json_files(args.directory):
173+
with open(file_, "r+") as fp:
174+
json_file = json.load(fp)
175+
if not has_release_version(json_file, KEYS, args.recent):
176+
logs["skipped"].append(
177+
f"Version '{args.recent}' not found in '{file_}'"
178+
)
179+
continue
180+
update_version(json_file, KEYS, args)
181+
fp.seek(0)
182+
json.dump(json_file, fp, **DUMP_ARGS)
183+
logs["updated"].append(f"Updated '{file_}'")
184+
185+
# Print logs collected.
186+
print_logs(logs, args.verbose)
187+
188+
189+
if __name__ == "__main__":
190+
args = parse_args()
191+
main(args)

0 commit comments

Comments
 (0)