From edab084813d176c42dd82ab09135a38aa25b0a38 Mon Sep 17 00:00:00 2001 From: Wannes Gennar Date: Wed, 28 Feb 2024 20:27:34 +0100 Subject: [PATCH] add OpenApi spec and some unit tests --- .formatter.exs | 2 +- config/dev.exs | 3 + config/test.exs | 4 + lib/helldivers_2_web.ex | 8 ++ lib/helldivers_2_web/api_spec.ex | 22 +++++ .../controllers/api/planets_controller.ex | 37 ++++++- .../controllers/api/war_season_controller.ex | 33 ++++++- lib/helldivers_2_web/plugs/rate_limit.ex | 6 +- lib/helldivers_2_web/plugs/war_season.ex | 33 +++++++ lib/helldivers_2_web/router.ex | 14 +++ .../schemas/home_world_schema.ex | 24 +++++ .../schemas/not_found_schema.ex | 16 +++ lib/helldivers_2_web/schemas/planet_schema.ex | 54 ++++++++++ .../schemas/too_many_requests_schema.ex | 14 +++ .../schemas/war_info_schema.ex | 47 +++++++++ mix.exs | 3 +- mix.lock | 1 + .../api/planets_controller_test.exs | 99 +++++++++++++++++++ .../controllers/page_controller_test.exs | 8 +- 19 files changed, 413 insertions(+), 15 deletions(-) create mode 100644 lib/helldivers_2_web/api_spec.ex create mode 100644 lib/helldivers_2_web/plugs/war_season.ex create mode 100644 lib/helldivers_2_web/schemas/home_world_schema.ex create mode 100644 lib/helldivers_2_web/schemas/not_found_schema.ex create mode 100644 lib/helldivers_2_web/schemas/planet_schema.ex create mode 100644 lib/helldivers_2_web/schemas/too_many_requests_schema.ex create mode 100644 lib/helldivers_2_web/schemas/war_info_schema.ex create mode 100644 test/helldivers_2_web/controllers/api/planets_controller_test.exs diff --git a/.formatter.exs b/.formatter.exs index e945e12..0871027 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,5 +1,5 @@ [ - import_deps: [:phoenix], + import_deps: [:phoenix, :open_api_spex], plugins: [Phoenix.LiveView.HTMLFormatter], inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}"] ] diff --git a/config/dev.exs b/config/dev.exs index d8b0209..e7a1c17 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -66,3 +66,6 @@ config :phoenix, :plug_init_mode, :runtime # Include HEEx debug annotations as HTML comments in rendered markup config :phoenix_live_view, :debug_heex_annotations, true + +# Ensures the OpenApi spec is refreshed during development and not cached +config :open_api_spex, :cache_adapter, OpenApiSpex.Plug.NoneCache diff --git a/config/test.exs b/config/test.exs index 1e2bb23..1726bfb 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,5 +1,9 @@ import Config +# We don't start up any Helldiver seasons during tests to avoid hitting the API +config :helldivers_2, +war_seasons: [] + # We don't run a server during test. If one is required, # you can enable the server option below. config :helldivers_2, Helldivers2Web.Endpoint, diff --git a/lib/helldivers_2_web.ex b/lib/helldivers_2_web.ex index 0b90223..bd9ca1b 100644 --- a/lib/helldivers_2_web.ex +++ b/lib/helldivers_2_web.ex @@ -28,6 +28,7 @@ defmodule Helldivers2Web do import Phoenix.Controller import Phoenix.LiveView.Router import Helldivers2Web.Plugs.RateLimit, only: [rate_limit: 2] + import Helldivers2Web.Plugs.WarSeason, only: [check_war_id: 2] end end @@ -45,6 +46,13 @@ defmodule Helldivers2Web do import Plug.Conn + # OpenApi helpers + alias OpenApiSpex.Schema + alias OpenApiSpex.JsonErrorResponse + alias OpenApiSpex.Plug.CastAndValidate + alias Helldivers2Web.Schemas.NotFoundSchema + alias Helldivers2Web.Schemas.TooManyRequestsSchema + unquote(verified_routes()) end end diff --git a/lib/helldivers_2_web/api_spec.ex b/lib/helldivers_2_web/api_spec.ex new file mode 100644 index 0000000..79a3100 --- /dev/null +++ b/lib/helldivers_2_web/api_spec.ex @@ -0,0 +1,22 @@ +defmodule Helldivers2Web.ApiSpec do + alias OpenApiSpex.{Info, OpenApi, Paths, Server} + alias Helldivers2Web.{Endpoint, Router} + @behaviour OpenApi + + @impl OpenApi + def spec do + %OpenApi{ + servers: [ + # Populate the Server info from a phoenix endpoint + Server.from_endpoint(Endpoint) + ], + info: %Info{ + title: "Helldivers 2", + version: "0.0.1" + }, + # Populate the paths from a phoenix router + paths: Paths.from_router(Router) + } + |> OpenApiSpex.resolve_schema_modules() # Discover request/response schemas from path specs + end +end diff --git a/lib/helldivers_2_web/controllers/api/planets_controller.ex b/lib/helldivers_2_web/controllers/api/planets_controller.ex index 243d811..4e390f0 100644 --- a/lib/helldivers_2_web/controllers/api/planets_controller.ex +++ b/lib/helldivers_2_web/controllers/api/planets_controller.ex @@ -1,19 +1,48 @@ defmodule Helldivers2Web.Api.PlanetsController do use Helldivers2Web, :controller + use OpenApiSpex.ControllerSpecs + plug CastAndValidate, json_render_error_v2: true action_fallback Helldivers2Web.FallbackController alias Helldivers2.WarSeason + alias Helldivers2Web.Schemas.PlanetSchema - def index(conn, %{"war_id" => war_id}) do + operation :index, + summary: "Get an overview of all planets", + parameters: [ + war_id: [in: :path, description: "The war ID", type: :integer, example: 801] + ], + responses: [ + ok: PlanetSchema.responses(), + not_found: NotFoundSchema.response(), + too_many_requests: TooManyRequestsSchema.response() + ] + def index(conn, %{war_id: war_id}) do with {:ok, planets} <- WarSeason.get_planets(war_id) do render(conn, :index, planets: planets) end end - def show(conn, %{"war_id" => war_id, "planet_index" => planet_index}) do - with {planet_index, _} <- Integer.parse(planet_index), - {:ok, planets} <- WarSeason.get_planet(war_id, planet_index) do + operation :show, + summary: "Get information on a specific planet", + parameters: [ + war_id: [in: :path, description: "The war ID", type: :integer, example: 801], + planet_index: [ + in: :path, + description: "The index of the planet", + type: :integer, + example: 0 + ] + ], + responses: [ + ok: PlanetSchema.response(), + not_found: NotFoundSchema.response(), + too_many_requests: TooManyRequestsSchema.response(), + unprocessable_entity: JsonErrorResponse.response() + ] + def show(conn, %{war_id: war_id, planet_index: planet_index}) do + with {:ok, planets} <- WarSeason.get_planet(war_id, planet_index) do render(conn, :show, planet: planets) end end diff --git a/lib/helldivers_2_web/controllers/api/war_season_controller.ex b/lib/helldivers_2_web/controllers/api/war_season_controller.ex index d9c9edc..964487c 100644 --- a/lib/helldivers_2_web/controllers/api/war_season_controller.ex +++ b/lib/helldivers_2_web/controllers/api/war_season_controller.ex @@ -1,14 +1,43 @@ defmodule Helldivers2Web.Api.WarSeasonController do use Helldivers2Web, :controller - alias Helldivers2.WarSeason + use OpenApiSpex.ControllerSpecs + plug CastAndValidate, json_render_error_v2: true action_fallback Helldivers2Web.FallbackController + alias Helldivers2.WarSeason + alias Helldivers2Web.Schemas.WarInfoSchema + + operation :index, + summary: "Get an overview of all available war seasons", + responses: [ + ok: + {"Warseason overview", "application/json", + %Schema{type: :array, items: %Schema{type: :string}}}, + too_many_requests: TooManyRequestsSchema.response() + ] + def index(conn, _) do json(conn, Application.get_env(:helldivers_2, :war_seasons)) end - def show_info(conn, %{"war_id" => war_id}) do + operation :show_info, + summary: "Get information on a war season", + externalDocs: %OpenApiSpex.ExternalDocumentation{ + description: "This is a mapped version of the official WarInfo object", + url: "https://api.live.prod.thehelldiversgame.com/api/WarSeason/801/WarInfo" + }, + parameters: [ + war_id: [in: :path, description: "The war ID", type: :integer, example: 801] + ], + responses: [ + ok: WarInfoSchema.response(), + not_found: NotFoundSchema.response(), + too_many_requests: TooManyRequestsSchema.response(), + unprocessable_entity: JsonErrorResponse.response() + ] + + def show_info(conn, %{war_id: war_id}) do with {:ok, war_info} <- WarSeason.get_war_info(war_id) do render(conn, :show, war_info: war_info) end diff --git a/lib/helldivers_2_web/plugs/rate_limit.ex b/lib/helldivers_2_web/plugs/rate_limit.ex index 5669763..5c9032f 100644 --- a/lib/helldivers_2_web/plugs/rate_limit.ex +++ b/lib/helldivers_2_web/plugs/rate_limit.ex @@ -26,7 +26,7 @@ defmodule Helldivers2Web.Plugs.RateLimit do conn |> put_rate_limit_headers(limit, 0) - |> put_resp_header("Retry-After", to_string(ms_to_next_bucket / 1_000)) + |> put_resp_header("retry-after", to_string(ms_to_next_bucket / 1_000)) |> put_status(:too_many_requests) |> json(%{error: "Rate limit exceeded."}) |> halt() @@ -34,7 +34,7 @@ defmodule Helldivers2Web.Plugs.RateLimit do defp put_rate_limit_headers(conn, limit, remaining) do conn - |> put_resp_header("X-RateLimit-Limit", to_string(limit)) - |> put_resp_header("X-RateLimit-Remaining", to_string(remaining)) + |> put_resp_header("x-ratelimit-limit", to_string(limit)) + |> put_resp_header("x-ratelimit-remaining", to_string(remaining)) end end diff --git a/lib/helldivers_2_web/plugs/war_season.ex b/lib/helldivers_2_web/plugs/war_season.ex new file mode 100644 index 0000000..6633e55 --- /dev/null +++ b/lib/helldivers_2_web/plugs/war_season.ex @@ -0,0 +1,33 @@ +defmodule Helldivers2Web.Plugs.WarSeason do + import Plug.Conn + + alias Helldivers2Web.FallbackController + alias Helldivers2.WarSeason + + @doc """ + If the request contains a `war_id` it validates that it exists. + + This ensures that the rest of the application can assume any `war_id` passed exists. + """ + @spec check_war_id(Plug.Conn.t()) :: Plug.Conn.t() + def check_war_id(conn, _options \\ []) do + case Map.get(conn.params, "war_id") do + nil -> + conn + war_id -> + validate_war_id(conn, war_id) + end + end + + # We have a war_id, validate it exists + defp validate_war_id(conn, war_id) do + case WarSeason.exists?(war_id) do + true -> + conn + false -> + conn + |> FallbackController.call({:error, :not_found}) + |> halt() + end + end +end diff --git a/lib/helldivers_2_web/router.ex b/lib/helldivers_2_web/router.ex index 15aa833..9e9d459 100644 --- a/lib/helldivers_2_web/router.ex +++ b/lib/helldivers_2_web/router.ex @@ -12,7 +12,14 @@ defmodule Helldivers2Web.Router do pipeline :api do plug :accepts, ["json"] + plug OpenApiSpex.Plug.PutApiSpec, module: Helldivers2Web.ApiSpec plug :rate_limit, [interval_seconds: 300, max_requests: 10] + plug :check_war_id + end + + pipeline :openapi do + plug :accepts, ["json"] + plug OpenApiSpex.Plug.PutApiSpec, module: Helldivers2Web.ApiSpec end # scope "/", Helldivers2Web do @@ -21,6 +28,13 @@ defmodule Helldivers2Web.Router do # get "/", PageController, :home # end + scope "/api" do + pipe_through :openapi + + get "/openapi", OpenApiSpex.Plug.RenderSpec, [] + get "/swaggerui", OpenApiSpex.Plug.SwaggerUI, path: "/api/openapi" + end + # Other scopes may use custom stacks. scope "/api", Helldivers2Web.Api do pipe_through :api diff --git a/lib/helldivers_2_web/schemas/home_world_schema.ex b/lib/helldivers_2_web/schemas/home_world_schema.ex new file mode 100644 index 0000000..f536652 --- /dev/null +++ b/lib/helldivers_2_web/schemas/home_world_schema.ex @@ -0,0 +1,24 @@ +defmodule Helldivers2Web.Schemas.HomeWorldSchema do + alias Helldivers2Web.Schemas.PlanetSchema + alias OpenApiSpex.Schema + require OpenApiSpex + + @doc "Generates a schema for a single homeworld schema response" + def response(), do: {"Homeworld response", "application/json", __MODULE__} + + OpenApiSpex.schema(%{ + description: "Homeworld information of a given faction", + type: :object, + properties: %{ + race: %Schema{ + type: :string, + description: "The race that the planet is the homeworld of" + }, + planets: %Schema{ + type: :array, + items: PlanetSchema, + description: "The planets this race considers it's homeworlds" + } + } + }) +end diff --git a/lib/helldivers_2_web/schemas/not_found_schema.ex b/lib/helldivers_2_web/schemas/not_found_schema.ex new file mode 100644 index 0000000..2f36b05 --- /dev/null +++ b/lib/helldivers_2_web/schemas/not_found_schema.ex @@ -0,0 +1,16 @@ +defmodule Helldivers2Web.Schemas.NotFoundSchema do + alias OpenApiSpex.Schema + require OpenApiSpex + + def response(), do: {"Resource not found", "application/json", __MODULE__} + + OpenApiSpex.schema(%{ + description: "The resource you tried to retrieve could not be found", + type: :object, + properties: %{ + errors: %Schema{type: :object, properties: %{ + detail: %Schema{type: :string, description: "Description of what went wrong"} + }} + } + }) +end diff --git a/lib/helldivers_2_web/schemas/planet_schema.ex b/lib/helldivers_2_web/schemas/planet_schema.ex new file mode 100644 index 0000000..ba7e4cb --- /dev/null +++ b/lib/helldivers_2_web/schemas/planet_schema.ex @@ -0,0 +1,54 @@ +defmodule Helldivers2Web.Schemas.PlanetSchema do + alias OpenApiSpex.Schema + require OpenApiSpex + + @doc "Generates a schema for a single planet schema response" + def response(), do: {"Planet response", "application/json", __MODULE__} + + @doc "Generates a schema for an array of planet schemas" + def responses(), do: {"Planets response", "application/json", %Schema{type: :array, items: __MODULE__}} + + OpenApiSpex.schema(%{ + description: "Represents a planet in the galactic war that must receive Managed democracy", + type: :object, + properties: %{ + index: %Schema{ + type: :integer, + description: + "The index of this planet, for convenience kept the same as in the official API" + }, + name: %Schema{ + type: :string, + description: "The human readable name of the planet, or unknown if it's not a known name" + }, + hash: %Schema{ + type: :integer, + description: "A hash retrieved from the official API, purpose unknown" + }, + position: %Schema{ + type: :object, + description: "The coordinates in the galaxy where this planet is located", + properties: %{ + x: %Schema{type: :number, description: "X coordinate"}, + y: %Schema{type: :number, description: "Y coordinate"} + } + }, + waypoints: %Schema{ + type: :array, + description: "Waypoints, seems to link planets together but purpose unclear" + }, + max_health: %Schema{ + type: :integer, + description: "The maximum health of this planet, used in conflict stats" + }, + disabled: %Schema{ + type: :boolean, + description: "Whether or not this planet is currently playable (enabled)" + }, + initial_owner: %Schema{ + type: :string, + description: "Which faction originally claimed this planet" + } + } + }) +end diff --git a/lib/helldivers_2_web/schemas/too_many_requests_schema.ex b/lib/helldivers_2_web/schemas/too_many_requests_schema.ex new file mode 100644 index 0000000..09e0677 --- /dev/null +++ b/lib/helldivers_2_web/schemas/too_many_requests_schema.ex @@ -0,0 +1,14 @@ +defmodule Helldivers2Web.Schemas.TooManyRequestsSchema do + alias OpenApiSpex.Schema + require OpenApiSpex + + def response(), do: {"Rate limit exceeded", "application/json", __MODULE__} + + OpenApiSpex.schema(%{ + description: "You're making too many requests in a limited span of time", + type: :object, + properties: %{ + error: %Schema{type: :string, description: "Error message for rate limit being exceeded"} + } + }) +end diff --git a/lib/helldivers_2_web/schemas/war_info_schema.ex b/lib/helldivers_2_web/schemas/war_info_schema.ex new file mode 100644 index 0000000..9cad5ed --- /dev/null +++ b/lib/helldivers_2_web/schemas/war_info_schema.ex @@ -0,0 +1,47 @@ +defmodule Helldivers2Web.Schemas.WarInfoSchema do + require OpenApiSpex + + alias OpenApiSpex.Schema + alias Helldivers2Web.Schemas.{PlanetSchema, HomeWorldSchema} + + @doc "Generates a schema for a single war info schema response" + def response(), do: {"War info response", "application/json", __MODULE__} + + OpenApiSpex.schema(%{ + description: "Global overview of the war, it's planets, capitals etc", + type: :object, + properties: %{ + war_id: %Schema{ + type: :string, + description: + "The identifier for this war, this ID must be passed for all resources under this war" + }, + start_date: %Schema{ + type: :string, + format: :"date-time", + description: "When this war season was started" + }, + end_date: %Schema{ + type: :string, + format: :"date-time", + description: "When this war season is scheduled to end" + }, + minimum_client_version: %Schema{ + type: :string, + description: "Used by the Helldivers 2 game client" + }, + planets: %Schema{ + type: :array, + items: PlanetSchema, + description: "All planets present in this war season" + }, + home_worlds: %Schema{ + type: :array, + items: HomeWorldSchema, + description: "All homeworlds present in this war season" + }, + capitals: %Schema{type: :array, description: "Empty, not been mapped yet"}, + planet_permanent_effects: %Schema{type: :array, description: "Empty, not been mapped yet"} + } + }) +end diff --git a/mix.exs b/mix.exs index 84dbfcb..c3a6881 100644 --- a/mix.exs +++ b/mix.exs @@ -52,7 +52,8 @@ defmodule Helldivers2.MixProject do {:nimble_options, "~> 1.1.0"}, {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}, - {:ex_rated, "~> 2.1.0"} + {:ex_rated, "~> 2.1.0"}, + {:open_api_spex, "~> 3.18"} ] end diff --git a/mix.lock b/mix.lock index c907fa1..0a7a050 100644 --- a/mix.lock +++ b/mix.lock @@ -20,6 +20,7 @@ "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, "nimble_ownership": {:hex, :nimble_ownership, "0.2.1", "3e44c72ebe8dd213db4e13aff4090aaa331d158e72ce1891d02e0ffb05a1eb2d", [:mix], [], "hexpm", "bf38d2ef4fb990521a4ecf112843063c1f58a5c602484af4c7977324042badee"}, "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, + "open_api_spex": {:hex, :open_api_spex, "3.18.2", "8c855e83bfe8bf81603d919d6e892541eafece3720f34d1700b58024dadde247", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0 or ~> 5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:ymlr, "~> 2.0 or ~> 3.0 or ~> 4.0", [hex: :ymlr, repo: "hexpm", optional: true]}], "hexpm", "aa3e6dcfc0ad6a02596b2172662da21c9dd848dac145ea9e603f54e3d81b8d2b"}, "phoenix": {:hex, :phoenix, "1.7.11", "1d88fc6b05ab0c735b250932c4e6e33bfa1c186f76dcf623d8dd52f07d6379c7", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "b1ec57f2e40316b306708fe59b92a16b9f6f4bf50ccfa41aa8c7feb79e0ec02a"}, "phoenix_html": {:hex, :phoenix_html, "3.3.3", "380b8fb45912b5638d2f1d925a3771b4516b9a78587249cabe394e0a5d579dc9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "923ebe6fec6e2e3b3e569dfbdc6560de932cd54b000ada0208b5f45024bdd76c"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"}, diff --git a/test/helldivers_2_web/controllers/api/planets_controller_test.exs b/test/helldivers_2_web/controllers/api/planets_controller_test.exs new file mode 100644 index 0000000..97aea78 --- /dev/null +++ b/test/helldivers_2_web/controllers/api/planets_controller_test.exs @@ -0,0 +1,99 @@ +defmodule Helldivers2Web.Api.PlanetsControllerTest do + use Helldivers2Web.ConnCase + + import OpenApiSpex.TestAssertions + + alias Helldivers2.Models.WarInfo.Planet + alias Helldivers2.Models.WarInfo + alias Helldivers2.WarSeason + + @war_id "1" + + setup _ do + # Start up an internal war season + {:ok, _} = WarSeason.start_link(war_id: @war_id) + + # Store a few planets in the given war season + WarSeason.store(@war_id, %WarInfo{ + planets: [ + %Planet{ + index: 0, + name: "Super Earth", + hash: 897_386_910, + position: {0, 0}, + waypoints: [1], + sector: "Sol", + max_health: 1_000_000, + disabled: false, + initial_owner: "Humans" + }, + %Planet{ + index: 1, + name: "Klen Dahth II", + hash: 3621417917, + position: {0.05373042, 0.10565466}, + waypoints: [2], + sector: "Altus", + max_health: 1000000, + disabled: false, + initial_owner: "Humans" + } + ] + }) + + :ok + end + + describe "GET /api/:war_id/planets" do + test "returns a list of all available planets", %{conn: conn} do + response = + conn + |> get(~p"/api/#{@war_id}/planets") + |> json_response(200) + + assert [%{"index" => 0}] = Enum.take(response, 1) + end + + test "conforms to it's schema", %{conn: conn} do + response = + conn + |> get(~p"/api/#{@war_id}/planets") + |> json_response(200) + + spec = Helldivers2Web.ApiSpec.spec() + for planet <- response do + assert_schema(planet, "PlanetSchema", spec) + end + end + end + + describe "GET /api/:war_id/planets/:planet_index" do + test "returns 404 for unknown planets", %{conn: conn} do + conn + |> get(~p"/api/#{@war_id}/planets/5") + |> json_response(404) + end + + test "returns 422 for invalid planet indices", %{conn: conn} do + conn + |> get(~p"/api/#{@war_id}/planets/invalid") + |> json_response(422) + end + + test "returns 200 for a valid planet index", %{conn: conn} do + conn + |> get(~p"/api/#{@war_id}/planets/0") + |> json_response(200) + end + + test "response conforms to schema", %{conn: conn} do + response = + conn + |> get(~p"/api/#{@war_id}/planets/0") + |> json_response(200) + + spec = Helldivers2Web.ApiSpec.spec() + assert_schema(response, "PlanetSchema", spec) + end + end +end diff --git a/test/helldivers_2_web/controllers/page_controller_test.exs b/test/helldivers_2_web/controllers/page_controller_test.exs index 5df0be6..7c56d4e 100644 --- a/test/helldivers_2_web/controllers/page_controller_test.exs +++ b/test/helldivers_2_web/controllers/page_controller_test.exs @@ -1,8 +1,8 @@ defmodule Helldivers2Web.PageControllerTest do use Helldivers2Web.ConnCase - test "GET /", %{conn: conn} do - conn = get(conn, ~p"/") - assert html_response(conn, 200) =~ "Peace of mind from prototype to production" - end + # test "GET /", %{conn: conn} do + # conn = get(conn, ~p"/") + # assert html_response(conn, 200) =~ "Peace of mind from prototype to production" + # end end