Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document elixir equivalents where erlang is used #150

Merged
merged 2 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,23 @@
----------------------------------------------------------------------------------------------
A Murder of Crows, aka amoc, is a simple framework for running massively parallel tests in a distributed environment.

It can be used as a rebar3 dependency:
It can be used as a `rebar3` dependency:

```erlang
{deps, [
{amoc, "3.0.0-rc1"}
]}.
```

or in `mix`:
```elixir
defp deps() do
[
{:amoc, "~> 3.0.0-rc1"}
]
end
```

[MongooseIM](https://github.com/esl/MongooseIM) is continuously being load tested with Amoc.
All the XMPP scenarios can be found [here](https://github.com/esl/amoc-arsenal-xmpp).

Expand Down
27 changes: 20 additions & 7 deletions guides/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,29 @@ In the same manner you can also define your own entries to configure the scenari

The ``amoc_config:get/1`` and ``amoc_config:get/2`` interfaces can be used to get
parameters required for your scenario, however every scenario must declare (using
`-required_variable(...)` attributes) all the required parameters in advance. For more
information, see the example [scenario module](../integration_test/dummy_scenario.erl)
`-required_variable(...)`/`@required_variable ...` attributes) all the required parameters in advance.
For more information, see the example [scenario module](../integration_test/dummy_scenario.erl)

Scenario configuration also can be set/updated at runtime using an API.

```erlang
-required_variable(#{name => Name, description => Description,
default_value => Value,
update => UpdateFn,
verification => VerificationFn}).
-required_variable(
#{name => Name, description => Description,
default_value => Value,
update => UpdateMfa,
verification => VerificationMfa}
).
```
```elixir
## Note that the attribute needs to be marked as persisted
## for the Elixir compiler to store it in the generated BEAM file.
Module.register_attribute(__MODULE__, :required_variable, persist: true)
@required_variable [
%{:name => name, :description => description,
:default_value => 6,
:update => updateMfa,
:verification => verificationMfa}
]
```
where

Expand Down Expand Up @@ -80,7 +93,7 @@ An action to take when the value of this variable is updated. It is triggered at

## Reasonale

NB: the reason why the `-required_variable(...)` is preferred over the usual behaviour
The reason why the `-required_variable(...)` is preferred over the usual behaviour
callback is because the orchestration tools can easily extract the attributes even
without the compilation, while configuring via a callback, requires a successful
compilation of the module. As an example, a module:
Expand Down
22 changes: 14 additions & 8 deletions guides/distributed-run.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,41 @@ and start scenarios on all known nodes (except master).
```erlang
amoc_dist:do(my_scenario, 100, Settings).
```
```elixir
:amoc_dist.do(:my_scenario, 100, settings).
```

Start `my_scenario` spawning 100 amoc users with IDs from the range [1,100] inclusive.
Start `my_scenario` spawning 100 amoc users with IDs from the range `[1, 100]` inclusive.
In this case sessions are going to be distributed across all nodes except master.

`Settings` is an optional proplist with scenario options that can be extracted using amoc_config module.
The values provided in this list shadow OS and APP environment variables. Note that these settings will be propagated
automatically among all the nodes in the amoc cluster.

The values provided in this list shadow OS and APP environment variables.
Note that these settings will be propagated automatically among all the nodes in the amoc cluster.

```erlang
amoc_dist:add(50).
```
```elixir
:amoc_dist.add(50).
```
Add 50 more users to the currently started scenario.

```erlang
amoc_dist:remove(50, Force).
```

```elixir
:amoc_dist.remove(50, force).
```
Remove 50 sessions.

Where ``Force`` is a boolean of value:

* ``true`` - to kill the user processes using ``supervisor:terminate_child/2`` function
* ``false`` - to send ``exit(User,shutdown)`` signal to the user process (can be ignored by the user)

All the users are ``temporary`` children of the ``simple_one_for_one`` supervisor with the ``shutdown``
key set to ``2000``.
All the users are `temporary` children of the `simple_one_for_one` supervisor with the `shutdown` key set to `2000`.

Also all the user processes trap exit signal.
Also all the user processes trap exits.


## Don't stop scenario on exit
Expand Down
9 changes: 9 additions & 0 deletions guides/local-run.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,25 @@ Start `my_scenario` spawning 10 amoc users with IDs from range (1,10) inclusive.
```erlang
amoc:do(my_scenario, 10, []).
```
```elixir
:amoc.do(:my_scenario, 10, []).
```

Add 10 more user sessions.
```erlang
amoc:add(10).
```
```elixir
:amoc.add(10).
```

Remove 10 users.
```erlang
amoc:remove(10, true).
```
```elixir
:amoc.remove(10, true).
```

#### Many independent Amoc nodes

Expand Down
45 changes: 42 additions & 3 deletions guides/scenario.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
## Developing a scenario

A scenario specification is an [Erlang](https://www.erlang.org/) module that implements
the `amoc_scenario` behaviour.
A scenario specification is an [Erlang](https://www.erlang.org/) or [Elixir](https://elixir-lang.org/) module that implements the `amoc_scenario` behaviour.
It has to export two callback functions:
- `init/0` - called only once per test run on every node, at the very beginning.
It can be used for setting up initial (global) state: metrics, database connections, etc.
Expand Down Expand Up @@ -34,8 +33,28 @@ start(Id) ->
%% send some messages again
ok.
```
or, using the `start/2` function:
```elixir
defmodule LoadTest do
@behaviour :amoc_scenario

def init do
## initialize some metrics
settings = get_settings()
:ok
end

def start(id) do
## connect user
## fetch user's history
## send some messages
## wait a little bit
## send some messages again
ok.
end

end
```
or, using the `start/2` function:
```erlang
-module(my_scenario).

Expand All @@ -55,7 +74,27 @@ start(Id, Settings) ->
%% send some messages again
ok.
```
```elixir
defmodule LoadTest do
@behaviour :amoc_scenario

def init do
## initialize some metrics
settings = get_settings()
{:ok, Settings}
end

def start(id, settings) do
## connect user using Settings
## fetch user's history
## send some messages
## wait a little bit
## send some messages again
ok.
end

end
```

For developing XMPP scenarios, we recommend the
[esl/escalus](https://github.com/esl/escalus) library.
Expand Down
2 changes: 1 addition & 1 deletion guides/throttle.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ user_loop(Id) ->

```
Here a system should be under a continuous load of 100 messages per minute.
Note that if we used something like `amoc_throttle:run(messages_rate, fun() -> send_message(Id) end)` instead of `send_and_wait/2` the system would be flooded with requests.
Note that if we used something like `amoc_throttle:run(messages_rate, fun() -> send_message(Id) end)` instead of `amoc_throttle:send_and_wait/2` the system would be flooded with requests.

A test may of course be much more complicated.
For example it can have the load changing in time.
Expand Down