Skip to content

Commit aaf5ba9

Browse files
authored
Merge pull request #17769 from MinaProtocol/dkijania/single_archive_node_upgrade_script
[HF][Upgrade Script] Upgrade script for single archive node test
2 parents 37e9e13 + 4eec5b1 commit aaf5ba9

File tree

11 files changed

+166
-43
lines changed

11 files changed

+166
-43
lines changed

src/test/archive/archive_node_tests/archive_node_tests.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,13 @@ let () =
2323
.Make_FixtureWithoutBootstrap
2424
(Load_genesis_ledger) ) )
2525
] )
26+
; ( "upgrade_archive"
27+
, [ test_case
28+
"Recreate database from precomputed blocks after upgrade script is \
29+
applied"
30+
`Quick
31+
(Runner.run_blocking
32+
( module Mina_automation_fixture.Archive.Make_FixtureWithBootstrap
33+
(Upgrade_archive) ) )
34+
] )
2635
]

src/test/archive/archive_node_tests/archive_precomputed_blocks_test.ml

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ open Async
22
open Core
33
open Mina_automation
44
open Mina_automation_fixture.Archive
5+
open Common
56

67
(**
78
* Test the basic functionality of the mina archive with mocked deamon
@@ -118,11 +119,8 @@ let test_case (test_data : t) =
118119
let archive_uri = test_data.archive.config.postgres_uri in
119120
let output = test_data.temp_dir in
120121
let%bind precomputed_blocks =
121-
Network_data.untar_precomputed_blocks test_data.network_data output
122-
in
123-
let precomputed_blocks =
124-
List.map precomputed_blocks ~f:(fun file -> output ^ "/" ^ file)
125-
|> List.filter ~f:(fun file -> String.is_suffix file ~suffix:".json")
122+
unpack_precomputed_blocks test_data.network_data
123+
~temp_dir:test_data.temp_dir
126124
in
127125
let log_file = output ^ "/precomputed_blocks_test.log" in
128126
Archive.Process.start_logging test_data.archive ~log_file ;
@@ -136,32 +134,13 @@ let test_case (test_data : t) =
136134
assert_archived_blocks ~archive_uri
137135
~expected:(List.length precomputed_blocks)
138136
in
139-
let connection = Psql.Conn_str archive_uri in
140-
let%bind latest_state_hash =
141-
Psql.run_command ~connection
142-
"SELECT state_hash FROM blocks ORDER BY id DESC LIMIT 1"
143-
in
144-
let latest_state_hash =
145-
match latest_state_hash with
146-
| Ok hash ->
147-
hash
148-
| Error err ->
149-
failwith
150-
("Failed to query latest state hash: " ^ Error.to_string_hum err)
151-
in
152-
let output_ledger = output ^ "/output_ledger.json" in
153-
let replayer = Replayer.default in
154-
let%bind replayer_output =
155-
Replayer.run replayer ~archive_uri
156-
~input_config:
137+
138+
let%bind () =
139+
assert_replayer_run_against_last_block
140+
~replayer_input_file_path:
157141
(Network_data.replayer_input_file_path test_data.network_data)
158-
~target_state_hash:latest_state_hash ~interval_checkpoint:10
159-
~output_ledger ()
142+
archive_uri test_data.temp_dir
160143
in
161-
let () = print_endline replayer_output in
162-
let output_ledger = Replayer.Output.of_json_file_exn output_ledger in
163-
assert (
164-
String.equal output_ledger.target_epoch_ledgers_state_hash latest_state_hash ) ;
165144

166145
let%bind perf_data = extract_perf_metrics log_file in
167146
perf_metrics_to_yojson perf_data |> Yojson.to_file "archive.perf" ;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
open Async
2+
open Core
3+
open Mina_automation
4+
5+
(** Assert that the replayer runs successfully against the latest block in the archive.
6+
7+
This function queries the archive database to find the latest state hash,
8+
then runs the replayer with the specified input configuration file against
9+
that target state hash. It verifies that the output ledger's target epoch
10+
ledgers state hash matches the latest state hash from the database.
11+
12+
@param replayer_input_file_path Path to the replayer input configuration file
13+
@param archive_uri URI connection string for the archive database
14+
@param output Output directory path where the ledger will be written
15+
@return Unit deferred that completes when assertion passes *)
16+
let assert_replayer_run_against_last_block ~replayer_input_file_path archive_uri
17+
output =
18+
let open Deferred.Let_syntax in
19+
let connection = Psql.Conn_str archive_uri in
20+
let%bind latest_state_hash =
21+
Psql.run_command ~connection
22+
"SELECT state_hash FROM blocks ORDER BY id DESC LIMIT 1"
23+
in
24+
let latest_state_hash =
25+
match latest_state_hash with
26+
| Ok hash ->
27+
hash
28+
| Error err ->
29+
failwith
30+
("Failed to query latest state hash: " ^ Error.to_string_hum err)
31+
in
32+
let output_ledger = output ^ "/output_ledger.json" in
33+
let replayer = Replayer.default in
34+
let%bind replayer_output =
35+
Replayer.run replayer ~archive_uri ~input_config:replayer_input_file_path
36+
~target_state_hash:latest_state_hash ~interval_checkpoint:10
37+
~output_ledger ()
38+
in
39+
let () = print_endline replayer_output in
40+
let output_ledger = Replayer.Output.of_json_file_exn output_ledger in
41+
assert (
42+
String.equal output_ledger.target_epoch_ledgers_state_hash latest_state_hash ) ;
43+
Deferred.unit
44+
45+
(** Unpack precomputed blocks from a source archive to a temporary directory.
46+
47+
This function extracts precomputed blocks from a tar archive into the specified
48+
temporary directory and filters the results to only include JSON files.
49+
50+
@param temp_dir Temporary directory path where blocks will be extracted
51+
@param source Source path of the tar archive containing precomputed blocks
52+
@return Deferred list of file paths to extracted JSON block files *)
53+
let unpack_precomputed_blocks ~temp_dir source =
54+
let open Deferred.Let_syntax in
55+
let%bind precomputed_blocks =
56+
Network_data.untar_precomputed_blocks source temp_dir
57+
in
58+
List.map precomputed_blocks ~f:(fun file -> temp_dir ^ "/" ^ file)
59+
|> List.filter ~f:(fun file -> String.is_suffix file ~suffix:".json")
60+
|> Deferred.return
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
open Async
2+
open Core
3+
open Mina_automation
4+
open Mina_automation_fixture.Archive
5+
open Common
6+
7+
type t = Mina_automation_fixture.Archive.after_bootstrap
8+
9+
let test_case (test_data : t) =
10+
let open Deferred.Let_syntax in
11+
let daemon = Daemon.default () in
12+
let archive_uri = test_data.archive.config.postgres_uri in
13+
let temp_dir = test_data.temp_dir in
14+
let%bind precomputed_blocks =
15+
unpack_precomputed_blocks ~temp_dir test_data.network_data
16+
in
17+
let log_file = temp_dir ^ "/upgrade.log" in
18+
let upgrade_path =
19+
Archive.Scripts.filepath `Upgrade
20+
|> Option.value_exn ~message:"Failed to find upgrade script"
21+
in
22+
let%bind _ =
23+
Psql.run_script ~connection:(Psql.Conn_str archive_uri) upgrade_path
24+
in
25+
26+
Archive.Process.start_logging test_data.archive ~log_file ;
27+
let%bind () =
28+
Daemon.archive_blocks_from_files daemon.executor
29+
~archive_address:test_data.archive.config.server_port ~format:`Precomputed
30+
precomputed_blocks
31+
in
32+
33+
let%bind () =
34+
assert_replayer_run_against_last_block
35+
~replayer_input_file_path:
36+
(Network_data.replayer_input_file_path test_data.network_data)
37+
archive_uri temp_dir
38+
in
39+
40+
Deferred.Or_error.return Mina_automation_fixture.Intf.Passed

src/test/mina_automation/archive.ml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,28 @@ module Paths = struct
3535
let official_name = "mina-archive"
3636
end
3737

38+
module Scripts = struct
39+
type t = [ `CreateSchema | `DropTables | `Upgrade | `Rollback ]
40+
41+
let possible_locations = [ "/etc/mina/archive"; "src/app/archive" ]
42+
43+
let file t =
44+
match t with
45+
| `CreateSchema ->
46+
"create_schema.sql"
47+
| `DropTables ->
48+
"drop_tables.sql"
49+
| `Upgrade ->
50+
"upgrade-to-mesa.sql"
51+
| `Rollback ->
52+
"rollback_to-berkeley.sql"
53+
54+
let filepath t =
55+
let file = file t in
56+
let possible_locations = [ "/etc/mina/archive"; "src/app/archive" ] in
57+
Utils.possible_locations ~file possible_locations
58+
end
59+
3860
module Executor = Executor.Make (Paths)
3961

4062
type t = { config : Config.t; executor : Executor.t }

src/test/mina_automation/archive_blocks.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ let path () =
2323
Deferred.map Executor.PathFinder.standalone_path ~f:(fun opt ->
2424
Option.value_exn opt
2525
~message:
26-
"Could not find standalone path for archive blocks. App is not \
27-
executable outside the dune" )
26+
"Could not find standalone path for archive blocks. Archive blocks \
27+
is not executable outside the dune" )
2828

2929
let format_to_string format =
3030
match format with

src/test/mina_automation/daemon.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,13 @@ let archive_blocks t ~archive_address ~format blocks =
188188
]
189189
@ blocks )
190190

191+
type t = { config : Config.t; executor : Executor.t }
192+
191193
let archive_blocks_from_files t ~archive_address ~format ?(sleep = 5) blocks =
192194
Deferred.List.iter blocks ~f:(fun block ->
193195
let%bind _ = archive_blocks t ~archive_address ~format [ block ] () in
194196
after (Time.Span.of_sec (Float.of_int sleep)) )
195197

196-
type t = { config : Config.t; executor : Executor.t }
197-
198198
let of_config config = { config; executor = Executor.AutoDetect }
199199

200200
let default () = { config = Config.default (); executor = Executor.AutoDetect }

src/test/mina_automation/executor.ml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,6 @@ let logger = Logger.create ()
3333
module Make_PathFinder (P : AppPaths) = struct
3434
module Paths = P
3535

36-
let paths =
37-
Option.value_map ~f:(String.split ~on:':') ~default:[] (Sys.getenv "PATH")
38-
3936
let built_name = Printf.sprintf "_build/default/%s" P.dune_name
4037

4138
let exists_at_path path prefix =
@@ -51,7 +48,7 @@ module Make_PathFinder (P : AppPaths) = struct
5148
Deferred.return (Some built_name)
5249
| _ -> (
5350
match%bind
54-
Deferred.List.find_map ~f:(exists_at_path P.official_name) paths
51+
Deferred.List.find_map ~f:(exists_at_path P.official_name) Utils.paths
5552
with
5653
| Some _ ->
5754
Deferred.return (Some P.official_name)
@@ -133,7 +130,7 @@ module Make (P : AppPaths) = struct
133130
match%bind
134131
Deferred.List.find_map
135132
~f:(PathFinder.exists_at_path PathFinder.Paths.official_name)
136-
PathFinder.paths
133+
Utils.paths
137134
with
138135
| Some prefix ->
139136
f_debian ~args ~prefix ?env ()

src/test/mina_automation/missing_blocks_auditor.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ let path () =
1717
Deferred.map PathFinder.standalone_path ~f:(fun opt ->
1818
Option.value_exn opt
1919
~message:
20-
"Could not find standalone path for missing block auditor. App is \
21-
not executable outside the dune" )
20+
"Could not find standalone for missing block auditor. Missing block \
21+
auditor is not executable outside the dune" )

src/test/mina_automation/psql.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,10 @@ let run_command ~connection command =
8282
@return A deferred string containing the output of the command.
8383
*)
8484

85-
let run_script ~connection ~db script =
85+
let run_script ~connection ?db script =
86+
let maybe_db = Option.value_map db ~default:[] ~f:(fun db -> [ "-d"; db ]) in
8687
let creds = create_credential_arg ~connection in
87-
Util.run_cmd_exn "." psql (creds @ [ "-d"; db; "-a"; "-f"; script ])
88+
Util.run_cmd_exn "." psql (creds @ maybe_db @ [ "-a"; "-f"; script ])
8889

8990
let create_empty_db ~connection ~db =
9091
run_command ~connection (sprintf "CREATE DATABASE %s;" db)

0 commit comments

Comments
 (0)