Case template for tests that upgrade a real release from one version to the next.
The template adds a per-module :scratch path and aliases
Forecastle.Deployment. The project supplies the releases and assertions.
Build the target release with a relup for the deployed baseline:
defp releases do
[
my_app: fn ->
[upgrade_from: ["tar:artifacts/my_app-1.0.0.tar.gz"]]
|> Castle.customize()
end
]
endDeploy the baseline, start it, then install and commit the target:
defmodule MyApp.UpgradeTest do
use Forecastle.UpgradeCase
@moduletag :upgrade
@shipped "tar:artifacts/my_app-1.0.0.tar.gz"
@next "_build/prod/my_app-1.1.0.tar.gz"
setup_all %{scratch: scratch} do
deployment = Deployment.deploy!(@shipped, Path.join(scratch, "deploy"))
on_exit(fn -> Deployment.stop(deployment) end)
Deployment.start!(deployment)
Deployment.rpc!(deployment, "IO.puts(MyApp.Counter.bump())")
Deployment.stage!(deployment, @next)
Deployment.castle!(deployment, ["unpack", "1.1.0"])
Deployment.castle!(deployment, ["install", "1.1.0"])
Deployment.castle!(deployment, ["commit"])
{:ok, deployment: deployment}
end
test "moved to 1.1.0 and took the count with it", %{deployment: deployment} do
assert Deployment.rpc!(deployment, "IO.puts(inspect(MyApp.Counter.info()))") ==
~s({"1.1.0", 1})
assert Deployment.version(deployment) == "1.1.0"
end
endcastle!/3 raises on a non-zero exit. Assert both retained state and the code
version serving calls. A missing appup instruction can leave old code running
while the release reports the new version. Compile a version tag into the
module under test:
defmodule MyApp.Counter do
use GenServer
@vsn_tag Mix.Project.config()[:version]
@doc "`{the version compiled into the code serving this call, count}`"
def info, do: GenServer.call(__MODULE__, :info)
def handle_call(:info, _from, state), do: {:reply, {@vsn_tag, state.count}, state}
endDeployment.deploy!/3 accepts rel:, tar: and ref: baselines. Prefer the
shipped tar: artifact when available.
Use Deployment.install_supervised!/3 for restart_emulator transitions and
castle!/3 for hot installs. The supervised form restarts the release while
bin/castle install waits for it to return.
The scratch path lives under _build/castle/deployments. The template does
not create, clear or remove it. Register Deployment.stop/1 with on_exit/1
for every started deployment.
Mark the whole module with @moduletag :upgrade; these tests start named nodes
and should not run asynchronously or as part of the ordinary unit suite.