-
Notifications
You must be signed in to change notification settings - Fork 50
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
Refactoring test suite using StreamData #919
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# | ||
# This file is part of Astarte. | ||
# | ||
# Copyright 2024 SECO Mind Srl | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
|
||
defmodule Astarte.AppEngine.API.V2DeviceTest do | ||
use ExUnit.Case, async: true | ||
use ExUnitProperties | ||
use Astarte.Test.Cases.Device | ||
|
||
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: DatabaseSetup | ||
alias Astarte.Test.Setups.Interface, as: InterfaceSetup | ||
alias Astarte.Test.Generators.String, as: StringGenerator | ||
alias Astarte.Test.Generators.Interface, as: InterfaceGenerator | ||
alias Astarte.Test.Generators.Mapping, as: MappingGenerator | ||
alias Astarte.Test.Generators.Device, as: DeviceGenerator | ||
alias Astarte.Test.Helpers.Database, as: DatabaseHelper | ||
|
||
@moduletag :v2 | ||
@moduletag :device | ||
@moduletag interface_count: 10 | ||
@moduletag device_count: 100 | ||
|
||
describe "device generator testing" do | ||
property "validate device with pre-generated interfaces", %{interfaces: interfaces} do | ||
check all device <- DeviceGenerator.device(interfaces: interfaces) do | ||
:ok | ||
end | ||
end | ||
end | ||
|
||
describe "devices fixtures testing" do | ||
test "validate inserted devices", %{ | ||
cluster: cluster, | ||
keyspace: keyspace, | ||
devices: devices | ||
} do | ||
list = DatabaseHelper.select!(:device, cluster, keyspace, devices) | ||
fields = [:device_id, :encoded_id] | ||
|
||
for field <- fields do | ||
f = fn l -> Enum.map(l, fn d -> d[field] end) end | ||
devices_ids_a = f.(devices) | ||
devices_ids_b = f.(list) | ||
assert [] === devices_ids_a -- devices_ids_b | ||
assert [] === devices_ids_b -- devices_ids_a | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,147 @@ | ||||||
# | ||||||
# This file is part of Astarte. | ||||||
# | ||||||
# Copyright 2024 SECO Mind Srl | ||||||
# | ||||||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
# you may not use this file except in compliance with the License. | ||||||
# You may obtain a copy of the License at | ||||||
# | ||||||
# http://www.apache.org/licenses/LICENSE-2.0 | ||||||
# | ||||||
# Unless required by applicable law or agreed to in writing, software | ||||||
# distributed under the License is distributed on an "AS IS" BASIS, | ||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
# See the License for the specific language governing permissions and | ||||||
# limitations under the License. | ||||||
# | ||||||
|
||||||
defmodule Astarte.AppEngine.API.V2GroupTest do | ||||||
use ExUnit.Case, async: true | ||||||
use ExUnitProperties | ||||||
use Astarte.Test.Cases.Group | ||||||
use Astarte.Test.Cases.Conn | ||||||
|
||||||
alias Astarte.AppEngine.API.Device | ||||||
alias Astarte.AppEngine.API.Device.DevicesList | ||||||
alias Astarte.AppEngine.API.Device.DeviceStatus | ||||||
alias Astarte.Test.Generators.Group, as: GroupGenerator | ||||||
alias Astarte.Test.Generators.Device, as: DeviceGenerator | ||||||
|
||||||
@moduletag :v2 | ||||||
@moduletag :group | ||||||
@moduletag interface_count: 10 | ||||||
@moduletag device_count: 100 | ||||||
@moduletag group_count: 2 | ||||||
|
||||||
describe "create" do | ||||||
@tag :unit | ||||||
property "fails when group name is not valid", %{auth_conn: auth_conn, keyspace: keyspace} do | ||||||
check all {{group_name, error}, devices} <- | ||||||
tuple({ | ||||||
bind(GroupGenerator.name(), fn name -> | ||||||
bind(integer(0..2), fn num -> | ||||||
constant( | ||||||
case num do | ||||||
0 -> {"", "can't be blank"} | ||||||
1 -> {"~" <> name, "is not valid"} | ||||||
2 -> {"@" <> name, "is not valid"} | ||||||
end | ||||||
) | ||||||
end) | ||||||
end), | ||||||
list_of(DeviceGenerator.encoded_id(), min_length: 0, max_length: 1) | ||||||
}) do | ||||||
params = %{ | ||||||
"group_name" => group_name, | ||||||
"devices" => devices | ||||||
} | ||||||
|
||||||
response = post(auth_conn, groups_path(auth_conn, :create, keyspace), data: params) | ||||||
assert [error] === json_response(response, 422)["errors"]["group_name"] | ||||||
end | ||||||
end | ||||||
|
||||||
property "fails when devices list empty", %{auth_conn: auth_conn, keyspace: keyspace} do | ||||||
@tag :unit | ||||||
check all group_name <- GroupGenerator.name() do | ||||||
params = %{ | ||||||
"group_name" => group_name, | ||||||
"devices" => [] | ||||||
} | ||||||
|
||||||
response = post(auth_conn, groups_path(auth_conn, :create, keyspace), data: params) | ||||||
|
||||||
assert ["should have at least 1 item(s)"] === | ||||||
json_response(response, 422)["errors"]["devices"] | ||||||
end | ||||||
end | ||||||
|
||||||
property "fails when device does not exist", %{auth_conn: auth_conn, keyspace: keyspace} do | ||||||
check all group_name <- GroupGenerator.name(), | ||||||
devices <- list_of(DeviceGenerator.encoded_id(), min_length: 1) do | ||||||
params = %{ | ||||||
"group_name" => group_name, | ||||||
"devices" => devices | ||||||
} | ||||||
|
||||||
response = post(auth_conn, groups_path(auth_conn, :create, keyspace), data: params) | ||||||
|
||||||
assert ["must exist (#{Enum.at(devices, 0)} not found)"] === | ||||||
json_response(response, 422)["errors"]["devices"] | ||||||
end | ||||||
end | ||||||
|
||||||
test "fails when the group already exists", %{ | ||||||
auth_conn: auth_conn, | ||||||
cluster: cluster, | ||||||
keyspace: keyspace, | ||||||
interfaces: interfaces, | ||||||
devices: devices, | ||||||
groups: groups | ||||||
} do | ||||||
device_ids = Enum.map(devices, & &1.encoded_id) | ||||||
existing_group_name = Enum.at(groups, 0).name | ||||||
|
||||||
params = %{ | ||||||
"group_name" => existing_group_name, | ||||||
"devices" => device_ids | ||||||
} | ||||||
|
||||||
response = post(auth_conn, groups_path(auth_conn, :create, keyspace), data: params) | ||||||
assert "Group already exists" === json_response(response, 409)["errors"]["detail"] | ||||||
end | ||||||
|
||||||
property "success creates groups with valid parameters", %{ | ||||||
auth_conn: auth_conn, | ||||||
cluster: cluster, | ||||||
keyspace: keyspace, | ||||||
interfaces: interfaces, | ||||||
devices: devices, | ||||||
groups: groups | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make explicit that these are old groups
Suggested change
|
||||||
} do | ||||||
device_ids = Enum.map(devices, & &1.encoded_id) | ||||||
old_group_names = Enum.map(groups, & &1.name) | ||||||
|
||||||
check all group_name <- | ||||||
filter(GroupGenerator.name(), fn name -> name not in old_group_names end) do | ||||||
params = %{ | ||||||
"group_name" => group_name, | ||||||
"devices" => device_ids | ||||||
} | ||||||
|
||||||
response = post(auth_conn, groups_path(auth_conn, :create, keyspace), data: params) | ||||||
assert params === json_response(response, 201)["data"] | ||||||
response = get(auth_conn, groups_path(auth_conn, :show, keyspace, group_name)) | ||||||
assert group_name === json_response(response, 200)["data"]["group_name"] | ||||||
|
||||||
for device <- device_ids do | ||||||
{:ok, %DeviceStatus{groups: groups}} = Device.get_device_status!(keyspace, device) | ||||||
assert group_name in groups | ||||||
# TODO right way | ||||||
# assert [group_name] === groups -- old_group_names | ||||||
Comment on lines
+138
to
+142
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we're just testing that a group is being created, why checking that every device in the group has it in its status? This is probably a (slightly) different property that should be checked in another test |
||||||
end | ||||||
end | ||||||
end | ||||||
end | ||||||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This
use
hides the setup step(s) needed to populate the db, so it is unclear where e.g. devices selected at line 39 do come from. It should be possible to clearly identify what is being created, what operation is being performed and what the expected output would be by just looking at a single test.I find that explicitly implementing
setup_all
andsetup
in the test case helps doing so.The same goes for the other tests on groups and interfaces.