]> Entropealabs - wampex_test_suite.git/commitdiff
initial commit
authorChristopher <chris@entropealabs.com>
Fri, 17 Apr 2020 18:37:04 +0000 (13:37 -0500)
committerChristopher <chris@entropealabs.com>
Fri, 17 Apr 2020 18:37:04 +0000 (13:37 -0500)
16 files changed:
.formatter.exs [new file with mode: 0644]
.gitignore [new file with mode: 0644]
README.md [new file with mode: 0644]
config/config.exs [new file with mode: 0644]
lib/wampex_test_suite.ex [new file with mode: 0644]
mix.exs [new file with mode: 0644]
mix.lock [new file with mode: 0644]
test/cluster_kv_test.exs [new file with mode: 0644]
test/support/authentication.ex [new file with mode: 0644]
test/support/authorization.ex [new file with mode: 0644]
test/support/test_callee.ex [new file with mode: 0644]
test/support/test_subscriber.ex [new file with mode: 0644]
test/test_helper.exs [new file with mode: 0644]
test/wampex_router_test.exs [new file with mode: 0644]
test/wampex_test.exs [new file with mode: 0644]
test/wampex_test_suite_test.exs [new file with mode: 0644]

diff --git a/.formatter.exs b/.formatter.exs
new file mode 100644 (file)
index 0000000..d2cda26
--- /dev/null
@@ -0,0 +1,4 @@
+# Used by "mix format"
+[
+  inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
+]
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..9c877a1
--- /dev/null
@@ -0,0 +1,24 @@
+# The directory Mix will write compiled artifacts to.
+/_build/
+
+# If you run "mix test --cover", coverage assets end up here.
+/cover/
+
+# The directory Mix downloads your dependencies sources to.
+/deps/
+
+# Where third-party dependencies like ExDoc output generated docs.
+/doc/
+
+# Ignore .fetch files in case you like to edit your project deps locally.
+/.fetch
+
+# If the VM crashes, it generates a dump, let's ignore it too.
+erl_crash.dump
+
+# Also ignore archive artifacts (built via "mix archive.build").
+*.ez
+
+# Ignore package tarball (built via "mix hex.build").
+wampex_test_suite-*.tar
+
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..50864e1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,21 @@
+# WampexTestSuite
+
+**TODO: Add description**
+
+## Installation
+
+If [available in Hex](https://hex.pm/docs/publish), the package can be installed
+by adding `wampex_test_suite` to your list of dependencies in `mix.exs`:
+
+```elixir
+def deps do
+  [
+    {:wampex_test_suite, "~> 0.1.0"}
+  ]
+end
+```
+
+Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
+and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
+be found at [https://hexdocs.pm/wampex_test_suite](https://hexdocs.pm/wampex_test_suite).
+
diff --git a/config/config.exs b/config/config.exs
new file mode 100644 (file)
index 0000000..61dbdf6
--- /dev/null
@@ -0,0 +1,4 @@
+use Mix.Config
+
+config :logger,
+  level: :info
diff --git a/lib/wampex_test_suite.ex b/lib/wampex_test_suite.ex
new file mode 100644 (file)
index 0000000..6b86963
--- /dev/null
@@ -0,0 +1,18 @@
+defmodule WampexTestSuite do
+  @moduledoc """
+  Documentation for WampexTestSuite.
+  """
+
+  @doc """
+  Hello world.
+
+  ## Examples
+
+      iex> WampexTestSuite.hello()
+      :world
+
+  """
+  def hello do
+    :world
+  end
+end
diff --git a/mix.exs b/mix.exs
new file mode 100644 (file)
index 0000000..30cad0c
--- /dev/null
+++ b/mix.exs
@@ -0,0 +1,65 @@
+defmodule WampexTestSuite.MixProject do
+  use Mix.Project
+
+  def project do
+    [
+      app: :wampex_test_suite,
+      version: "0.1.0",
+      elixir: "~> 1.9",
+      elixirc_paths: elixirc_paths(),
+      start_permanent: Mix.env() == :prod,
+      aliases: aliases(),
+      deps: deps(),
+      preferred_cli_env: [
+        coveralls: :test,
+        "coveralls.detail": :test,
+        "coveralls.post": :test,
+        "coveralls.html": :test,
+        all_tests: :test
+      ],
+      test_coverage: [tool: ExCoveralls]
+    ]
+  end
+
+  def application do
+    [
+      extra_applications: [:logger]
+    ]
+  end
+
+  defp elixirc_paths, do: ["lib", "test/support"]
+
+  def deps do
+    [
+      {:excoveralls, "~> 0.12.2", runtime: false}
+    ] ++ deps(Mix.env())
+  end
+
+  defp deps(:dev) do
+    [
+      {:cluster_kv, path: "../cluster_kv", override: true},
+      {:wampex, path: "../wampex", override: true},
+      {:wampex_client, path: "../wampex_client"},
+      {:wampex_router, path: "../wampex_router"}
+    ]
+  end
+
+  defp deps(:test) do
+    [
+      {:cluster_kv,
+       git: "https://gitlab.com/entropealabs/cluster_kv.git", tag: "dev", override: true},
+      {:wampex, git: "https://gitlab.com/entropealabs/wampex.git", tag: "dev", override: true},
+      {:wampex_client, git: "https://gitlab.com/entropealabs/wampex_client.git", tag: "dev"},
+      {:wampex_router, git: "https://gitlab.com/entropealabs/wampex_router.git", tag: "dev"}
+    ]
+  end
+
+  defp aliases do
+    [
+      all_tests: [
+        "compile --force --warnings-as-errors",
+        "coveralls"
+      ]
+    ]
+  end
+end
diff --git a/mix.lock b/mix.lock
new file mode 100644 (file)
index 0000000..e30591c
--- /dev/null
+++ b/mix.lock
@@ -0,0 +1,37 @@
+%{
+  "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"},
+  "cluster_kv": {:git, "https://gitlab.com/entropealabs/cluster_kv.git", "bcb05440a2b39e921b7f0e333b2fbb98e35520ce", [tag: "dev"]},
+  "conv_case": {:hex, :conv_case, "0.2.2", "5a98b74ab8f7ddbad670e5c7bb39ff280e60699aa3b25c7062ceccf48137433c", [:mix], [], "hexpm", "561c550ab6d55b2a4d4c14449e58c9957798613eb26ea182e14a962965377bca"},
+  "cors_plug": {:hex, :cors_plug, "2.0.2", "2b46083af45e4bc79632bd951550509395935d3e7973275b2b743bd63cc942ce", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f0d0e13f71c51fd4ef8b2c7e051388e4dfb267522a83a22392c856de7e46465f"},
+  "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "04fd8c6a39edc6aaa9c26123009200fc61f92a3a94f3178c527b70b767c6e605"},
+  "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm", "79f954a7021b302186a950a32869dbc185523d99d3e44ce430cd1f3289f41ed4"},
+  "elixpath": {:hex, :elixpath, "0.1.0", "f860e931db7bda6856dc68145694ca429643cc068ef30d7ff6b4096d4357963e", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "30ce06079b41f1f5216ea2cd11605cfe4c82239628555cb3fde9f10055a6eb67"},
+  "excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "568a3e616c264283f5dea5b020783ae40eef3f7ee2163f7a67cbd7b35bcadada"},
+  "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"},
+  "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
+  "jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"},
+  "json_xema": {:hex, :json_xema, "0.4.0", "377446cd5c0e2cbba52b9d7ab67c05579e6d4a788335220215a8870eac821996", [:mix], [{:conv_case, "~> 0.2", [hex: :conv_case, repo: "hexpm", optional: false]}, {:xema, "~> 0.11", [hex: :xema, repo: "hexpm", optional: false]}], "hexpm", "452724a5b2751cd69191edd3fd3da0c2194c164ebd49efd85f9abb64d6621b53"},
+  "libcluster": {:hex, :libcluster, "3.2.1", "b2cd5b447cde25d5897749bee6f7aaeb6c96ac379481024e9b6ba495dabeb97d", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "89f225612d135edce9def56f43bf18d575d88ac4680e3f6161283f2e55cadca4"},
+  "libring": {:hex, :libring, "1.5.0", "44313eb6862f5c9168594a061e9d5f556a9819da7c6444706a9e2da533396d70", [:mix], [], "hexpm", "04e843d4fdcff49a62d8e03778d17c6cb2a03fe2d14020d3825a1761b55bd6cc"},
+  "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
+  "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm", "6cbe761d6a0ca5a31a0931bf4c63204bceb64538e664a8ecf784a9a6f3b875f1"},
+  "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
+  "msgpax": {:hex, :msgpax, "2.2.4", "7b3790ef684089076b63c0f08c2f4b079c6311daeb006b69e4ed2bf67518291e", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "b351b6d992d79624a8430a99d21a41b36b1b90edf84326a294e9f4a2de11f089"},
+  "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
+  "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
+  "pbkdf2": {:hex, :pbkdf2, "2.0.0", "11c23279fded5c0027ab3996cfae77805521d7ef4babde2bd7ec04a9086cf499", [:rebar3], [], "hexpm", "1e793ce6fdb0576613115714deae9dfc1d1537eaba74f07efb36de139774488d"},
+  "plug": {:hex, :plug, "1.10.0", "6508295cbeb4c654860845fb95260737e4a8838d34d115ad76cd487584e2fc4d", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "422a9727e667be1bf5ab1de03be6fa0ad67b775b2d84ed908f3264415ef29d4a"},
+  "plug_cowboy": {:hex, :plug_cowboy, "2.1.3", "38999a3e85e39f0e6bdfdf820761abac61edde1632cfebbacc445cdcb6ae1333", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "056f41f814dbb38ea44613e0f613b3b2b2f2c6afce64126e252837669eba84db"},
+  "plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"},
+  "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
+  "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
+  "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"},
+  "states_language": {:hex, :states_language, "0.2.9", "5c8c6b7d37ea6952c4345960d22facb2159ae6f8b06514c0fdc320b8077e1277", [:mix], [{:elixpath, "~> 0.1.0", [hex: :elixpath, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:json_xema, "~> 0.4.0", [hex: :json_xema, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:xema, "~> 0.11.0", [hex: :xema, repo: "hexpm", optional: false]}], "hexpm", "2da0c7621e1574a2687790d321632a121eea6de4d86e77543f86a678cda65c40"},
+  "telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm", "4738382e36a0a9a2b6e25d67c960e40e1a2c95560b9f936d8e29de8cd858480f"},
+  "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
+  "wampex": {:git, "https://gitlab.com/entropealabs/wampex.git", "ae6f2cfcc23dc9af94fa2c375b52bad6c1d0f75d", [tag: "dev"]},
+  "wampex_client": {:git, "https://gitlab.com/entropealabs/wampex_client.git", "b01f5f0e8db0309d7db010269493c284d97b6645", [tag: "dev"]},
+  "wampex_router": {:git, "https://gitlab.com/entropealabs/wampex_router.git", "73c8e72448fc726c994bcf9576a269b1809339a4", [tag: "dev"]},
+  "websockex": {:hex, :websockex, "0.4.2", "9a3b7dc25655517ecd3f8ff7109a77fce94956096b942836cdcfbc7c86603ecc", [:mix], [], "hexpm", "803cd76e91544b56f0e655e36790be797fa6436db9224f7c303db9b9df2a3df4"},
+  "xema": {:hex, :xema, "0.11.0", "7b5118418633cffc27092110d02d4faeea938149dd3f6c64299e41e747067e80", [:mix], [{:conv_case, "~> 0.2.2", [hex: :conv_case, repo: "hexpm", optional: false]}, {:decimal, "~> 1.7", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "51491c9a953d65069d4b30aa2f70bc45ff99fd1bc3345bc72ce4e644d01ea14e"},
+}
diff --git a/test/cluster_kv_test.exs b/test/cluster_kv_test.exs
new file mode 100644 (file)
index 0000000..3335fba
--- /dev/null
@@ -0,0 +1,74 @@
+defmodule ClusterKVTest do
+  use ExUnit.Case
+  doctest ClusterKV
+
+  @topologies [
+    test: [
+      strategy: Cluster.Strategy.Epmd,
+      config: [hosts: []]
+    ]
+  ]
+
+  @keyspace "com.myrealm"
+
+  setup_all do
+    ClusterKV.start_link(name: TestCluster, topologies: @topologies, replicas: 1, quorum: 1)
+    [db: TestCluster]
+  end
+
+  test "test", %{db: db} do
+    me = {self(), self()}
+    ClusterKV.put(db, @keyspace, "test1:test", :hello)
+    ClusterKV.put(db, @keyspace, "test1:test", :cruel)
+    ClusterKV.put(db, @keyspace, "test1:test", :world)
+
+    assert "test:1" = ClusterKV.get_wildcard_key(".test.light..status", ".", ":", "")
+
+    ClusterKV.put_wildcard(
+      db,
+      @keyspace,
+      "com.test..temp",
+      {1_003_039_494, me},
+      ".",
+      ":",
+      ""
+    )
+
+    assert {"test1:test", [:world, :cruel, :hello]} = ClusterKV.get(db, @keyspace, "test1:test")
+
+    assert [{["com", "test", "", "temp"], {1_003_039_494, me}}] =
+             ClusterKV.wildcard(
+               db,
+               @keyspace,
+               "com.test.data.temp",
+               ".",
+               ":",
+               ""
+             )
+
+    ClusterKV.update(db, @keyspace, "test1:test", :cruel, fn {id, values}, value ->
+      {id, List.delete(values, value)}
+    end)
+
+    assert {"test1:test", [:world, :hello]} = ClusterKV.get(db, @keyspace, "test1:test")
+  end
+
+  test "update_if", %{db: db} do
+    assert :updated =
+             ClusterKV.update_if(db, @keyspace, "test.profile", :initial_value, &update_if/2)
+
+    assert :noop =
+             ClusterKV.update_if(db, @keyspace, "test.profile", :initial_value, &update_if/2)
+
+    assert :updated = ClusterKV.update_if(db, @keyspace, "test.profile", :new_value, &update_if/2)
+    assert :noop = ClusterKV.update_if(db, @keyspace, "test.profile", :new_value, &update_if/2)
+    assert :noop = ClusterKV.update_if(db, @keyspace, "test.profile", :new_value, &update_if/2)
+  end
+
+  defp update_if({key, [old]}, val) do
+    case old == val do
+      true -> :noop
+      false -> {:update, {key, [val]}}
+    end
+  end
+end
diff --git a/test/support/authentication.ex b/test/support/authentication.ex
new file mode 100644 (file)
index 0000000..26c906f
--- /dev/null
@@ -0,0 +1,72 @@
+defmodule Wampex.Router.AuthenticationImpl do
+  @moduledoc false
+  @behaviour Wampex.Router.Authentication
+  require Logger
+
+  alias Wampex.Crypto
+  alias Wampex.Serializers.JSON
+
+  @wampcra "wampcra"
+  @auth_provider "userdb"
+  @auth_role "user"
+  @auth_password "bnASR5qF9y8k/sHF6S+NneCOhvVI0zFkvoKQpc2F+hA="
+  @salt "test"
+  @keylen 8
+  @iterations 1
+
+  @impl true
+  def authenticate?(methods) do
+    can_auth(methods)
+  end
+
+  @impl true
+  def method, do: @wampcra
+
+  @impl true
+  def challenge(_realm, authid, session_id) do
+    now = DateTime.to_iso8601(DateTime.utc_now())
+
+    %{
+      challenge:
+        JSON.serialize!(%{
+          nonce: Crypto.random_string(@keylen),
+          authprovider: @auth_provider,
+          authid: authid,
+          timestamp: now,
+          authrole: @auth_role,
+          authmethod: @wampcra,
+          session: session_id
+        }),
+      salt: @salt,
+      keylen: @keylen,
+      iterations: @iterations
+    }
+  end
+
+  @impl true
+  def parse_challenge(challenge) do
+    ch = JSON.deserialize!(challenge.challenge)
+
+    {get_in(ch, ["authid"]), get_in(ch, ["authrole"]), get_in(ch, ["authmethod"]),
+     get_in(ch, ["authprovider"])}
+  end
+
+  @impl true
+  def authenticate(signature, realm, authid, %{
+        challenge: challenge
+      }) do
+    authed =
+      authid
+      |> get_secret(realm)
+      |> Crypto.hash_challenge(challenge)
+      |> :pbkdf2.compare_secure(signature)
+
+    {authed, %{}}
+  end
+
+  defp get_secret(_authid, _uri), do: Crypto.pbkdf2(@auth_password, @salt, @iterations, @keylen)
+
+  defp can_auth([]), do: false
+  defp can_auth([@wampcra | _]), do: true
+  defp can_auth([_ | t]), do: can_auth(t)
+end
diff --git a/test/support/authorization.ex b/test/support/authorization.ex
new file mode 100644 (file)
index 0000000..f0a55d7
--- /dev/null
@@ -0,0 +1,7 @@
+defmodule Wampex.Router.AuthorizationImpl do
+  @moduledoc false
+  @behaviour Wampex.Router.Authorization
+
+  @impl true
+  def authorized?(_, _, _), do: true
+end
diff --git a/test/support/test_callee.ex b/test/support/test_callee.ex
new file mode 100644 (file)
index 0000000..babdba2
--- /dev/null
@@ -0,0 +1,61 @@
+defmodule TestCallee do
+  @moduledoc false
+  use GenServer
+  require Logger
+  alias Wampex.Client
+  alias Wampex.Roles.{Callee, Dealer}
+  alias Wampex.Roles.Peer.Error
+  alias Callee.{Register, Yield}
+  alias Dealer.Invocation
+
+  def start_link(test, name, device) do
+    GenServer.start_link(__MODULE__, {test, name, device})
+  end
+
+  def init({test, name, device}) do
+    Client.add(name, self())
+    {:ok, {test, name, device}}
+  end
+
+  def handle_info({:connected, _}, {test, name, device} = state) do
+    {:ok, _reg} = Client.register(name, %Register{procedure: "com.actuator.#{device}.light"})
+    {:ok, reg} = Client.register(name, %Register{procedure: "return.error"})
+    send(test, {:registered, reg})
+    {:noreply, state}
+  end
+
+  def handle_info(
+        %Invocation{
+          request_id: id,
+          details: %{"procedure" => "return.error"},
+          arg_list: al,
+          arg_kw: akw
+        },
+        {_test, name, _device} = state
+      ) do
+    Client.error(
+      name,
+      %Error{request_id: id, error: "this.is.an.error", arg_list: al, arg_kw: akw}
+    )
+
+    {:noreply, state}
+  end
+
+  def handle_info(
+        %Invocation{request_id: id, details: _dets, arg_kw: arg_kw} = invocation,
+        {test, name, _device} = state
+      ) do
+    send(test, invocation)
+
+    Client.yield(
+      name,
+      %Yield{
+        request_id: id,
+        arg_list: [:ok],
+        arg_kw: %{color: Map.get(arg_kw, "color")}
+      }
+    )
+
+    {:noreply, state}
+  end
+end
diff --git a/test/support/test_subscriber.ex b/test/support/test_subscriber.ex
new file mode 100644 (file)
index 0000000..bde5dfa
--- /dev/null
@@ -0,0 +1,39 @@
+defmodule TestSubscriber do
+  @moduledoc false
+  use GenServer
+  require Logger
+  alias Wampex.Client
+  alias Wampex.Roles.Subscriber.Subscribe
+
+  def start_link(test, name, topic) do
+    GenServer.start_link(__MODULE__, {test, name, topic})
+  end
+
+  def init({test, name, topic}) do
+    Client.add(name, self())
+    {:ok, {test, name, topic}}
+  end
+
+  def handle_info({:connected, _client}, {test, name, topic}) do
+    {:ok, _sub1} = Client.subscribe(name, %Subscribe{topic: topic})
+    {:ok, _sub2} = Client.subscribe(name, %Subscribe{topic: "com.data.test"})
+    {:ok, _sub3} = Client.subscribe(name, %Subscribe{topic: "com.data"})
+
+    {:ok, _sub4} =
+      Client.subscribe(name, %Subscribe{topic: "com...temp", options: %{"match" => "wildcard"}})
+
+    {:ok, sub5} =
+      Client.subscribe(name, %Subscribe{
+        topic: "com..test.temp",
+        options: %{"match" => "wildcard"}
+      })
+
+    send(test, {:subscribed, sub5})
+    {:noreply, {test, name, topic}}
+  end
+
+  def handle_info(event, {test, _name, _topic} = state) do
+    send(test, event)
+    {:noreply, state}
+  end
+end
diff --git a/test/test_helper.exs b/test/test_helper.exs
new file mode 100644 (file)
index 0000000..869559e
--- /dev/null
@@ -0,0 +1 @@
+ExUnit.start()
diff --git a/test/wampex_router_test.exs b/test/wampex_router_test.exs
new file mode 100644 (file)
index 0000000..ebfda61
--- /dev/null
@@ -0,0 +1,179 @@
+defmodule WampexRouterTest do
+  use ExUnit.Case, async: true
+
+  alias Wampex.Client
+  alias Wampex.Client.{Authentication, Realm, Session}
+  alias Wampex.Roles.Broker.Event
+  alias Wampex.Roles.{Callee, Caller, Peer, Publisher, Subscriber}
+  alias Wampex.Roles.Caller.Call
+  alias Wampex.Roles.Dealer.{Invocation, Result}
+  alias Wampex.Roles.Peer.{Error, Hello}
+  alias Wampex.Roles.Publisher.Publish
+  alias Wampex.Router
+  alias Wampex.Router.AuthenticationImpl
+  alias Wampex.Router.AuthorizationImpl
+  require Logger
+
+  @topologies [
+    test: [
+      strategy: Cluster.Strategy.Epmd,
+      config: [hosts: []]
+    ]
+  ]
+
+  @url "ws://localhost:5999/ws"
+  @authid "admin"
+  @auth_password "bnASR5qF9y8k/sHF6S+NneCOhvVI0zFkvoKQpc2F+hA="
+  @realm_uri "admin"
+  @auth %Authentication{authid: @authid, authmethods: ["wampcra"], secret: @auth_password}
+  @realm %Realm{name: @realm_uri, authentication: @auth}
+  @roles [Caller, Callee, Publisher, Subscriber]
+  @device "as987d9a8sd79a87ds"
+  @session %Session{url: @url, realm: @realm, roles: @roles}
+  @s Supervisor.child_spec(
+       {Router,
+        name: TestRouter,
+        port: 5999,
+        topologies: @topologies,
+        replicas: 1,
+        quorum: 1,
+        authentication_module: AuthenticationImpl,
+        authorization_module: AuthorizationImpl},
+       id: Test
+     )
+
+  setup do
+    start_supervised(@s)
+    :ok
+  end
+
+  test "role not supported" do
+    callee_name = TestCalleeAbortRegistration
+    Client.start_link(name: callee_name, session: @session, reconnect: false)
+    TestCallee.start_link(self(), callee_name, @device)
+
+    name = TestCallerFail
+    [_ | t] = @session.roles
+    sess = %Session{@session | roles: t}
+    {:ok, _pid} = Client.start_link(name: name, session: sess, reconnect: false)
+
+    Client.call(name, %Call{procedure: "com.actuator.#{@device}.light"})
+  catch
+    :exit, {:end, er} -> Logger.error(inspect(er))
+    :exit, {:shutdown, er} -> Logger.error(inspect(er))
+  end
+
+  test "callee registration" do
+    name = TestCalleeRegistration
+    Client.start_link(name: name, session: @session, reconnect: false)
+    TestCallee.start_link(self(), name, @device)
+    assert_receive {:registered, id}
+  end
+
+  @tag :abort
+  test "abort" do
+    callee_name = TestAbort
+    {:ok, _pid} = Client.start_link(name: callee_name, session: @session, reconnect: false)
+    Client.cast(callee_name, Peer.hello(%Hello{realm: "test", roles: [Callee]}))
+  catch
+    :exit, er -> assert {:normal, _} = er
+  end
+
+  @tag :client
+  test "caller receives error when calling unknown procedure" do
+    caller_name = TestExistCaller
+    Client.start_link(name: caller_name, session: @session, reconnect: false)
+
+    assert %Error{error: "wamp.error.no_registration"} =
+             Client.call(
+               caller_name,
+               %Call{
+                 procedure: "this.should.not.exist",
+                 arg_list: [1],
+                 arg_kw: %{color: "#FFFFFF"}
+               }
+             )
+  end
+
+  @tag :client
+  test "caller receives error when callee returns an error" do
+    callee_name = TestErrorCalleeRespond
+    Client.start_link(name: callee_name, session: @session, reconnect: false)
+    TestCallee.start_link(self(), callee_name, @device)
+    assert_receive {_, _}
+    caller_name = TestErrorCaller
+    Client.start_link(name: caller_name, session: @session, reconnect: false)
+
+    assert %Error{error: "this.is.an.error", arg_list: [1], arg_kw: %{"color" => "#FFFFFF"}} =
+             Client.call(
+               caller_name,
+               %Call{
+                 procedure: "return.error",
+                 arg_list: [1],
+                 arg_kw: %{color: "#FFFFFF"}
+               }
+             )
+  end
+
+  @tag :client
+  test "callee is invoked and responds and caller gets result" do
+    callee_name = TestCalleeRespond
+    Client.start_link(name: callee_name, session: @session, reconnect: false)
+    TestCallee.start_link(self(), callee_name, @device)
+    assert_receive {_, _}
+    caller_name = TestCaller
+    Client.start_link(name: caller_name, session: @session, reconnect: false)
+
+    assert %Result{arg_list: ["ok"], arg_kw: %{"color" => "#FFFFFF"}} =
+             Client.call(
+               caller_name,
+               %Call{
+                 procedure: "com.actuator.#{@device}.light",
+                 arg_list: [1],
+                 arg_kw: %{color: "#FFFFFF"}
+               }
+             )
+
+    assert_receive %Invocation{}
+  end
+
+  @tag :client
+  test "subscriber registration" do
+    name = TestSubscriberRegister
+    Client.start_link(name: name, session: @session, reconnect: false)
+    TestSubscriber.start_link(self(), name, "com.data.temp")
+    assert_receive {:subscribed, id}
+  end
+
+  @tag :client
+  test "subscriber receives events from publisher" do
+    name = TestSubscriberEvents
+    Client.start_link(name: name, session: @session, reconnect: false)
+    TestSubscriber.start_link(self(), name, "com.data.test.temp")
+    assert_receive {:subscribed, id}
+
+    Client.start_link(name: TestPublisher, session: @session, reconnect: false)
+
+    Client.publish(
+      TestPublisher,
+      %Publish{
+        topic: "no.subscribers",
+        arg_list: [12.5, 45.6, 87.5],
+        arg_kw: %{loc: "60645"}
+      }
+    )
+
+    Client.publish(
+      TestPublisher,
+      %Publish{
+        topic: "com.data.test.temp",
+        arg_list: [12.5, 45.6, 87.5],
+        arg_kw: %{loc: "60645"}
+      }
+    )
+
+    assert_receive %Event{details: %{"topic" => "com.data.test.temp"}}, 2000
+    assert_receive %Event{details: %{"topic" => "com.data.test.temp"}}, 2000
+    assert_receive %Event{details: %{"topic" => "com.data.test.temp"}}, 2000
+  end
+end
diff --git a/test/wampex_test.exs b/test/wampex_test.exs
new file mode 100644 (file)
index 0000000..88d5c6c
--- /dev/null
@@ -0,0 +1,231 @@
+defmodule WampexTest do
+  use ExUnit.Case, async: true
+  doctest Wampex
+
+  alias Wampex.Roles.{Broker, Callee, Caller, Dealer, Peer, Publisher, Subscriber}
+  alias Wampex.Serializers.{JSON, MessagePack}
+  alias Broker.{Event, Published, Subscribed, Unsubscribed}
+  alias Callee.{Register, Unregister, Yield}
+  alias Caller.Call
+  alias Dealer.{Invocation, Registered, Result, Unregistered}
+  alias Peer.{Authenticate, Error, Goodbye, Hello}
+  alias Publisher.Publish
+  alias Subscriber.{Subscribe, Unsubscribe}
+  require Logger
+
+  test "Callee.add" do
+    assert %{callee: %{}} = Callee.add(%{})
+  end
+
+  test "Callee.invocation_error" do
+    assert [8, 68, 1234, %{}, "error", [], %{}] =
+             Callee.invocation_error(%Error{request_id: 1234, error: "error"})
+  end
+
+  test "Callee.register" do
+    assert [64, %{}, "test"] = Callee.register(%Register{procedure: "test"})
+  end
+
+  test "Callee.unregister" do
+    assert [66, 123_456] = Callee.unregister(%Unregister{registration_id: 123_456})
+  end
+
+  test "Callee.yield" do
+    assert [70, 1234, %{}, [], %{}] = Callee.yield(%Yield{request_id: 1234})
+    assert [70, 1234, %{}, ["1"], %{}] = Callee.yield(%Yield{request_id: 1234, arg_list: ["1"]})
+
+    assert [70, 1234, %{test: 1}, [2], %{}] =
+             Callee.yield(%Yield{
+               request_id: 1234,
+               arg_list: [2],
+               arg_kw: %{},
+               options: %{test: 1}
+             })
+  end
+
+  test "Caller.add" do
+    assert %{caller: %{}} = Caller.add(%{})
+  end
+
+  @tag :client
+  test "Caller.call" do
+    assert [48, %{}, "test", [], %{}] = Caller.call(%Call{procedure: "test"})
+    assert [48, %{}, "test", [1], %{}] = Caller.call(%Call{procedure: "test", arg_list: [1]})
+
+    assert [48, %{ok: 1}, "test", [1], %{test: 1}] =
+             Caller.call(%Call{
+               procedure: "test",
+               arg_list: [1],
+               arg_kw: %{test: 1},
+               options: %{ok: 1}
+             })
+  end
+
+  test "Peer.add" do
+    assert %{} = Caller.add(%{})
+  end
+
+  test "Peer.hello" do
+    assert [1, "test", %{agent: "WAMPex", roles: %{callee: %{}}}] =
+             Peer.hello(%Hello{realm: "test", roles: [Callee]})
+  end
+
+  test "Peer.authenticate" do
+    assert [5, "a-signa-ture", %{}] ==
+             Peer.authenticate(%Authenticate{signature: "a-signa-ture", extra: %{}})
+  end
+
+  test "Peer.gooodbye" do
+    assert [6, %{}, "test"] = Peer.goodbye(%Goodbye{reason: "test"})
+  end
+
+  test "Publisher.add" do
+    assert %{publisher: %{}} = Publisher.add(%{})
+  end
+
+  @tag :client
+  test "Publisher.publish" do
+    assert [16, %{}, "test", [], %{}] = Publisher.publish(%Publish{topic: "test"})
+    assert [16, %{}, "test", [1], %{}] = Publisher.publish(%Publish{topic: "test", arg_list: [1]})
+
+    assert [16, %{test: 2}, "test", [1], %{test: 1}] =
+             Publisher.publish(%Publish{
+               topic: "test",
+               arg_list: [1],
+               arg_kw: %{test: 1},
+               options: %{test: 2}
+             })
+  end
+
+  test "Subscriber.add" do
+    assert %{subscriber: %{}} = Subscriber.add(%{})
+  end
+
+  test "Subscriber.subscribe" do
+    assert [32, %{test: 1}, "test"] =
+             Subscriber.subscribe(%Subscribe{topic: "test", options: %{test: 1}})
+  end
+
+  test "Subscriber.unsubscribe" do
+    assert [34, 1234] = Subscriber.unsubscribe(%Unsubscribe{subscription_id: 1234})
+  end
+
+  test "Dealer.add" do
+    assert %{dealer: %{}} = Dealer.add(%{})
+  end
+
+  test "Dealer.registered" do
+    assert [65, 123_456, 765_432] =
+             Dealer.registered(%Registered{request_id: 123_456, registration_id: 765_432})
+  end
+
+  test "Dealer.unregistered" do
+    assert [67, 123_456] = Dealer.unregistered(%Unregistered{request_id: 123_456})
+  end
+
+  test "Dealer.call_error" do
+    assert [8, 48, 123_456, %{}, "error", [], %{}] =
+             Dealer.call_error(%Error{request_id: 123_456, details: %{}, error: "error"})
+  end
+
+  test "Dealer.register_error" do
+    assert [8, 64, 123_456, %{}, "error"] =
+             Dealer.register_error(%Error{request_id: 123_456, details: %{}, error: "error"})
+  end
+
+  test "Dealer.result" do
+    assert [50, 1234, %{}, [], %{}] = Dealer.result(%Result{request_id: 1234})
+    assert [50, 1234, %{}, ["1"], %{}] = Dealer.result(%Result{request_id: 1234, arg_list: ["1"]})
+
+    assert [50, 1234, %{test: 1}, [2], %{}] =
+             Dealer.result(%Result{
+               request_id: 1234,
+               arg_list: [2],
+               arg_kw: %{},
+               details: %{test: 1}
+             })
+  end
+
+  test "Dealer.invocation" do
+    assert [68, 1234, 1234, %{}, [], %{}] =
+             Dealer.invocation(%Invocation{request_id: 1234, registration_id: 1234})
+
+    assert [68, 1234, 1234, %{}, ["1"], %{}] =
+             Dealer.invocation(%Invocation{
+               request_id: 1234,
+               registration_id: 1234,
+               arg_list: ["1"]
+             })
+
+    assert [68, 1234, 1234, %{test: 1}, [2], %{test: 2}] =
+             Dealer.invocation(%Invocation{
+               request_id: 1234,
+               registration_id: 1234,
+               arg_list: [2],
+               arg_kw: %{test: 2},
+               details: %{test: 1}
+             })
+  end
+
+  test "Broker.add" do
+    assert %{broker: %{}} = Broker.add(%{})
+  end
+
+  test "Broker.event" do
+    assert [36, 123_456, 765_432, %{}, [], %{}] =
+             Broker.event(%Event{subscription_id: 123_456, publication_id: 765_432})
+
+    assert [36, 123_456, 765_432, %{}, [2], %{}] =
+             Broker.event(%Event{subscription_id: 123_456, publication_id: 765_432, arg_list: [2]})
+
+    assert [36, 123_456, 765_432, %{}, [2], %{test: 1}] =
+             Broker.event(%Event{
+               subscription_id: 123_456,
+               publication_id: 765_432,
+               arg_list: [2],
+               arg_kw: %{test: 1}
+             })
+  end
+
+  test "Broker.subscribed" do
+    assert [33, 123_456, 123_456] =
+             Broker.subscribed(%Subscribed{request_id: 123_456, subscription_id: 123_456})
+  end
+
+  test "Broker.unsubscribed" do
+    assert [35, 123_456] = Broker.unsubscribed(%Unsubscribed{request_id: 123_456})
+  end
+
+  test "Broker.subscribe_error" do
+    assert [8, 32, 123_456, %{}, "error"] =
+             Broker.subscribe_error(%Error{request_id: 123_456, details: %{}, error: "error"})
+  end
+
+  test "Broker.published" do
+    assert [17, 123_456, 654_321] =
+             Broker.published(%Published{request_id: 123_456, publication_id: 654_321})
+  end
+
+  test "MessagePack Serializer" do
+    assert :binary = MessagePack.data_type()
+
+    val = [
+      5,
+      "this is a string/binary",
+      "123456789",
+      [%{"test" => "ok"}, 45, 54, 56, 77],
+      %{"key" => "true", "value" => 34}
+    ]
+
+    s = MessagePack.serialize!(val)
+    assert ^val = MessagePack.deserialize!(s)
+  end
+
+  test "JSON Serializer" do
+    assert :text = JSON.data_type()
+    assert "[5,\"123456789\",{}]" = JSON.serialize!([5, "123456789", %{}])
+    assert {:ok, "[5,\"123456789\",{}]"} = JSON.serialize([5, "123456789", %{}])
+    assert [5, "123456789", %{}] = JSON.deserialize!("[5,\"123456789\",{}]")
+    assert {:ok, [5, "123456789", %{}]} = JSON.deserialize("[5,\"123456789\",{}]")
+  end
+end
diff --git a/test/wampex_test_suite_test.exs b/test/wampex_test_suite_test.exs
new file mode 100644 (file)
index 0000000..7b8f8bf
--- /dev/null
@@ -0,0 +1,8 @@
+defmodule WampexTestSuiteTest do
+  use ExUnit.Case
+  doctest WampexTestSuite
+
+  test "greets the world" do
+    assert WampexTestSuite.hello() == :world
+  end
+end