diff --git a/apps/astarte_appengine_api/mix.exs b/apps/astarte_appengine_api/mix.exs index d88c59ecf..00b29f599 100644 --- a/apps/astarte_appengine_api/mix.exs +++ b/apps/astarte_appengine_api/mix.exs @@ -48,7 +48,7 @@ defmodule Astarte.AppEngine.API.Mixfile do end # Specifies which paths to compile per environment. - defp elixirc_paths(:test), do: ["test/support", "lib"] + defp elixirc_paths(:test), do: ["test/support", "test/support_v2", "lib"] defp elixirc_paths(_), do: ["lib"] defp dialyzer_cache_directory(:ci) do diff --git a/apps/astarte_appengine_api/test/astarte_appengine_api/example_v2_test.exs b/apps/astarte_appengine_api/test/astarte_appengine_api/example_v2_test.exs new file mode 100644 index 000000000..1edf355ec --- /dev/null +++ b/apps/astarte_appengine_api/test/astarte_appengine_api/example_v2_test.exs @@ -0,0 +1,33 @@ +defmodule Astarte.AppEngine.API.ExampleTest do + use ExUnit.Case, async: true + use ExUnitProperties + use Astarte.Test.Cases.Database + use Astarte.Test.Cases.Conn + + alias Astarte.Test.Setups.Database, as: DatabaseSetup + alias Astarte.Test.Setups.Conn, as: ConnSetup + + # @moduletag :v2 + describe "db smoke" do + # setup single test fixtures + setup [ + {ConnSetup, :request_path} + ] + + property "realm exists", %{conn: conn, cluster: cluster, realm: realm} do + with {:ok, prepared} <- Xandra.Cluster.prepare(cluster, "DESCRIBE TABLES;"), + {:ok, %Xandra.Page{} = page} <- Xandra.Cluster.execute(cluster, prepared), + do: Enum.to_list(page) |> IO.inspect() + + :ok + # check all {first, second, third} <- NumbersGenerator.random_numbers(max_value) do + # assert true + # end + end + + test "no token returns 401", %{conn: conn, request_path: request_path} do + conn = get(conn, request_path) + assert json_response(conn, 401)["errors"]["detail"] == "Unauthorized" + end + end +end diff --git a/apps/astarte_appengine_api/test/astarte_appengine_api/stats/stats_v2_test.exs b/apps/astarte_appengine_api/test/astarte_appengine_api/stats/stats_v2_test.exs new file mode 100644 index 000000000..abc2dd0e2 --- /dev/null +++ b/apps/astarte_appengine_api/test/astarte_appengine_api/stats/stats_v2_test.exs @@ -0,0 +1,84 @@ +defmodule Astarte.AppEngine.API.StatsV2Test do + use ExUnit.Case, async: true + use ExUnitProperties + use Astarte.Test.Cases.Database + alias Ecto.Changeset + alias StreamData + alias Astarte.Core.Mapping + alias Astarte.Core.Interface + alias Astarte.AppEngine.API.Stats + alias Astarte.AppEngine.API.Stats.DevicesStats + alias Astarte.Test.Setups.Database, as: DatabaseSetups + alias Astarte.Test.Generators.Strings, as: StringGenerator + alias Astarte.Test.Generators.Interfaces, as: InterfaceGenerator + alias Astarte.Test.Generators.Mappings, as: MappingGenerator + + describe "validation generators" do + # setup [{DatabaseSetups, :setup_devices}] + + @tag :v2 + property "validate interface" do + check all interface <- InterfaceGenerator.interface() do + %Changeset{valid?: valid, errors: errors} = Interface.changeset(interface) + assert valid + end + end + end + + describe "get_devices_stats" do + setup [{DatabaseSetups, :setup_devices}] + + # @tag :v2 + property "return correct response on get_devices_stats", %{ + realm: realm, + devices: devices + } do + check all {realm_name, valid} <- + frequency([ + {1, tuple({realm, true})}, + {1, tuple({StringGenerator.realm_name(), constant(false)})} + ]) do + if valid do + assert {:ok, %DevicesStats{} = stats} = Stats.get_devices_stats(realm_name) + # assert stats.total_devices == DatabaseTestHelper.devices_count() + # assert stats.connected_devices == 0 + else + assert {:error, _reason} = Stats.get_devices_stats(realm_name) + end + end + end + + # test "returns an error for unexisting realm" do + # assert {:error, _reason} = Stats.get_devices_stats("unexisting") + # end + end + + # setup do + # DatabaseTestHelper.seed_data() + # end + + # describe "get_devices_stats" do + # test "returns an error for unexisting realm" do + # assert {:error, _reason} = Stats.get_devices_stats("unexisting") + # end + + # test "returns the correct stats for the autotestrealm" do + # assert {:ok, %DevicesStats{} = stats} = Stats.get_devices_stats("autotestrealm") + + # assert stats.total_devices == DatabaseTestHelper.devices_count() + # assert stats.connected_devices == 0 + # end + + # test "gets updated connected count after device connection" do + # assert {:ok, %DevicesStats{connected_devices: 0}} = Stats.get_devices_stats("autotestrealm") + + # DatabaseTestHelper.fake_connect_device("f0VMRgIBAQAAAAAAAAAAAA", true) + + # assert {:ok, %DevicesStats{connected_devices: 1}} = Stats.get_devices_stats("autotestrealm") + + # DatabaseTestHelper.fake_connect_device("f0VMRgIBAQAAAAAAAAAAAA", false) + + # assert {:ok, %DevicesStats{connected_devices: 0}} = Stats.get_devices_stats("autotestrealm") + # end + # end +end diff --git a/apps/astarte_appengine_api/test/support_v2/cases/conn.ex b/apps/astarte_appengine_api/test/support_v2/cases/conn.ex new file mode 100644 index 000000000..4ef85dbfc --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/cases/conn.ex @@ -0,0 +1,20 @@ +defmodule Astarte.Test.Cases.Conn do + use ExUnit.CaseTemplate + + using do + quote do + import Plug.Conn + import Phoenix.ConnTest + import Astarte.AppEngine.APIWeb.Router.Helpers + + # The default endpoint for testing + @endpoint Astarte.AppEngine.APIWeb.Endpoint + end + end + + alias Astarte.Test.Setups.Conn, as: ConnSetup + + setup_all [ + {ConnSetup, :create_conn} + ] +end diff --git a/apps/astarte_appengine_api/test/support_v2/cases/database.ex b/apps/astarte_appengine_api/test/support_v2/cases/database.ex new file mode 100644 index 000000000..5b0f47634 --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/cases/database.ex @@ -0,0 +1,15 @@ +defmodule Astarte.Test.Cases.Database do + use ExUnit.CaseTemplate + + using do + quote do + end + end + + alias Astarte.Test.Setups.Database, as: DatabaseSetup + + setup_all [ + {DatabaseSetup, :connect_db}, + {DatabaseSetup, :setup_db} + ] +end diff --git a/apps/astarte_appengine_api/test/support_v2/common.ex b/apps/astarte_appengine_api/test/support_v2/common.ex new file mode 100644 index 000000000..e69de29bb diff --git a/apps/astarte_appengine_api/test/support_v2/generators/entites.ex b/apps/astarte_appengine_api/test/support_v2/generators/entites.ex new file mode 100644 index 000000000..f3426f010 --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/generators/entites.ex @@ -0,0 +1,59 @@ +defmodule Astarte.Test.Generators.Entities do + use ExUnitProperties + + def domain() do + gen all first <- string([?a..?z], length: 3), + second <- string([?a..?z, ?A..?Z], min_length: 1, max_length: 10), + third <- string([?a..?z, ?A..?Z], min_length: 1, max_length: 10) do + first <> "." <> second <> "." <> third + end + end + + def interface() do + gen all domain <- domain(), + enabled <- boolean() do + {domain, enabled} + end + end + + def interface_value() do + gen all interface <- interface(), + value <- integer(1..100_100) do + {interface, value} + end + end + + def interfaces() do + gen all interface_value <- list_of(interface_value()), + num <- integer(0..20) do + Enum.take(interface_value, num) |> Map.new() + end + end + + def options do + optional_map(%{ + display_name: string(:alphanumeric), + serial: string(?0..?9, min_length: 1, max_length: 10) + }) + end + + def attributes do + fixed_map(%{ + attribute_key: string(:alphanumeric) + }) + end + + def device() do + gen all id <- string(:alphanumeric, length: 22), + value <- integer(0..8_000_000), + interfaces <- one_of([nil, interfaces()]), + options <- one_of([nil, options()]), + attributes <- attributes() do + {id, value, interfaces, options, attributes} + end + end + + def devices() do + list_of(device()) + end +end diff --git a/apps/astarte_appengine_api/test/support_v2/generators/interfaces.ex b/apps/astarte_appengine_api/test/support_v2/generators/interfaces.ex new file mode 100644 index 000000000..edbd7f675 --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/generators/interfaces.ex @@ -0,0 +1,124 @@ +defmodule Astarte.Test.Generators.Interfaces do + use ExUnitProperties + + alias Astarte.Core.Interface + alias Astarte.Test.Generators.Strings, as: StringsGenerator + alias Astarte.Test.Generators.Mappings, as: MappingsGenerator + + defp name() do + string(:alphanumeric, min_length: 1, max_length: 16) + |> list_of( + min_length: 2, + max_length: 5 + ) + |> filter(fn [<> | _] -> + first < 48 or first > 57 + end) + |> map(&Enum.join(&1, ".")) + end + + defp versions() do + gen all major_version <- integer(0..9), + minor_version <- integer(0..255) do + case {major_version, minor_version} do + {0, 0} -> {0, 1} + valid -> valid + end + end + end + + defp type() do + [ + :datastream, + :properties + ] + |> Enum.map(&constant/1) + |> one_of() + end + + defp ownership() do + [ + :device, + :server + ] + |> Enum.map(&constant/1) + |> one_of() + end + + defp mappings(config) do + uniq_list_of(MappingsGenerator.mapping(config), min_length: 1, max_length: 1000) + end + + defp aggregation(%{type: :properties}) do + constant(:individual) + end + + defp aggregation(_) do + [ + :individual, + :object + ] + |> Enum.map(&constant/1) + |> one_of() + end + + defp description() do + string(:ascii, min_length: 1, max_length: 1000) + end + + defp doc() do + string(:ascii, min_length: 1, max_length: 100_000) + end + + defp required_fields() do + gen all name <- name(), + {major_version, minor_version} <- versions(), + type <- type(), + aggregation <- aggregation(%{type: type}), + ownership <- ownership(), + prefix <- StringsGenerator.endpoint_prefix(), + retention <- MappingsGenerator.retention(), + reliability <- MappingsGenerator.reliability(), + expiry <- MappingsGenerator.expiry(), + allow_unset <- MappingsGenerator.allow_unset(), + explicit_timestamp <- MappingsGenerator.explicit_timestamp(), + mappings <- + mappings(%{ + aggregation: aggregation, + prefix: prefix, + retention: retention, + reliability: reliability, + expiry: expiry, + allow_unset: allow_unset, + explicit_timestamp: explicit_timestamp + }) do + %{ + name: name, + interface_name: name, + major_version: major_version, + minor_version: minor_version, + version_major: major_version, + version_minor: minor_version, + type: type, + interface_type: type, + ownership: ownership, + aggregation: aggregation, + mappings: mappings + } + end + end + + defp optional_fields() do + optional_map(%{ + description: description(), + doc: doc() + }) + end + + def interface() do + gen all required <- required_fields(), + optional <- optional_fields() do + struct(Interface, Map.merge(required, optional)) + end + end +end diff --git a/apps/astarte_appengine_api/test/support_v2/generators/mappings.ex b/apps/astarte_appengine_api/test/support_v2/generators/mappings.ex new file mode 100644 index 000000000..8f7c1f5d7 --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/generators/mappings.ex @@ -0,0 +1,131 @@ +defmodule Astarte.Test.Generators.Mappings do + use ExUnitProperties + + alias Astarte.Core.Mapping + + defp endpoint(%{aggregation: aggregation, prefix: prefix}) do + # TODO: thinking about it + generator = + case aggregation do + :individual -> repeatedly(fn -> "/individual_#{System.unique_integer([:positive])}" end) + :object -> repeatedly(fn -> "/object_#{System.unique_integer([:positive])}" end) + end + + gen all postfix <- generator do + prefix <> postfix + end + end + + defp type() do + [ + :double, + :integer, + :boolean, + :longinteger, + :string, + :binaryblob, + :datetime, + :doublearray, + :integerarray, + :booleanarray, + :longintegerarray, + :stringarray, + :binaryblobarray, + :datetimearray + ] + |> Enum.map(&constant/1) + |> one_of() + end + + def reliability() do + [ + :unreliable, + :guaranteed, + :unique + ] + |> Enum.map(&constant/1) + |> one_of() + end + + def explicit_timestamp() do + boolean() + end + + def retention() do + [ + :discard, + :volatile, + :stored + ] + |> Enum.map(&constant/1) + |> one_of() + end + + def expiry() do + one_of([ + constant(0), + integer(1..10_000) + ]) + end + + def database_retention_policy() do + [ + :no_ttl, + :use_ttl + ] + |> Enum.map(&constant/1) + |> one_of() + end + + def database_retention_ttl() do + integer(0..10_1000) + end + + def allow_unset() do + boolean() + end + + defp description() do + string(:ascii, min_length: 1, max_length: 1000) + end + + defp doc() do + string(:ascii, min_length: 1, max_length: 100_000) + end + + defp required_fields(%{ + aggregation: aggregation, + prefix: prefix, + retention: retention, + reliability: reliability, + explicit_timestamp: explicit_timestamp, + allow_unset: allow_unset, + expiry: expiry + }) do + fixed_map(%{ + endpoint: endpoint(%{aggregation: aggregation, prefix: prefix}), + type: type(), + retention: constant(retention), + reliability: constant(reliability), + explicit_timestamp: constant(explicit_timestamp), + allow_unset: constant(allow_unset), + expiry: constant(expiry) + }) + end + + defp optional_fields(_config) do + optional_map(%{ + database_retention_policy: database_retention_policy(), + database_retention_ttl: database_retention_ttl(), + description: description(), + doc: doc() + }) + end + + def mapping(config) do + gen all required <- required_fields(config), + optional <- optional_fields(config) do + struct(Mapping, Map.merge(required, optional)) + end + end +end diff --git a/apps/astarte_appengine_api/test/support_v2/generators/numbers.ex b/apps/astarte_appengine_api/test/support_v2/generators/numbers.ex new file mode 100644 index 000000000..4f2fb1071 --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/generators/numbers.ex @@ -0,0 +1,11 @@ +defmodule Astarte.Test.Generators.Numbers do + use ExUnitProperties + + def random_numbers(max) do + gen all first <- StreamData.integer(0..max), + second <- StreamData.integer(0..max), + third <- StreamData.integer(0..max) do + {first, second, third} + end + end +end diff --git a/apps/astarte_appengine_api/test/support_v2/generators/strings.ex b/apps/astarte_appengine_api/test/support_v2/generators/strings.ex new file mode 100644 index 000000000..655e70205 --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/generators/strings.ex @@ -0,0 +1,37 @@ +defmodule Astarte.Test.Generators.Strings do + use ExUnitProperties + alias StreamData + + def random_string(max) do + string(:alphanumeric, length: max) + end + + def realm_name() do + repeatedly(fn -> "realm_#{System.unique_integer([:positive, :monotonic])}" end) + end + + def endpoint_subpath() do + string([?a..?z, ?_], min_length: 1, max_length: 5) + end + + def endpoint_parametric_subpath() do + gen all subpath <- endpoint_subpath() do + "%{" <> subpath <> "}" + end + end + + def endpoint_prefix() do + gen all prefix <- + frequency([ + {1, endpoint_subpath()}, + {1, endpoint_parametric_subpath()} + ]) + |> list_of( + min_length: 1, + max_length: 5 + ) + |> map(&Enum.join(&1, "/")) do + "/" <> prefix + end + end +end diff --git a/apps/astarte_appengine_api/test/support_v2/helpers/database.ex b/apps/astarte_appengine_api/test/support_v2/helpers/database.ex new file mode 100644 index 000000000..900d17216 --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/helpers/database.ex @@ -0,0 +1,209 @@ +defmodule Astarte.Test.Helpers.Database do + @create_realm """ + CREATE KEYSPACE :realm + WITH + replication = {'class': 'SimpleStrategy', 'replication_factor': '1'} AND + durable_writes = true; + """ + + @drop_realm """ + DROP KEYSPACE :realm; + """ + + @create_kv_store """ + CREATE TABLE :realm.kv_store ( + group varchar, + key varchar, + value blob, + + PRIMARY KEY ((group), key) + ); + """ + + @create_names_table """ + CREATE TABLE :realm.names ( + object_name varchar, + object_type int, + object_uuid uuid, + + PRIMARY KEY ((object_name), object_type) + ); + """ + + @create_devices_table """ + CREATE TABLE :realm.devices ( + device_id uuid, + aliases map, + introspection map, + introspection_minor map, + protocol_revision int, + first_registration timestamp, + credentials_secret ascii, + inhibit_credentials_request boolean, + cert_serial ascii, + cert_aki ascii, + first_credentials_request timestamp, + last_connection timestamp, + last_disconnection timestamp, + connected boolean, + pending_empty_cache boolean, + total_received_msgs bigint, + total_received_bytes bigint, + last_credentials_request_ip inet, + last_seen_ip inet, + + PRIMARY KEY (device_id) + ); + """ + + @create_interfaces_table """ + CREATE TABLE :realm.interfaces ( + name ascii, + major_version int, + minor_version int, + interface_id uuid, + storage_type int, + storage ascii, + type int, + ownership int, + aggregation int, + automaton_transitions blob, + automaton_accepting_states blob, + description varchar, + doc varchar, + + PRIMARY KEY (name, major_version) + ); + """ + + @create_endpoints_table """ + CREATE TABLE :realm.endpoints ( + interface_id uuid, + endpoint_id uuid, + interface_name ascii, + interface_major_version int, + interface_minor_version int, + interface_type int, + endpoint ascii, + value_type int, + reliability int, + retention int, + database_retention_policy int, + database_retention_ttl int, + expiry int, + allow_unset boolean, + explicit_timestamp boolean, + description varchar, + doc varchar, + + PRIMARY KEY ((interface_id), endpoint_id) + ); + """ + @create_individual_properties_table """ + CREATE TABLE :realm.individual_properties ( + device_id uuid, + interface_id uuid, + endpoint_id uuid, + path varchar, + reception_timestamp timestamp, + reception_timestamp_submillis smallint, + + double_value double, + integer_value int, + boolean_value boolean, + longinteger_value bigint, + string_value varchar, + binaryblob_value blob, + datetime_value timestamp, + doublearray_value list, + integerarray_value list, + booleanarray_value list, + longintegerarray_value list, + stringarray_value list, + binaryblobarray_value list, + datetimearray_value list, + + PRIMARY KEY((device_id, interface_id), endpoint_id, path) + ); + """ + + @create_individual_datastreams_table """ + CREATE TABLE IF NOT EXISTS :realm.individual_datastreams ( + device_id uuid, + interface_id uuid, + endpoint_id uuid, + path varchar, + value_timestamp timestamp, + reception_timestamp timestamp, + reception_timestamp_submillis smallint, + + double_value double, + integer_value int, + boolean_value boolean, + longinteger_value bigint, + string_value varchar, + binaryblob_value blob, + datetime_value timestamp, + doublearray_value list, + integerarray_value list, + booleanarray_value list, + longintegerarray_value list, + stringarray_value list, + binaryblobarray_value list, + datetimearray_value list, + + PRIMARY KEY((device_id, interface_id, endpoint_id, path), value_timestamp, reception_timestamp, reception_timestamp_submillis) + ); + """ + + @create_test_object_table """ + CREATE TABLE :realm.com_example_testobject_v1 ( + device_id uuid, + path varchar, + reception_timestamp timestamp, + v_string varchar, + v_value double, + PRIMARY KEY ((device_id, path), reception_timestamp) + ); + """ + + def create_test_keyspace(realm, cluster) do + case Xandra.Cluster.execute(cluster, String.replace(@create_realm, ":realm", realm)) do + {:ok, _} -> + Xandra.Cluster.execute!(cluster, String.replace(@create_devices_table, ":realm", realm)) + Xandra.Cluster.execute!(cluster, String.replace(@create_names_table, ":realm", realm)) + Xandra.Cluster.execute!(cluster, String.replace(@create_kv_store, ":realm", realm)) + Xandra.Cluster.execute!(cluster, String.replace(@create_endpoints_table, ":realm", realm)) + + Xandra.Cluster.execute!( + cluster, + String.replace(@create_individual_properties_table, ":realm", realm) + ) + + Xandra.Cluster.execute!( + cluster, + String.replace(@create_individual_datastreams_table, ":realm", realm) + ) + + Xandra.Cluster.execute!( + cluster, + String.replace(@create_test_object_table, ":realm", realm) + ) + + Xandra.Cluster.execute!( + cluster, + String.replace(@create_interfaces_table, ":realm", realm) + ) + + :ok + + {:error, msg} -> + {:error, msg} + end + end + + def destroy_test_keyspace(realm, cluster) do + Xandra.Cluster.execute(cluster, String.replace(@drop_realm, ":realm", realm)) + :ok + end +end diff --git a/apps/astarte_appengine_api/test/support_v2/setups/conn.ex b/apps/astarte_appengine_api/test/support_v2/setups/conn.ex new file mode 100644 index 000000000..72c62b027 --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/setups/conn.ex @@ -0,0 +1,18 @@ +defmodule Astarte.Test.Setups.Conn do + alias Phoenix.ConnTest + + def create_conn(_context) do + {:ok, conn: ConnTest.build_conn()} + end + + # TODO generator + @device_id "f0VMRgIBAQAAAAAAAAAAAA" + # TODO generator + @interface "com.test.LCDMonitor" + # @escaped_interface "com\\.test\\.LCDMonitor" + # TODO generator + @path "/time/to" + def request_path(%{realm: realm}) do + {:ok, request_path: "/v1/#{realm}/devices/#{@device_id}/interfaces/#{@interface}#{@path}"} + end +end diff --git a/apps/astarte_appengine_api/test/support_v2/setups/database.ex b/apps/astarte_appengine_api/test/support_v2/setups/database.ex new file mode 100644 index 000000000..f1e962e39 --- /dev/null +++ b/apps/astarte_appengine_api/test/support_v2/setups/database.ex @@ -0,0 +1,58 @@ +defmodule Astarte.Test.Setups.Database do + use ExUnit.Case, async: false + alias Astarte.Test.Helpers.Database, as: DatabaseHelper + alias Astarte.Test.Generators.Strings, as: StringsGenerator + alias Astarte.Test.Generators.Entities, as: EntitiesGenerator + + # TODO + # doctest Astarte.Test.Fixture.Database + + def connect_db(_context) do + {:ok, cluster: :xandra} + end + + def setup_db(%{cluster: cluster}) do + realm = StringsGenerator.realm_name() |> Enum.at(0) + + on_exit(fn -> + :ok = DatabaseHelper.destroy_test_keyspace(realm, cluster) + end) + + :ok = DatabaseHelper.create_test_keyspace(realm, cluster) + {:ok, realm: realm} + end + + # @devices_list [ + # {"f0VMRgIBAQAAAAAAAAAAAA", 4_500_000, + # %{ + # {"com.example.TestObject", 1} => 9300, + # {"com.example.ServerOwnedTestObject", 1} => 100, + # {"com.example.PixelsConfiguration", 1} => 4230, + # {"com.test.LCDMonitor", 1} => 10, + # {"com.test.LCDMonitor", 0} => 42 + # }, + # %{ + # {"com.example.TestObject", 1} => 2_000_000, + # {"com.example.ServerOwnedTestObject", 1} => 30_000, + # {"com.example.PixelsConfiguration", 1} => 2_010_000, + # {"com.test.LCDMonitor", 1} => 3000, + # {"com.test.LCDMonitor", 0} => 9000 + # }, %{"display_name" => "device_a"}, %{"attribute_key" => "device_a_attribute"}}, + # {"olFkumNuZ_J0f_d6-8XCDg", 10, nil, nil, nil, nil}, + # {"4UQbIokuRufdtbVZt9AsLg", 22, %{{"com.test.LCDMonitor", 1} => 4}, + # %{{"com.test.LCDMonitor", 1} => 16}, %{"display_name" => "device_b", "serial" => "1234"}, + # %{"attribute_key" => "device_b_attribute"}}, + # {"aWag-VlVKC--1S-vfzZ9uQ", 0, %{}, %{}, %{"display_name" => "device_c"}, + # %{"attribute_key" => "device_c_attribute"}}, + # {"DKxaeZ9LzUZLz7WPTTAEAA", 300, %{{"com.test.SimpleStreamTest", 1} => 9}, + # %{{"com.test.SimpleStreamTest", 1} => 250}, %{"display_name" => "device_d"}, + # %{"attribute_key" => "device_d_attribute"}}, + # {"ehNpbPVtQ2CcdJdJK3QUlA", 300, %{{"com.test.SimpleStreamTest", 1} => 9}, + # %{{"com.test.SimpleStreamTest", 1} => 250}, %{"display_name" => "device_e"}, + # %{"attribute_key" => "device_e_attribute"}} + # ] + def setup_devices(%{cluster: cluster}) do + temp = EntitiesGenerator.devices() |> IO.inspect() + :ok + end +end