Add a workflow to compare the bazel/erlang.mk output

To catch any drift between the builds
This commit is contained in:
Rin Kuryloski 2023-05-01 10:32:59 +02:00
parent 1ee8454129
commit eb94a58bc9
29 changed files with 315 additions and 62 deletions

View File

@ -0,0 +1,125 @@
name: Check Bazel/Erlang.mk Equivalence
on:
schedule:
- cron: '0 2 * * *'
workflow_dispatch:
env:
erlang_version: 25.3
elixir_version: 1.14
VERSION: 3.13.0
PLUGINS: amqp10_common amqp10_client rabbitmq_amqp1_0 rabbitmq_auth_backend_cache rabbitmq_auth_backend_http rabbitmq_auth_backend_ldap rabbitmq_auth_backend_oauth2 rabbitmq_auth_mechanism_ssl rabbitmq_consistent_hash_exchange rabbitmq_event_exchange rabbitmq_federation rabbitmq_jms_topic_exchange rabbitmq_mqtt rabbitmq_random_exchange rabbitmq_recent_history_exchange rabbitmq_sharding rabbitmq_shovel rabbitmq_stomp rabbitmq_stream rabbitmq_trust_store rabbitmq_web_dispatch rabbitmq_management_agent rabbitmq_management rabbitmq_prometheus rabbitmq_federation_management rabbitmq_shovel_management rabbitmq_stream_management rabbitmq_top rabbitmq_tracing rabbitmq_web_mqtt rabbitmq_web_mqtt_examples rabbitmq_web_stomp rabbitmq_web_stomp_examples rabbitmq_aws rabbitmq_peer_discovery_common rabbitmq_peer_discovery_aws rabbitmq_peer_discovery_k8s rabbitmq_peer_discovery_consul rabbitmq_peer_discovery_etcd
jobs:
build-with-bazel:
name: bazel build package-generic-unix.tar.xz
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: CHECKOUT REPOSITORY
uses: actions/checkout@v3
- name: CONFIGURE ERLANG
uses: erlef/setup-beam@v1.15.3
with:
otp-version: ${{ env.erlang_version }}
elixir-version: ${{ env.elixir_version }}
- name: CONFIGURE BAZEL
run: |
cat << EOF >> user.bazelrc
build --disk_cache=
build --color=yes
EOF
- name: BUILD package-generic-unix.tar.xz
run: |
bazelisk build //:package-generic-unix
- name: RESOLVE ARCHIVES_DIR
run: |
echo "archives_dir=$(readlink -f bazel-bin)" >> $GITHUB_ENV
- name: UPLOAD package-generic-unix.tar.xz
uses: actions/upload-artifact@v3.1.2
with:
name: bazel-package-generic-unix.tar.xz
path: ${{ env.archives_dir }}/package-generic-unix.tar.xz
if-no-files-found: error
build-with-make:
name: make package-generic-unix.tar.xz
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: CHECKOUT REPOSITORY
uses: actions/checkout@v3
with:
path: rabbitmq
- name: CONFIGURE ERLANG
uses: erlef/setup-beam@v1.15.3
with:
otp-version: ${{ env.erlang_version }}
elixir-version: ${{ env.elixir_version }}
- name: BUILD package-generic-unix.tar.xz
env:
MAKE: make
run: |
$MAKE -C rabbitmq \
source-dist \
PACKAGES_DIR="$PWD/PACKAGES" \
PLUGINS="$PLUGINS" \
PROJECT_VERSION="$VERSION"
$MAKE -C rabbitmq/packaging \
package-generic-unix \
PACKAGES_DIR="$PWD/PACKAGES" \
VERSION="$VERSION"
- name: UPLOAD package-generic-unix.tar.xz
uses: actions/upload-artifact@v3.1.2
with:
name: make-package-generic-unix.tar.xz
path: PACKAGES/rabbitmq-server-generic-unix-*.tar.xz
if-no-files-found: error
compare:
needs:
- build-with-bazel
- build-with-make
name: Compare package-generic-unix.tar.xz
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: CHECKOUT REPOSITORY
uses: actions/checkout@v3
with:
path: rabbitmq-server
- name: CONFIGURE ERLANG
uses: erlef/setup-beam@v1.15.3
with:
otp-version: ${{ env.erlang_version }}
elixir-version: ${{ env.elixir_version }}
- name: DOWNLOAD bazel-package-generic-unix.tar.xz
uses: actions/download-artifact@v3
with:
name: bazel-package-generic-unix.tar.xz
- name: DOWNLOAD make-package-generic-unix.tar.xz
uses: actions/download-artifact@v3
with:
name: make-package-generic-unix.tar.xz
- name: EXPAND & COMPARE
run: |
mkdir bazel
pushd bazel
tar -xf ${{ github.workspace }}/package-generic-unix.tar.xz
find . | sort > ${{ github.workspace }}/bazel.manifest
popd
mkdir make
pushd make
tar -xf ${{ github.workspace }}/rabbitmq-server-generic-unix-*.tar.xz
# delete an empty directory
rm -d rabbitmq_server-*/plugins/rabbitmq_random_exchange-*/include
find . | sort > ${{ github.workspace }}/make.manifest
popd
tree -L 2 bazel
tree -L 2 make
sleep 1
set -x
./rabbitmq-server/tools/compare_dist.sh make bazel

View File

@ -69,8 +69,11 @@ exports_files([
# gazelle:exclude deps/*/deps
# gazelle:exclude deps/*/.erlang.mk
# gazelle:exclude deps/rabbitmq_cli/_build
# gazelle:exclude extra_deps
# gazelle:exclude packaging
# gazelle:exclude PACKAGES
# gazelle:exclude plugins
# gazelle:exclude release-notes
# gazelle:exclude logs
# gazelle:erlang_apps_dirs deps
# gazelle:erlang_skip_rules test_erlang_app
@ -217,13 +220,7 @@ iex_eval(
filegroup(
name = "root-licenses",
srcs = glob(
["LICENSE*"],
exclude = [
"LICENSE.md",
"LICENSE.txt",
],
),
srcs = glob(["LICENSE*"]),
visibility = ["//visibility:public"],
)

View File

@ -207,8 +207,8 @@ erlang_package.hex_package(
erlang_package.hex_package(
name = "gen_batch_server",
build_file = "@rabbitmq-server//bazel:BUILD.gen_batch_server",
sha256 = "94a49a528486298b009d2a1b452132c0a0d68b3e89d17d3764cb1ec879b7557a",
version = "0.8.7",
sha256 = "c3e6a1a2a0fb62aee631a98cfa0fd8903e9562422cbf72043953e2fb1d203017",
version = "0.8.8",
)
erlang_package.hex_package(

View File

@ -17,10 +17,12 @@ erlc_opts(
erlang_bytecode(
name = "behaviours",
srcs = ["src/ranch_transport.erl"],
outs = ["ebin/ranch_transport.beam"],
hdrs = [],
srcs = [
"src/ranch_transport.erl",
],
hdrs = [":public_and_private_hdrs"],
app_name = "ranch",
dest = "ebin",
erlc_opts = "//:erlc_opts",
)
@ -44,27 +46,10 @@ erlang_bytecode(
"src/ranch_sup.erl",
"src/ranch_tcp.erl",
],
outs = [
"ebin/ranch.beam",
"ebin/ranch_acceptor.beam",
"ebin/ranch_acceptors_sup.beam",
"ebin/ranch_app.beam",
"ebin/ranch_conns_sup.beam",
"ebin/ranch_conns_sup_sup.beam",
"ebin/ranch_crc32c.beam",
"ebin/ranch_embedded_sup.beam",
"ebin/ranch_listener_sup.beam",
"ebin/ranch_protocol.beam",
"ebin/ranch_proxy_header.beam",
"ebin/ranch_server.beam",
"ebin/ranch_server_proxy.beam",
"ebin/ranch_ssl.beam",
"ebin/ranch_sup.beam",
"ebin/ranch_tcp.beam",
],
hdrs = [],
hdrs = [":public_and_private_hdrs"],
app_name = "ranch",
beam = [":behaviours"],
dest = "ebin",
erlc_opts = "//:erlc_opts",
)
@ -99,19 +84,15 @@ filegroup(
],
)
filegroup(
name = "private_hdrs",
srcs = [],
)
filegroup(name = "private_hdrs")
filegroup(
name = "public_hdrs",
srcs = [],
)
filegroup(name = "public_hdrs")
filegroup(
name = "priv",
srcs = [],
srcs = [
"ebin/ranch.appup", # keep
],
)
filegroup(
@ -138,9 +119,12 @@ filegroup(
erlang_app(
name = "erlang_app",
srcs = [":all_srcs"],
hdrs = [":public_hdrs"],
app_name = "ranch",
beam_files = [":beam_files"],
extra_apps = ["ssl"],
license_files = [":license_files"],
priv = [":priv"],
)
alias(
@ -148,3 +132,10 @@ alias(
actual = ":erlang_app",
visibility = ["//visibility:public"],
)
filegroup(
name = "license_files",
srcs = [
"LICENSE",
],
)

View File

@ -28,7 +28,7 @@ APP_EXTRA_KEYS = """%% Hex.pm package informations.
{licenses, ["MPL-2.0"]},
{links, [
{"Website", "https://www.rabbitmq.com/"},
{"GitHub", "https://github.com/rabbitmq/rabbitmq-server/deps/amqp10_client"}
{"GitHub", "https://github.com/rabbitmq/rabbitmq-server/tree/main/deps/amqp10_client"}
]},
{build_tools, ["make", "rebar3"]},
{files, [

View File

@ -31,7 +31,7 @@ PACKAGES_DIR ?= $(abspath PACKAGES)
BUILD_DEPS = rabbit_common elvis_mk
DEPS = amqp10_common
TEST_DEPS = rabbit rabbitmq_amqp1_0 rabbitmq_ct_helpers
LOCAL_DEPS = ssl inets crypto
LOCAL_DEPS = ssl inets crypto public_key
DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-test.mk
DEP_PLUGINS = rabbit_common/mk/rabbitmq-macros.mk \

View File

@ -54,7 +54,7 @@ APP_EXTRA_KEYS = """%% Hex.pm package informations.
{licenses, ["MPL-2.0"]},
{links, [
{"Website", "https://www.rabbitmq.com/"},
{"GitHub", "https://github.com/rabbitmq/rabbitmq-server/deps/amqp10_common"}
{"GitHub", "https://github.com/rabbitmq/rabbitmq-server/tree/main/deps/amqp10_common"}
]},
{build_tools, ["make", "rebar3"]},
{files, [
@ -66,7 +66,7 @@ APP_EXTRA_KEYS = """%% Hex.pm package informations.
"rabbitmq-components.mk",
"README",
"README.md",
"mk"
"src"
]}
"""

View File

@ -1140,7 +1140,7 @@ genrule(
outs = ["manpages.tar"],
cmd = """set -euo pipefail
DESTDIR=manpages-tmp/share/man
DESTDIR=share/man
mkdir -p $${DESTDIR}
for mp in $(SRCS); do
section=$${mp##*.}
@ -1148,8 +1148,8 @@ for mp in $(SRCS); do
gzip < $$mp \\
> $${DESTDIR}/man$$section/$$(basename $$mp).gz
done
tar --strip-components 1 -cf $@ manpages-tmp/*
rm -dr manpages-tmp
tar -cf $@ share
rm -dr share
""",
visibility = ["//visibility:public"],
)

5
deps/rabbit/app.bzl vendored
View File

@ -501,10 +501,7 @@ def all_srcs(name = "all_srcs"):
filegroup(
name = "priv",
srcs = [
"priv/schema/.gitignore",
"priv/schema/rabbit.schema",
],
srcs = ["priv/schema/rabbit.schema"], #keep
)
filegroup(
name = "private_hdrs",

View File

@ -28,7 +28,7 @@ endef
LOCAL_DEPS = compiler crypto public_key sasl ssl syntax_tools tools xmerl
DEPS = thoas recon credentials_obfuscation
dep_credentials_obfuscation = hex 3.2.0
dep_credentials_obfuscation = hex 3.4.0
# Variables and recipes in development.*.mk are meant to be used from
# any Git clone. They are excluded from the files published to Hex.pm.

View File

@ -20,7 +20,9 @@ load(
)
APP_ENV = """[
{http_method, get},
{http_method, get},
{request_timeout, 15000},
{connection_timeout, 15000},
{user_path, "http://localhost:8000/auth/user"},
{vhost_path, "http://localhost:8000/auth/vhost"},
{resource_path, "http://localhost:8000/auth/resource"},

View File

@ -34,7 +34,7 @@ define PROJECT_APP_EXTRA_KEYS
{broker_version_requirements, []}
endef
LOCAL_DEPS = eldap
LOCAL_DEPS = eldap public_key
DEPS = rabbit_common rabbit
TEST_DEPS = ct_helper rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client
dep_ct_helper = git https://github.com/extend/ct_helper.git master

View File

@ -5,6 +5,7 @@ PROJECT_DESCRIPTION = OAuth 2 and JWT-based AuthN and AuthZ backend
BUILD_WITHOUT_QUIC=1
export BUILD_WITHOUT_QUIC
LOCAL_DEPS = inets public_key
BUILD_DEPS = rabbit_common
DEPS = rabbit cowlib jose base64url
TEST_DEPS = cowboy rabbitmq_web_dispatch rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client rabbitmq_mqtt emqtt

View File

@ -12,6 +12,7 @@ define PROJECT_APP_EXTRA_KEYS
{broker_version_requirements, []}
endef
LOCAL_DEPS = public_key
DEPS = rabbit_common rabbit
DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk

View File

@ -7,7 +7,7 @@ define PROJECT_ENV
[]
endef
LOCAL_DEPS = crypto inets ssl xmerl
LOCAL_DEPS = crypto inets ssl xmerl public_key
BUILD_DEPS = rabbit_common
DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk
TEST_DEPS = meck

View File

@ -5,7 +5,7 @@ define PROJECT_APP_EXTRA_KEYS
{broker_version_requirements, []}
endef
DEPS = rabbit_common rabbit rabbitmq_management rabbitmq_federation
DEPS = amqp_client rabbit_common rabbit rabbitmq_management rabbitmq_federation
TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers
DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk

View File

@ -1,6 +1,7 @@
PROJECT = rabbitmq_jms_topic_exchange
PROJECT_DESCRIPTION = RabbitMQ JMS topic selector exchange plugin
LOCAL_DEPS = mnesia
DEPS = rabbit_common rabbit
TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client

View File

@ -61,7 +61,7 @@ test_suite_beam_files(name = "test_suite_beam_files")
# gazelle:erlang_app_extra_app crypto
# gazelle:erlang_app_extra_app public_key
# gazelle:erlang_app_dep_exclude ranch
# gazelle:erlang_app_dep ranch
rabbitmq_app(
name = "erlang_app",
@ -89,6 +89,7 @@ rabbitmq_app(
"//deps/rabbitmq_web_dispatch:erlang_app",
"@cowboy//:erlang_app",
"@cowlib//:erlang_app",
"@ranch//:erlang_app",
],
)

View File

@ -39,6 +39,7 @@ endef
BUILD_WITHOUT_QUIC=1
export BUILD_WITHOUT_QUIC
LOCAL_DEPS = ssl
DEPS = ranch rabbit_common rabbit amqp_client ra
TEST_DEPS = emqtt ct_helper rabbitmq_ct_helpers rabbitmq_ct_client_helpers rabbitmq_management rabbitmq_web_mqtt

View File

@ -43,6 +43,7 @@ rabbitmq_app(
name = "erlang_app",
srcs = [":all_srcs"],
hdrs = [":public_hdrs"],
app_description = "Prometheus metrics for RabbitMQ",
app_env = APP_ENV,
app_module = APP_MODULE,
app_name = APP_NAME,

View File

@ -7,8 +7,9 @@ define PROJECT_ENV
endef
PROJECT := rabbitmq_prometheus
PROJECT_DESCRIPTION = Prometheus metrics for RabbitMQ
PROJECT_MOD := rabbit_prometheus_app
DEPS = accept rabbit rabbitmq_management_agent prometheus rabbitmq_web_dispatch
DEPS = accept cowboy rabbit rabbitmq_management_agent prometheus rabbitmq_web_dispatch
BUILD_DEPS = amqp_client rabbit_common rabbitmq_management
TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers eunit_formatters

View File

@ -21,7 +21,8 @@ define PROJECT_ENV
endef
DEPS = rabbit rabbitmq_stream_common
LOCAL_DEPS = ssl
DEPS = rabbit rabbitmq_stream_common osiris ranch
TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client
DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk

View File

@ -10,7 +10,7 @@ define PROJECT_ENV
endef
DEPS = rabbit_common rabbit
LOCAL_DEPS += ssl crypto public_key
LOCAL_DEPS += ssl crypto public_key inets
## We need the Cowboy's test utilities
TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client ct_helper trust_store_http
dep_ct_helper = git https://github.com/extend/ct_helper.git master

View File

@ -17,6 +17,7 @@ endef
BUILD_WITHOUT_QUIC=1
export BUILD_WITHOUT_QUIC
LOCAL_DEPS = ssl
DEPS = rabbit_common rabbit cowboy rabbitmq_mqtt
TEST_DEPS = emqtt rabbitmq_ct_helpers rabbitmq_ct_client_helpers rabbitmq_management

View File

@ -77,7 +77,7 @@ def _sbin_dir_private_impl(ctx):
]
def _escript_dir_private_impl(ctx):
escripts = [copy_escript(ctx, escript) for escript in ctx.files._scripts]
escripts = [copy_escript(ctx, escript) for escript in ctx.files._escripts]
return [
DefaultInfo(
@ -136,6 +136,12 @@ def _versioned_plugins_dir_impl(ctx):
maybe_install_erlang(ctx),
]
commands.append(
"echo 'Put your EZs here and use rabbitmq-plugins to enable them.' > {plugins_dir}/README".format(
plugins_dir = plugins_dir.path,
)
)
for plugin in plugins:
lib_info = plugin[ErlangAppInfo]
version = _extract_version(lib_info)

View File

@ -78,7 +78,9 @@ ALL_PLUGINS = [
"//deps/rabbitmq_trust_store:erlang_app",
"//deps/rabbitmq_web_dispatch:erlang_app",
"//deps/rabbitmq_web_mqtt:erlang_app",
"//deps/rabbitmq_web_mqtt_examples:erlang_app",
"//deps/rabbitmq_web_stomp:erlang_app",
"//deps/rabbitmq_web_stomp_examples:erlang_app",
]
LABELS_WITH_TEST_VERSIONS = [

View File

@ -87,7 +87,7 @@ def _impl(ctx):
source_scripts = ctx.files._scripts_windows
scripts = [_copy_script(ctx, script) for script in source_scripts]
escripts = [copy_escript(ctx, escript) for escript in ctx.files._scripts]
escripts = [copy_escript(ctx, escript) for escript in ctx.files._escripts]
plugins = flatten([_plugins_dir_links(ctx, plugin) for plugin in plugins])
@ -108,6 +108,18 @@ def _impl(ctx):
]
RABBITMQ_HOME_ATTRS = {
"_escripts": attr.label_list(
default = [
"//deps/rabbit:scripts/rabbitmq-diagnostics",
"//deps/rabbit:scripts/rabbitmq-plugins",
"//deps/rabbit:scripts/rabbitmq-queues",
"//deps/rabbit:scripts/rabbitmq-streams",
"//deps/rabbit:scripts/rabbitmq-upgrade",
"//deps/rabbit:scripts/rabbitmqctl",
"//deps/rabbit:scripts/vmware-rabbitmq",
],
allow_files = True,
),
"_scripts": attr.label_list(
default = [
"//deps/rabbit:scripts/rabbitmq-defaults",

44
tools/compare_dist.sh Executable file
View File

@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -euo pipefail
GOLDEN=$1
SECOND=$2
echo "Check both have INSTALL"
test -f $GOLDEN/rabbitmq_server-${VERSION}/INSTALL
test -f $SECOND/rabbitmq_server-${VERSION}/INSTALL
echo "Check LICENSEs"
diff \
<(grep LICENSE make.manifest) \
<(grep LICENSE bazel.manifest | grep -v ".md" | grep -v ".txt")
echo "Check plugins"
plugins_rel=rabbitmq_server-${VERSION}/plugins
diff <(grep $plugins_rel make.manifest | grep -v ".ez") <(grep $plugins_rel bazel.manifest | grep -v ".ez")
echo "Plugins exist with same version and deps"
for p in ${PLUGINS}; do
echo "$p"
f="$(cd $GOLDEN && ls -d $plugins_rel/$p-*)"
test -f $GOLDEN/$f/ebin/$p.app || (echo "$GOLDEN/$f/ebin/$p.app does not exist"; exit 1)
test -d $SECOND/$f || (echo "$SECOND/$f does not exist"; exit 1)
test -f $SECOND/$f/ebin/$p.app || (echo "$SECOND/$f/ebin/$p.app does not exist"; exit 1)
./rabbitmq-server/tools/erlang_app_equal \
$GOLDEN/$f/ebin/$p.app \
$SECOND/$f/ebin/$p.app
done
echo "Both have escript"
escript_rel=rabbitmq_server-${VERSION}/escript
diff <(grep $escript_rel make.manifest) <(grep $escript_rel bazel.manifest)
echo "Both have sbin"
sbin_rel=rabbitmq_server-${VERSION}/sbin
diff <(grep $sbin_rel make.manifest) <(grep $sbin_rel bazel.manifest)
echo "Both have manpages"
manpages_rel=rabbitmq_server-${VERSION}/share/man
diff <(grep $manpages_rel make.manifest) <(grep $manpages_rel bazel.manifest)
echo "PASS"

68
tools/erlang_app_equal Executable file
View File

@ -0,0 +1,68 @@
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -nocookie
-mode(compile).
main([Left, Right]) ->
{ok, LeftMetadata} = file:consult(Left),
{ok, RightMetadata} = file:consult(Right),
compare(LeftMetadata, RightMetadata),
halt();
main(_) ->
halt(1).
compare(LeftMetadata, RightMetadata) ->
[{application, LeftApp, LeftProps}] = LeftMetadata,
[{application, RightApp, RightProps}] = RightMetadata,
assert_equal(LeftApp, RightApp, "application name"),
LeftId = proplists:get_value(id, LeftProps),
RightId = proplists:get_value(id, RightProps),
case LeftId of
RightId ->
ok;
_ ->
io:format(standard_error,
"Warning:\t 'id' does not match (~p != ~p)~n", [LeftId, RightId])
end,
LeftPropsMap = proplists:to_map(proplists:delete(id, LeftProps)),
RightPropsMap = proplists:to_map(proplists:delete(id, RightProps)),
assert_equal(
lists:sort(maps:keys(LeftPropsMap)),
lists:sort(maps:keys(RightPropsMap)),
"app property keys"
),
[case K of
K when K =:= applications orelse K =:= modules ->
assert_equal(
lists:sort(maps:get(K, LeftPropsMap)),
lists:sort(maps:get(K, RightPropsMap)),
K
);
env ->
assert_equal(
proplists:to_map(maps:get(K, LeftPropsMap)),
proplists:to_map(maps:get(K, RightPropsMap)),
K
);
_ ->
assert_equal(
maps:get(K, LeftPropsMap),
maps:get(K, RightPropsMap),
K
)
end || K <- lists:sort(maps:keys(LeftPropsMap))],
ok.
assert_equal(Expected, Actual, Context) ->
case Actual of
Expected ->
ok;
_ ->
io:format(standard_error,
"Expected:\t~p~n But got:\t~p~n For:\t~p~n", [Expected, Actual, Context]),
erlang:error(assertion_failed)
end.