Merge branch 'openapi-improvements' into 'develop'
Support validation for inline OpenAPI schema and automatic tests for examples Closes #1696 See merge request pleroma/pleroma!2421
This commit is contained in:
commit
d862c7156a
@ -6,8 +6,6 @@ defmodule Pleroma.Web.ApiSpec.AppOperation do
|
|||||||
alias OpenApiSpex.Operation
|
alias OpenApiSpex.Operation
|
||||||
alias OpenApiSpex.Schema
|
alias OpenApiSpex.Schema
|
||||||
alias Pleroma.Web.ApiSpec.Helpers
|
alias Pleroma.Web.ApiSpec.Helpers
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.AppCreateRequest
|
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.AppCreateResponse
|
|
||||||
|
|
||||||
@spec open_api_operation(atom) :: Operation.t()
|
@spec open_api_operation(atom) :: Operation.t()
|
||||||
def open_api_operation(action) do
|
def open_api_operation(action) do
|
||||||
@ -22,9 +20,9 @@ def create_operation do
|
|||||||
summary: "Create an application",
|
summary: "Create an application",
|
||||||
description: "Create a new application to obtain OAuth2 credentials",
|
description: "Create a new application to obtain OAuth2 credentials",
|
||||||
operationId: "AppController.create",
|
operationId: "AppController.create",
|
||||||
requestBody: Helpers.request_body("Parameters", AppCreateRequest, required: true),
|
requestBody: Helpers.request_body("Parameters", create_request(), required: true),
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("App", "application/json", AppCreateResponse),
|
200 => Operation.response("App", "application/json", create_response()),
|
||||||
422 =>
|
422 =>
|
||||||
Operation.response(
|
Operation.response(
|
||||||
"Unprocessable Entity",
|
"Unprocessable Entity",
|
||||||
@ -93,4 +91,58 @@ def verify_credentials_operation do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp create_request do
|
||||||
|
%Schema{
|
||||||
|
title: "AppCreateRequest",
|
||||||
|
description: "POST body for creating an app",
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
client_name: %Schema{type: :string, description: "A name for your application."},
|
||||||
|
redirect_uris: %Schema{
|
||||||
|
type: :string,
|
||||||
|
description:
|
||||||
|
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
|
||||||
|
},
|
||||||
|
scopes: %Schema{
|
||||||
|
type: :string,
|
||||||
|
description: "Space separated list of scopes",
|
||||||
|
default: "read"
|
||||||
|
},
|
||||||
|
website: %Schema{type: :string, description: "A URL to the homepage of your app"}
|
||||||
|
},
|
||||||
|
required: [:client_name, :redirect_uris],
|
||||||
|
example: %{
|
||||||
|
"client_name" => "My App",
|
||||||
|
"redirect_uris" => "https://myapp.com/auth/callback",
|
||||||
|
"website" => "https://myapp.com/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp create_response do
|
||||||
|
%Schema{
|
||||||
|
title: "AppCreateResponse",
|
||||||
|
description: "Response schema for an app",
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
id: %Schema{type: :string},
|
||||||
|
name: %Schema{type: :string},
|
||||||
|
client_id: %Schema{type: :string},
|
||||||
|
client_secret: %Schema{type: :string},
|
||||||
|
redirect_uri: %Schema{type: :string},
|
||||||
|
vapid_key: %Schema{type: :string},
|
||||||
|
website: %Schema{type: :string, nullable: true}
|
||||||
|
},
|
||||||
|
example: %{
|
||||||
|
"id" => "123",
|
||||||
|
"name" => "My App",
|
||||||
|
"client_id" => "TWhM-tNSuncnqN7DBJmoyeLnk6K3iJJ71KKXxgL1hPM",
|
||||||
|
"client_secret" => "ZEaFUFmF0umgBX1qKJDjaU99Q31lDkOU8NutzTOoliw",
|
||||||
|
"vapid_key" =>
|
||||||
|
"BCk-QqERU0q-CfYZjcuB6lnyyOYfJ2AifKqfeGIm7Z-HiTU5T9eTG5GxVA0_OH5mMlI4UkkDTpaZwozy0TzdZ2M=",
|
||||||
|
"website" => "https://myapp.com/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
defmodule Pleroma.Web.ApiSpec.CustomEmojiOperation do
|
defmodule Pleroma.Web.ApiSpec.CustomEmojiOperation do
|
||||||
alias OpenApiSpex.Operation
|
alias OpenApiSpex.Operation
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.CustomEmojisResponse
|
alias OpenApiSpex.Schema
|
||||||
|
alias Pleroma.Web.ApiSpec.Schemas.CustomEmoji
|
||||||
|
|
||||||
def open_api_operation(action) do
|
def open_api_operation(action) do
|
||||||
operation = String.to_existing_atom("#{action}_operation")
|
operation = String.to_existing_atom("#{action}_operation")
|
||||||
@ -18,8 +19,43 @@ def index_operation do
|
|||||||
description: "Returns custom emojis that are available on the server.",
|
description: "Returns custom emojis that are available on the server.",
|
||||||
operationId: "CustomEmojiController.index",
|
operationId: "CustomEmojiController.index",
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Custom Emojis", "application/json", CustomEmojisResponse)
|
200 => Operation.response("Custom Emojis", "application/json", custom_emojis_resposnse())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp custom_emojis_resposnse do
|
||||||
|
%Schema{
|
||||||
|
title: "CustomEmojisResponse",
|
||||||
|
description: "Response schema for custom emojis",
|
||||||
|
type: :array,
|
||||||
|
items: CustomEmoji,
|
||||||
|
example: [
|
||||||
|
%{
|
||||||
|
"category" => "Fun",
|
||||||
|
"shortcode" => "blank",
|
||||||
|
"static_url" => "https://lain.com/emoji/blank.png",
|
||||||
|
"tags" => ["Fun"],
|
||||||
|
"url" => "https://lain.com/emoji/blank.png",
|
||||||
|
"visible_in_picker" => false
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"category" => "Gif,Fun",
|
||||||
|
"shortcode" => "firefox",
|
||||||
|
"static_url" => "https://lain.com/emoji/Firefox.gif",
|
||||||
|
"tags" => ["Gif", "Fun"],
|
||||||
|
"url" => "https://lain.com/emoji/Firefox.gif",
|
||||||
|
"visible_in_picker" => true
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"category" => "pack:mixed",
|
||||||
|
"shortcode" => "sadcat",
|
||||||
|
"static_url" => "https://lain.com/emoji/mixed/sadcat.png",
|
||||||
|
"tags" => ["pack:mixed"],
|
||||||
|
"url" => "https://lain.com/emoji/mixed/sadcat.png",
|
||||||
|
"visible_in_picker" => true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -6,8 +6,6 @@ defmodule Pleroma.Web.ApiSpec.DomainBlockOperation do
|
|||||||
alias OpenApiSpex.Operation
|
alias OpenApiSpex.Operation
|
||||||
alias OpenApiSpex.Schema
|
alias OpenApiSpex.Schema
|
||||||
alias Pleroma.Web.ApiSpec.Helpers
|
alias Pleroma.Web.ApiSpec.Helpers
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.DomainBlockRequest
|
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse
|
|
||||||
|
|
||||||
def open_api_operation(action) do
|
def open_api_operation(action) do
|
||||||
operation = String.to_existing_atom("#{action}_operation")
|
operation = String.to_existing_atom("#{action}_operation")
|
||||||
@ -22,7 +20,13 @@ def index_operation do
|
|||||||
security: [%{"oAuth" => ["follow", "read:blocks"]}],
|
security: [%{"oAuth" => ["follow", "read:blocks"]}],
|
||||||
operationId: "DomainBlockController.index",
|
operationId: "DomainBlockController.index",
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Domain blocks", "application/json", DomainBlocksResponse)
|
200 =>
|
||||||
|
Operation.response("Domain blocks", "application/json", %Schema{
|
||||||
|
description: "Response schema for domain blocks",
|
||||||
|
type: :array,
|
||||||
|
items: %Schema{type: :string},
|
||||||
|
example: ["google.com", "facebook.com"]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -40,7 +44,7 @@ def create_operation do
|
|||||||
- prevent following new users from it (but does not remove existing follows)
|
- prevent following new users from it (but does not remove existing follows)
|
||||||
""",
|
""",
|
||||||
operationId: "DomainBlockController.create",
|
operationId: "DomainBlockController.create",
|
||||||
requestBody: Helpers.request_body("Parameters", DomainBlockRequest, required: true),
|
requestBody: domain_block_request(),
|
||||||
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
||||||
@ -54,11 +58,28 @@ def delete_operation do
|
|||||||
summary: "Unblock a domain",
|
summary: "Unblock a domain",
|
||||||
description: "Remove a domain block, if it exists in the user's array of blocked domains.",
|
description: "Remove a domain block, if it exists in the user's array of blocked domains.",
|
||||||
operationId: "DomainBlockController.delete",
|
operationId: "DomainBlockController.delete",
|
||||||
requestBody: Helpers.request_body("Parameters", DomainBlockRequest, required: true),
|
requestBody: domain_block_request(),
|
||||||
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
security: [%{"oAuth" => ["follow", "write:blocks"]}],
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp domain_block_request do
|
||||||
|
Helpers.request_body(
|
||||||
|
"Parameters",
|
||||||
|
%Schema{
|
||||||
|
type: :object,
|
||||||
|
properties: %{
|
||||||
|
domain: %Schema{type: :string}
|
||||||
|
},
|
||||||
|
required: [:domain]
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
example: %{
|
||||||
|
"domain" => "facebook.com"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.ApiSpec.Schemas.AppCreateRequest do
|
|
||||||
alias OpenApiSpex.Schema
|
|
||||||
require OpenApiSpex
|
|
||||||
|
|
||||||
OpenApiSpex.schema(%{
|
|
||||||
title: "AppCreateRequest",
|
|
||||||
description: "POST body for creating an app",
|
|
||||||
type: :object,
|
|
||||||
properties: %{
|
|
||||||
client_name: %Schema{type: :string, description: "A name for your application."},
|
|
||||||
redirect_uris: %Schema{
|
|
||||||
type: :string,
|
|
||||||
description:
|
|
||||||
"Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
|
|
||||||
},
|
|
||||||
scopes: %Schema{
|
|
||||||
type: :string,
|
|
||||||
description: "Space separated list of scopes. If none is provided, defaults to `read`."
|
|
||||||
},
|
|
||||||
website: %Schema{type: :string, description: "A URL to the homepage of your app"}
|
|
||||||
},
|
|
||||||
required: [:client_name, :redirect_uris],
|
|
||||||
example: %{
|
|
||||||
"client_name" => "My App",
|
|
||||||
"redirect_uris" => "https://myapp.com/auth/callback",
|
|
||||||
"website" => "https://myapp.com/"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
end
|
|
@ -1,33 +0,0 @@
|
|||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.ApiSpec.Schemas.AppCreateResponse do
|
|
||||||
alias OpenApiSpex.Schema
|
|
||||||
|
|
||||||
require OpenApiSpex
|
|
||||||
|
|
||||||
OpenApiSpex.schema(%{
|
|
||||||
title: "AppCreateResponse",
|
|
||||||
description: "Response schema for an app",
|
|
||||||
type: :object,
|
|
||||||
properties: %{
|
|
||||||
id: %Schema{type: :string},
|
|
||||||
name: %Schema{type: :string},
|
|
||||||
client_id: %Schema{type: :string},
|
|
||||||
client_secret: %Schema{type: :string},
|
|
||||||
redirect_uri: %Schema{type: :string},
|
|
||||||
vapid_key: %Schema{type: :string},
|
|
||||||
website: %Schema{type: :string, nullable: true}
|
|
||||||
},
|
|
||||||
example: %{
|
|
||||||
"id" => "123",
|
|
||||||
"name" => "My App",
|
|
||||||
"client_id" => "TWhM-tNSuncnqN7DBJmoyeLnk6K3iJJ71KKXxgL1hPM",
|
|
||||||
"client_secret" => "ZEaFUFmF0umgBX1qKJDjaU99Q31lDkOU8NutzTOoliw",
|
|
||||||
"vapid_key" =>
|
|
||||||
"BCk-QqERU0q-CfYZjcuB6lnyyOYfJ2AifKqfeGIm7Z-HiTU5T9eTG5GxVA0_OH5mMlI4UkkDTpaZwozy0TzdZ2M=",
|
|
||||||
"website" => "https://myapp.com/"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
end
|
|
@ -1,42 +0,0 @@
|
|||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.ApiSpec.Schemas.CustomEmojisResponse do
|
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.CustomEmoji
|
|
||||||
|
|
||||||
require OpenApiSpex
|
|
||||||
|
|
||||||
OpenApiSpex.schema(%{
|
|
||||||
title: "CustomEmojisResponse",
|
|
||||||
description: "Response schema for custom emojis",
|
|
||||||
type: :array,
|
|
||||||
items: CustomEmoji,
|
|
||||||
example: [
|
|
||||||
%{
|
|
||||||
"category" => "Fun",
|
|
||||||
"shortcode" => "blank",
|
|
||||||
"static_url" => "https://lain.com/emoji/blank.png",
|
|
||||||
"tags" => ["Fun"],
|
|
||||||
"url" => "https://lain.com/emoji/blank.png",
|
|
||||||
"visible_in_picker" => true
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
"category" => "Gif,Fun",
|
|
||||||
"shortcode" => "firefox",
|
|
||||||
"static_url" => "https://lain.com/emoji/Firefox.gif",
|
|
||||||
"tags" => ["Gif", "Fun"],
|
|
||||||
"url" => "https://lain.com/emoji/Firefox.gif",
|
|
||||||
"visible_in_picker" => true
|
|
||||||
},
|
|
||||||
%{
|
|
||||||
"category" => "pack:mixed",
|
|
||||||
"shortcode" => "sadcat",
|
|
||||||
"static_url" => "https://lain.com/emoji/mixed/sadcat.png",
|
|
||||||
"tags" => ["pack:mixed"],
|
|
||||||
"url" => "https://lain.com/emoji/mixed/sadcat.png",
|
|
||||||
"visible_in_picker" => true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
end
|
|
@ -1,20 +0,0 @@
|
|||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.ApiSpec.Schemas.DomainBlockRequest do
|
|
||||||
alias OpenApiSpex.Schema
|
|
||||||
require OpenApiSpex
|
|
||||||
|
|
||||||
OpenApiSpex.schema(%{
|
|
||||||
title: "DomainBlockRequest",
|
|
||||||
type: :object,
|
|
||||||
properties: %{
|
|
||||||
domain: %Schema{type: :string}
|
|
||||||
},
|
|
||||||
required: [:domain],
|
|
||||||
example: %{
|
|
||||||
"domain" => "facebook.com"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
end
|
|
@ -1,16 +0,0 @@
|
|||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse do
|
|
||||||
require OpenApiSpex
|
|
||||||
alias OpenApiSpex.Schema
|
|
||||||
|
|
||||||
OpenApiSpex.schema(%{
|
|
||||||
title: "DomainBlocksResponse",
|
|
||||||
description: "Response schema for domain blocks",
|
|
||||||
type: :array,
|
|
||||||
items: %Schema{type: :string},
|
|
||||||
example: ["google.com", "facebook.com"]
|
|
||||||
})
|
|
||||||
end
|
|
@ -17,12 +17,8 @@ defmodule Pleroma.Web.OAuth.Scopes do
|
|||||||
"""
|
"""
|
||||||
@spec fetch_scopes(map() | struct(), list()) :: list()
|
@spec fetch_scopes(map() | struct(), list()) :: list()
|
||||||
|
|
||||||
def fetch_scopes(%Pleroma.Web.ApiSpec.Schemas.AppCreateRequest{scopes: scopes}, default) do
|
|
||||||
parse_scopes(scopes, default)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fetch_scopes(params, default) do
|
def fetch_scopes(params, default) do
|
||||||
parse_scopes(params["scope"] || params["scopes"], default)
|
parse_scopes(params["scope"] || params["scopes"] || params[:scopes], default)
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_scopes(scopes, _default) when is_list(scopes) do
|
def parse_scopes(scopes, _default) when is_list(scopes) do
|
||||||
|
57
test/support/api_spec_helpers.ex
Normal file
57
test/support/api_spec_helpers.ex
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Tests.ApiSpecHelpers do
|
||||||
|
@moduledoc """
|
||||||
|
OpenAPI spec test helpers
|
||||||
|
"""
|
||||||
|
|
||||||
|
import ExUnit.Assertions
|
||||||
|
|
||||||
|
alias OpenApiSpex.Cast.Error
|
||||||
|
alias OpenApiSpex.Reference
|
||||||
|
alias OpenApiSpex.Schema
|
||||||
|
|
||||||
|
def assert_schema(value, schema) do
|
||||||
|
api_spec = Pleroma.Web.ApiSpec.spec()
|
||||||
|
|
||||||
|
case OpenApiSpex.cast_value(value, schema, api_spec) do
|
||||||
|
{:ok, data} ->
|
||||||
|
data
|
||||||
|
|
||||||
|
{:error, errors} ->
|
||||||
|
errors =
|
||||||
|
Enum.map(errors, fn error ->
|
||||||
|
message = Error.message(error)
|
||||||
|
path = Error.path_to_string(error)
|
||||||
|
"#{message} at #{path}"
|
||||||
|
end)
|
||||||
|
|
||||||
|
flunk(
|
||||||
|
"Value does not conform to schema #{schema.title}: #{Enum.join(errors, "\n")}\n#{
|
||||||
|
inspect(value)
|
||||||
|
}"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def resolve_schema(%Schema{} = schema), do: schema
|
||||||
|
|
||||||
|
def resolve_schema(%Reference{} = ref) do
|
||||||
|
schemas = Pleroma.Web.ApiSpec.spec().components.schemas
|
||||||
|
Reference.resolve_schema(ref, schemas)
|
||||||
|
end
|
||||||
|
|
||||||
|
def api_operations do
|
||||||
|
paths = Pleroma.Web.ApiSpec.spec().paths
|
||||||
|
|
||||||
|
Enum.flat_map(paths, fn {_, path_item} ->
|
||||||
|
path_item
|
||||||
|
|> Map.take([:delete, :get, :head, :options, :patch, :post, :put, :trace])
|
||||||
|
|> Map.values()
|
||||||
|
|> Enum.reject(&is_nil/1)
|
||||||
|
|> Enum.uniq()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
@ -51,6 +51,42 @@ defp oauth_access(scopes, opts \\ []) do
|
|||||||
%{user: user, token: token, conn: conn}
|
%{user: user, token: token, conn: conn}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp json_response_and_validate_schema(conn, status \\ nil) do
|
||||||
|
content_type =
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.get_resp_header("content-type")
|
||||||
|
|> List.first()
|
||||||
|
|> String.split(";")
|
||||||
|
|> List.first()
|
||||||
|
|
||||||
|
status = status || conn.status
|
||||||
|
|
||||||
|
%{private: %{open_api_spex: %{operation_id: op_id, operation_lookup: lookup, spec: spec}}} =
|
||||||
|
conn
|
||||||
|
|
||||||
|
schema = lookup[op_id].responses[status].content[content_type].schema
|
||||||
|
json = json_response(conn, status)
|
||||||
|
|
||||||
|
case OpenApiSpex.cast_value(json, schema, spec) do
|
||||||
|
{:ok, _data} ->
|
||||||
|
json
|
||||||
|
|
||||||
|
{:error, errors} ->
|
||||||
|
errors =
|
||||||
|
Enum.map(errors, fn error ->
|
||||||
|
message = OpenApiSpex.Cast.Error.message(error)
|
||||||
|
path = OpenApiSpex.Cast.Error.path_to_string(error)
|
||||||
|
"#{message} at #{path}"
|
||||||
|
end)
|
||||||
|
|
||||||
|
flunk(
|
||||||
|
"Response does not conform to schema of #{op_id} operation: #{
|
||||||
|
Enum.join(errors, "\n")
|
||||||
|
}\n#{inspect(json)}"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp ensure_federating_or_authenticated(conn, url, user) do
|
defp ensure_federating_or_authenticated(conn, url, user) do
|
||||||
initial_setting = Config.get([:instance, :federating])
|
initial_setting = Config.get([:instance, :federating])
|
||||||
on_exit(fn -> Config.put([:instance, :federating], initial_setting) end)
|
on_exit(fn -> Config.put([:instance, :federating], initial_setting) end)
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
# Pleroma: A lightweight social networking server
|
|
||||||
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
defmodule Pleroma.Web.ApiSpec.AppOperationTest do
|
|
||||||
use Pleroma.Web.ConnCase, async: true
|
|
||||||
|
|
||||||
alias Pleroma.Web.ApiSpec
|
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.AppCreateRequest
|
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.AppCreateResponse
|
|
||||||
|
|
||||||
import OpenApiSpex.TestAssertions
|
|
||||||
import Pleroma.Factory
|
|
||||||
|
|
||||||
test "AppCreateRequest example matches schema" do
|
|
||||||
api_spec = ApiSpec.spec()
|
|
||||||
schema = AppCreateRequest.schema()
|
|
||||||
assert_schema(schema.example, "AppCreateRequest", api_spec)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "AppCreateResponse example matches schema" do
|
|
||||||
api_spec = ApiSpec.spec()
|
|
||||||
schema = AppCreateResponse.schema()
|
|
||||||
assert_schema(schema.example, "AppCreateResponse", api_spec)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "AppController produces a AppCreateResponse", %{conn: conn} do
|
|
||||||
api_spec = ApiSpec.spec()
|
|
||||||
app_attrs = build(:oauth_app)
|
|
||||||
|
|
||||||
json =
|
|
||||||
conn
|
|
||||||
|> put_req_header("content-type", "application/json")
|
|
||||||
|> post(
|
|
||||||
"/api/v1/apps",
|
|
||||||
Jason.encode!(%{
|
|
||||||
client_name: app_attrs.client_name,
|
|
||||||
redirect_uris: app_attrs.redirect_uris
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|> json_response(200)
|
|
||||||
|
|
||||||
assert_schema(json, "AppCreateResponse", api_spec)
|
|
||||||
end
|
|
||||||
end
|
|
43
test/web/api_spec/schema_examples_test.exs
Normal file
43
test/web/api_spec/schema_examples_test.exs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.ApiSpec.SchemaExamplesTest do
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
import Pleroma.Tests.ApiSpecHelpers
|
||||||
|
|
||||||
|
@content_type "application/json"
|
||||||
|
|
||||||
|
for operation <- api_operations() do
|
||||||
|
describe operation.operationId <> " Request Body" do
|
||||||
|
if operation.requestBody do
|
||||||
|
@media_type operation.requestBody.content[@content_type]
|
||||||
|
@schema resolve_schema(@media_type.schema)
|
||||||
|
|
||||||
|
if @media_type.example do
|
||||||
|
test "request body media type example matches schema" do
|
||||||
|
assert_schema(@media_type.example, @schema)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @schema.example do
|
||||||
|
test "request body schema example matches schema" do
|
||||||
|
assert_schema(@schema.example, @schema)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for {status, response} <- operation.responses do
|
||||||
|
describe "#{operation.operationId} - #{status} Response" do
|
||||||
|
@schema resolve_schema(response.content[@content_type].schema)
|
||||||
|
|
||||||
|
if @schema.example do
|
||||||
|
test "example matches schema" do
|
||||||
|
assert_schema(@schema.example, @schema)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -27,7 +27,7 @@ test "apps/verify_credentials", %{conn: conn} do
|
|||||||
"vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
|
"vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert expected == json_response(conn, 200)
|
assert expected == json_response_and_validate_schema(conn, 200)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "creates an oauth app", %{conn: conn} do
|
test "creates an oauth app", %{conn: conn} do
|
||||||
@ -55,6 +55,6 @@ test "creates an oauth app", %{conn: conn} do
|
|||||||
"vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
|
"vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert expected == json_response(conn, 200)
|
assert expected == json_response_and_validate_schema(conn, 200)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -5,15 +5,13 @@
|
|||||||
defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do
|
defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do
|
||||||
use Pleroma.Web.ConnCase, async: true
|
use Pleroma.Web.ConnCase, async: true
|
||||||
alias Pleroma.Web.ApiSpec
|
alias Pleroma.Web.ApiSpec
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.CustomEmoji
|
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.CustomEmojisResponse
|
|
||||||
import OpenApiSpex.TestAssertions
|
import OpenApiSpex.TestAssertions
|
||||||
|
|
||||||
test "with tags", %{conn: conn} do
|
test "with tags", %{conn: conn} do
|
||||||
assert resp =
|
assert resp =
|
||||||
conn
|
conn
|
||||||
|> get("/api/v1/custom_emojis")
|
|> get("/api/v1/custom_emojis")
|
||||||
|> json_response(200)
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
assert [emoji | _body] = resp
|
assert [emoji | _body] = resp
|
||||||
assert Map.has_key?(emoji, "shortcode")
|
assert Map.has_key?(emoji, "shortcode")
|
||||||
@ -23,19 +21,6 @@ test "with tags", %{conn: conn} do
|
|||||||
assert Map.has_key?(emoji, "category")
|
assert Map.has_key?(emoji, "category")
|
||||||
assert Map.has_key?(emoji, "url")
|
assert Map.has_key?(emoji, "url")
|
||||||
assert Map.has_key?(emoji, "visible_in_picker")
|
assert Map.has_key?(emoji, "visible_in_picker")
|
||||||
assert_schema(resp, "CustomEmojisResponse", ApiSpec.spec())
|
|
||||||
assert_schema(emoji, "CustomEmoji", ApiSpec.spec())
|
assert_schema(emoji, "CustomEmoji", ApiSpec.spec())
|
||||||
end
|
end
|
||||||
|
|
||||||
test "CustomEmoji example matches schema" do
|
|
||||||
api_spec = ApiSpec.spec()
|
|
||||||
schema = CustomEmoji.schema()
|
|
||||||
assert_schema(schema.example, "CustomEmoji", api_spec)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "CustomEmojisResponse example matches schema" do
|
|
||||||
api_spec = ApiSpec.spec()
|
|
||||||
schema = CustomEmojisResponse.schema()
|
|
||||||
assert_schema(schema.example, "CustomEmojisResponse", api_spec)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -6,11 +6,8 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do
|
|||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
|
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ApiSpec
|
|
||||||
alias Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse
|
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
import OpenApiSpex.TestAssertions
|
|
||||||
|
|
||||||
test "blocking / unblocking a domain" do
|
test "blocking / unblocking a domain" do
|
||||||
%{user: user, conn: conn} = oauth_access(["write:blocks"])
|
%{user: user, conn: conn} = oauth_access(["write:blocks"])
|
||||||
@ -21,7 +18,7 @@ test "blocking / unblocking a domain" do
|
|||||||
|> put_req_header("content-type", "application/json")
|
|> put_req_header("content-type", "application/json")
|
||||||
|> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
|
|> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
|
||||||
|
|
||||||
assert %{} = json_response(ret_conn, 200)
|
assert %{} == json_response_and_validate_schema(ret_conn, 200)
|
||||||
user = User.get_cached_by_ap_id(user.ap_id)
|
user = User.get_cached_by_ap_id(user.ap_id)
|
||||||
assert User.blocks?(user, other_user)
|
assert User.blocks?(user, other_user)
|
||||||
|
|
||||||
@ -30,7 +27,7 @@ test "blocking / unblocking a domain" do
|
|||||||
|> put_req_header("content-type", "application/json")
|
|> put_req_header("content-type", "application/json")
|
||||||
|> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
|
|> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
|
||||||
|
|
||||||
assert %{} = json_response(ret_conn, 200)
|
assert %{} == json_response_and_validate_schema(ret_conn, 200)
|
||||||
user = User.get_cached_by_ap_id(user.ap_id)
|
user = User.get_cached_by_ap_id(user.ap_id)
|
||||||
refute User.blocks?(user, other_user)
|
refute User.blocks?(user, other_user)
|
||||||
end
|
end
|
||||||
@ -41,21 +38,10 @@ test "getting a list of domain blocks" do
|
|||||||
{:ok, user} = User.block_domain(user, "bad.site")
|
{:ok, user} = User.block_domain(user, "bad.site")
|
||||||
{:ok, user} = User.block_domain(user, "even.worse.site")
|
{:ok, user} = User.block_domain(user, "even.worse.site")
|
||||||
|
|
||||||
conn =
|
assert ["even.worse.site", "bad.site"] ==
|
||||||
conn
|
conn
|
||||||
|> assign(:user, user)
|
|> assign(:user, user)
|
||||||
|> get("/api/v1/domain_blocks")
|
|> get("/api/v1/domain_blocks")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
domain_blocks = json_response(conn, 200)
|
|
||||||
|
|
||||||
assert "bad.site" in domain_blocks
|
|
||||||
assert "even.worse.site" in domain_blocks
|
|
||||||
assert_schema(domain_blocks, "DomainBlocksResponse", ApiSpec.spec())
|
|
||||||
end
|
|
||||||
|
|
||||||
test "DomainBlocksResponse example matches schema" do
|
|
||||||
api_spec = ApiSpec.spec()
|
|
||||||
schema = DomainBlocksResponse.schema()
|
|
||||||
assert_schema(schema.example, "DomainBlocksResponse", api_spec)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user