upgrade_SUITE.erl 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. %% Copyright (c) 2020, Loïc Hoguin <essen@ninenines.eu>
  2. %%
  3. %% Permission to use, copy, modify, and/or distribute this software for any
  4. %% purpose with or without fee is hereby granted, provided that the above
  5. %% copyright notice and this permission notice appear in all copies.
  6. %%
  7. %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. -module(upgrade_SUITE).
  15. -compile(export_all).
  16. -compile(nowarn_export_all).
  17. -import(ct_helper, [doc/1]).
  18. %% ct.
  19. all() ->
  20. ct_helper:all(?MODULE).
  21. init_per_suite(Config) ->
  22. %% Remove environment variables inherited from Erlang.mk.
  23. os:unsetenv("ERLANG_MK_TMP"),
  24. os:unsetenv("APPS_DIR"),
  25. os:unsetenv("DEPS_DIR"),
  26. os:unsetenv("ERL_LIBS"),
  27. os:unsetenv("CI_ERLANG_MK"),
  28. %% Ensure we are using the C locale for all os:cmd calls.
  29. os:putenv("LC_ALL", "C"),
  30. Config.
  31. end_per_suite(_Config) ->
  32. ok.
  33. %% Find GNU Make.
  34. do_find_make_cmd() ->
  35. case os:getenv("MAKE") of
  36. false ->
  37. case os:find_executable("gmake") of
  38. false -> "make";
  39. Cmd -> Cmd
  40. end;
  41. Cmd ->
  42. Cmd
  43. end.
  44. %% Manipulate the release.
  45. do_get_paths(Example0) ->
  46. Example = atom_to_list(Example0),
  47. {ok, CWD} = file:get_cwd(),
  48. Dir = CWD ++ "/../../examples/" ++ Example,
  49. Rel = Dir ++ "/_rel/" ++ Example ++ "_example/bin/" ++ Example ++ "_example",
  50. Log = Dir ++ "/_rel/" ++ Example ++ "_example/log/erlang.log.1",
  51. {Dir, Rel, Log}.
  52. do_compile_and_start(Example, Config) ->
  53. Make = do_find_make_cmd(),
  54. {Dir, Rel, _} = do_get_paths(Example),
  55. ct:log("~s~n", [os:cmd(Make ++ " -C " ++ Dir ++ " distclean")]),
  56. %% TERM=dumb disables relx coloring.
  57. ct:log("~s~n", [os:cmd(Make ++ " -C " ++ Dir ++ " TERM=dumb")]),
  58. %% @todo Should move the "1" tarball in the correct directory to avoid a warning on downgrade?
  59. ct:log("~s~n", [os:cmd(Rel ++ " stop")]),
  60. ct:log("~s~n", [os:cmd(Rel ++ " start")]),
  61. timer:sleep(2000),
  62. ct:log("~s~n", [os:cmd(Rel ++ " eval 'application:info()'")]).
  63. do_stop(Example) ->
  64. {Dir, Rel, Log} = do_get_paths(Example),
  65. ct:log("~s~n", [os:cmd("sed -i.bak s/\"2\"/\"1\"/ " ++ Dir ++ "/relx.config")]),
  66. ct:log("~s~n", [os:cmd(Rel ++ " stop")]),
  67. ct:log("~s~n", [element(2, file:read_file(Log))]).
  68. %% When we are on a tag (git describe --exact-match succeeds),
  69. %% we use the tag before that as a starting point. Otherwise
  70. %% we use the most recent tag.
  71. do_use_ranch_previous(Example) ->
  72. TagsOutput = os:cmd("git tag | tr - \\~ | sort -V | tr \\~ -"),
  73. ct:log("~s~n", [TagsOutput]),
  74. Tags = string:lexemes(TagsOutput, "\n"),
  75. DescribeOutput = os:cmd("git describe --exact-match"),
  76. ct:log("~s~n", [DescribeOutput]),
  77. {CommitOrTag, Prev} = case DescribeOutput of
  78. "fatal: no tag exactly matches " ++ _ -> {commit, hd(lists:reverse(Tags))};
  79. _ -> {tag, hd(tl(lists:reverse(Tags)))}
  80. end,
  81. do_use_ranch_commit(Example, Prev),
  82. CommitOrTag.
  83. %% Replace the current Ranch commit with the one given as argument.
  84. do_use_ranch_commit(Example, Commit) ->
  85. {Dir, _, _} = do_get_paths(Example),
  86. ct:log("~s~n", [os:cmd(
  87. "sed -i.bak s/\"dep_ranch_commit = .*\"/\"dep_ranch_commit = "
  88. ++ Commit ++ "\"/ " ++ Dir ++ "/Makefile"
  89. )]).
  90. %% Remove Ranch and rebuild, this time generating a relup.
  91. do_build_relup(Example, CommitOrTag) ->
  92. Make = do_find_make_cmd(),
  93. {Dir, _, _} = do_get_paths(Example),
  94. ct:log("~s~n", [os:cmd("rm -rf " ++ Dir ++ "/deps/ranch")]),
  95. ct:log("~s~n", [os:cmd("sed -i.bak s/\"1\"/\"2\"/ " ++ Dir ++ "/relx.config")]),
  96. %% We need Ranch to be fetched first in order to copy the current appup
  97. %% and optionally update its version when we are not on a tag.
  98. ct:log("~s~n", [os:cmd(Make ++ " -C " ++ Dir ++ " deps")]),
  99. ct:log("~s~n", [os:cmd("cp " ++ Dir ++ "/../../ebin/ranch.appup "
  100. ++ Dir ++ "/deps/ranch/ebin/")]),
  101. case CommitOrTag of
  102. tag -> ok;
  103. commit ->
  104. ProjectVersion = os:cmd("grep \"PROJECT_VERSION = \" " ++ Dir ++ "/deps/ranch/Makefile"),
  105. ct:log(ProjectVersion),
  106. ["PROJECT_VERSION = " ++ Vsn0|_] = string:lexemes(ProjectVersion, "\n"),
  107. [A, B|Tail] = string:lexemes(Vsn0, "."),
  108. Vsn = binary_to_list(iolist_to_binary([A, $., B, ".9", lists:join($., Tail)])),
  109. ct:log("Changing Ranch version from ~s to ~s~n", [Vsn0, Vsn]),
  110. ct:log("~s~n", [os:cmd(
  111. "sed -i.bak s/\"PROJECT_VERSION = .*\"/\"PROJECT_VERSION = " ++ Vsn ++ "\"/ "
  112. ++ Dir ++ "/deps/ranch/Makefile"
  113. )]),
  114. %% The version in the appup must be the same as PROJECT_VERSION.
  115. ct:log("~s~n", [os:cmd(
  116. "sed -i.bak s/\"" ++ Vsn0 ++ "\"/\"" ++ Vsn ++ "\"/ "
  117. ++ Dir ++ "/deps/ranch/ebin/ranch.appup"
  118. )])
  119. end,
  120. ct:log("~s~n", [os:cmd(Make ++ " -C " ++ Dir ++ " relup")]).
  121. %% Copy the tarball in the correct location and upgrade.
  122. do_upgrade(Example) ->
  123. ExampleStr = atom_to_list(Example),
  124. {Dir, Rel, _} = do_get_paths(Example),
  125. ct:log("~s~n", [os:cmd("cp "
  126. ++ Dir ++ "/_rel/" ++ ExampleStr
  127. ++ "_example/" ++ ExampleStr ++ "_example-2.tar.gz "
  128. ++ Dir ++ "/_rel/" ++ ExampleStr
  129. ++ "_example/releases/2/" ++ ExampleStr ++ "_example.tar.gz")]),
  130. ct:log("~s~n", [os:cmd(Rel ++ " upgrade \"2\"")]),
  131. ct:log("~s~n", [os:cmd(Rel ++ " eval 'application:info()'")]).
  132. do_downgrade(Example) ->
  133. {_, Rel, _} = do_get_paths(Example),
  134. ct:log("~s~n", [os:cmd(Rel ++ " downgrade \"1\"")]),
  135. ct:log("~s~n", [os:cmd(Rel ++ " eval 'application:info()'")]).
  136. %% Tests.
  137. upgrade_ranch_one_conn(Config) ->
  138. Example = tcp_echo,
  139. Port = 5555,
  140. try
  141. %% Build and start the example release using the previous Ranch version.
  142. CommitOrTag = do_use_ranch_previous(Example),
  143. do_compile_and_start(Example, Config),
  144. %% Establish a connection and check that it works.
  145. {ok, S} = gen_tcp:connect("localhost", Port, [{active, false}, binary]),
  146. ok = gen_tcp:send(S, "Hello!"),
  147. {ok, <<"Hello!">>} = gen_tcp:recv(S, 0, 1000),
  148. %% Update Ranch to master then build a release upgrade.
  149. do_use_ranch_commit(Example, "master"),
  150. do_build_relup(Example, CommitOrTag),
  151. %% Perform the upgrade, then check that our connection is still up.
  152. do_upgrade(Example),
  153. ok = gen_tcp:send(S, "Hello!"),
  154. {ok, <<"Hello!">>} = gen_tcp:recv(S, 0, 1000),
  155. %% Check that new connections are still accepted.
  156. {ok, _} = gen_tcp:connect("localhost", Port, [{active, false}, binary]),
  157. %% Perform the downgrade, then check that our connection is still up.
  158. do_downgrade(Example),
  159. ok = gen_tcp:send(S, "Hello!"),
  160. {ok, <<"Hello!">>} = gen_tcp:recv(S, 0, 1000),
  161. %% Check that new connections are still accepted.
  162. {ok, _} = gen_tcp:connect("localhost", Port, [{active, false}, binary]),
  163. ok
  164. after
  165. do_stop(tcp_echo)
  166. end.
  167. %% @todo upgrade_ranch_max_conn