summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Freire <tcfonnet@gmail.com>2016-08-16 01:18:30 -0300
committerTiago Freire <code.tiago.frire@locaweb.com.br>2016-08-18 15:08:05 -0300
commit1db1adbf2d061848f78711c38678edd02250f923 (patch)
tree2932151e492855506a40c9e7af5b6e7583aa1903
parent[WIP] Init. (diff)
WIP
-rw-r--r--README.md10
-rw-r--r--config/config.exs4
-rw-r--r--lib/http_client.ex4
-rw-r--r--lib/powerdnsex.ex2
-rw-r--r--lib/powerdnsex/config.ex (renamed from lib/powerdnsx/config.ex)6
-rw-r--r--lib/powerdnsex/managers/records_manager.ex34
-rw-r--r--lib/powerdnsex/managers/zones_manager.ex46
-rw-r--r--lib/powerdnsex/models/error.ex3
-rw-r--r--lib/powerdnsex/models/record.ex27
-rw-r--r--lib/powerdnsex/models/resource_record_set.ex40
-rw-r--r--lib/powerdnsex/models/zone.ex28
-rw-r--r--lib/powerdnsx.ex2
-rw-r--r--lib/powerdnsx/managers/zones_manager.ex40
-rw-r--r--lib/powerdnsx/models/zone.ex25
-rw-r--r--lib/powerdnsx/validations/zone_validation.ex38
-rw-r--r--mix.exs4
-rw-r--r--mix.lock4
-rw-r--r--test/lib/powerdnsex/config_test.exs (renamed from test/lib/powerdnsx/config_test.exs)28
-rw-r--r--test/lib/powerdnsex/managers/records_manager_test.exs73
-rw-r--r--test/lib/powerdnsex/managers/zones_manager_test.exs102
-rw-r--r--test/lib/powerdnsex/models/zone_test.exs0
-rw-r--r--test/lib/powerdnsx/managers/zones_manager_test.exs80
-rw-r--r--test/lib/powerdnsx/models/zone_test.exs27
-rw-r--r--test/support/cassettes/records_manager/create/success.json30
-rw-r--r--test/support/cassettes/records_manager/update/success.json30
-rw-r--r--test/support/cassettes/zones_manager/create/invalid_not_canonical.json31
-rw-r--r--test/support/cassettes/zones_manager/create/success.json31
-rw-r--r--test/support/cassettes/zones_manager/create/valid_parameters.json1
-rw-r--r--test/support/cassettes/zones_manager/show/not_found.json31
-rw-r--r--test/support/cassettes/zones_manager/show/success.json31
-rw-r--r--test/support/cassettes/zones_manager/show/valid_record.json27
-rw-r--r--test/support/fake_config.exs9
32 files changed, 577 insertions, 271 deletions
diff --git a/README.md b/README.md
index 08ed556..18dee79 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# PowerDNSx
+# PowerDNSex
**TODO: Add description**
@@ -6,19 +6,19 @@
If [available in Hex](https://hex.pm/docs/publish), the package can be installed as:
- 1. Add `powerdnsx` to your list of dependencies in `mix.exs`:
+ 1. Add `powerdnsex` to your list of dependencies in `mix.exs`:
```elixir
def deps do
- [{:powerdnsx, "~> 0.1.0"}]
+ [{:powerdnsex, "~> 0.1.0"}]
end
```
- 2. Ensure `powerdnsx` is started before your application:
+ 2. Ensure `powerdnsex` is started before your application:
```elixir
def application do
- [applications: [:powerdnsx]]
+ [applications: [:powerdnsex]]
end
```
diff --git a/config/config.exs b/config/config.exs
index 2272984..4f2b23f 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -10,11 +10,11 @@ use Mix.Config
# You can configure for your application as:
#
-# config :powerdnsx, key: :value
+# config :powerdnsex, key: :value
#
# And access this configuration in your application as:
#
-# Application.get_env(:powerdnsx, :key)
+# Application.get_env(:powerdnsex, :key)
#
# Or configure a 3rd-party app:
#
diff --git a/lib/http_client.ex b/lib/http_client.ex
index d819087..6d18cbe 100644
--- a/lib/http_client.ex
+++ b/lib/http_client.ex
@@ -1,11 +1,11 @@
-defmodule PowerDNSx.HttpClient do
+defmodule PowerDNSex.HttpClient do
@moduledoc"""
Client to do http requests for PowerDns API
"""
use HTTPoison.Base
- alias PowerDNSx.Config
+ alias PowerDNSex.Config
def process_url(url) do
Config.powerdns_url <> url
diff --git a/lib/powerdnsex.ex b/lib/powerdnsex.ex
new file mode 100644
index 0000000..c82aa59
--- /dev/null
+++ b/lib/powerdnsex.ex
@@ -0,0 +1,2 @@
+defmodule PowerDNSex do
+end
diff --git a/lib/powerdnsx/config.ex b/lib/powerdnsex/config.ex
index d172fa9..50589d4 100644
--- a/lib/powerdnsx/config.ex
+++ b/lib/powerdnsex/config.ex
@@ -1,8 +1,8 @@
-defmodule PowerDNSx.Config do
+defmodule PowerDNSex.Config do
defstruct url: "",
token: ""
- alias PowerDNSx.Config
+ alias PowerDNSex.Config
def data do
set_attr_value = &(Map.put(&2, &1, get_key(&1)))
@@ -30,7 +30,7 @@ defmodule PowerDNSx.Config do
{:ok, {:system, env_var_name}} -> System.get_env(env_var_name)
{:ok, value} -> value
_ ->
- raise "[PowerDNSx] PowerDNS #{Atom.to_string(key)} not configured."
+ raise "[PowerDNSex] PowerDNS #{Atom.to_string(key)} not configured."
end
end
end
diff --git a/lib/powerdnsex/managers/records_manager.ex b/lib/powerdnsex/managers/records_manager.ex
new file mode 100644
index 0000000..f9e71e1
--- /dev/null
+++ b/lib/powerdnsex/managers/records_manager.ex
@@ -0,0 +1,34 @@
+defmodule PowerDNSex.RecordsManager do
+
+ alias PowerDNSex.HttpClient
+ alias PowerDNSex.Models.{Zone, Record, Error}
+ alias PowerDNSex.Models.ResourceRecordSet, as: RRset
+ alias HTTPoison.Response
+
+ def create(%Zone{url: nil}, _) do
+ raise "[Records Manager] Zone URL attribute is empty!"
+ end
+
+ def create(%Zone{} = zone, %{} = rrset_attrs) do
+ rrset_attrs = Map.merge(rrset_attrs, %{changetype: "REPLACE"})
+
+ zone.url
+ |> HttpClient.patch!(RRset.as_body(RRset.build(rrset_attrs)))
+ |> process_request_response
+ end
+
+ def update(%Zone{} = zone, %{} = rrset_attrs) do
+ create(zone, rrset_attrs)
+ end
+
+ ###
+ # Private
+ ##
+
+ defp process_request_response(%Response{body: body, status_code: status}) do
+ case status do
+ s when s < 300 -> :ok
+ s when s >= 300 -> body |> Poison.decode!(as: %Error{})
+ end
+ end
+end
diff --git a/lib/powerdnsex/managers/zones_manager.ex b/lib/powerdnsex/managers/zones_manager.ex
new file mode 100644
index 0000000..e511ac1
--- /dev/null
+++ b/lib/powerdnsex/managers/zones_manager.ex
@@ -0,0 +1,46 @@
+defmodule PowerDNSex.ZonesManager do
+
+ @default_server "localhost"
+
+ alias PowerDNSex.HttpClient
+ alias PowerDNSex.Models.{Zone, Error, ResourceRecordSet, Record}
+ alias HTTPoison.Response
+
+ def create(%Zone{} = zone, server_name \\ @default_server) do
+ zone_path(server_name)
+ |> HttpClient.post!(Zone.as_body(zone))
+ |> process_request_response
+ end
+
+ def show(zone_name, server_name \\ @default_server)
+ when is_bitstring(zone_name) do
+
+ zone_path(server_name, zone_name)
+ |> HttpClient.get!
+ |> process_request_response
+ end
+
+ ###
+ # Private
+ ###
+
+ defp zone_path(server_name) when is_bitstring(server_name) do
+ "api/v1/servers/#{server_name}/zones"
+ end
+
+ defp zone_path(server_name, zone_name) when is_bitstring(server_name) do
+ zone_path(server_name) <> "/#{zone_name}"
+ end
+
+ defp process_request_response(%Response{body: body, status_code: status}) do
+ case status do
+ s when s < 300 ->
+ body |> Poison.decode!(as: %Zone{rrsets: [
+ %ResourceRecordSet{
+ records: [%Record{}]
+ }]})
+ s when s >= 300 ->
+ body |> Poison.decode!(as: %Error{})
+ end
+ end
+end
diff --git a/lib/powerdnsex/models/error.ex b/lib/powerdnsex/models/error.ex
new file mode 100644
index 0000000..1cf9f62
--- /dev/null
+++ b/lib/powerdnsex/models/error.ex
@@ -0,0 +1,3 @@
+defmodule PowerDNSex.Models.Error do
+ defstruct [:error]
+end
diff --git a/lib/powerdnsex/models/record.ex b/lib/powerdnsex/models/record.ex
new file mode 100644
index 0000000..57378fc
--- /dev/null
+++ b/lib/powerdnsex/models/record.ex
@@ -0,0 +1,27 @@
+defmodule PowerDNSex.Models.Record do
+ defstruct [:content, :disabled]
+
+ def build(attrs) when is_list(attrs) do
+ Enum.reduce(attrs, [], &(&2 ++ [build(&1)]))
+ end
+
+ def build(attrs) when is_tuple(attrs) do
+ %__MODULE__{content: elem(attrs, 0), disabled: elem(attrs, 1)}
+ end
+
+ def build(attrs) when is_map(attrs) do
+ %__MODULE__{content: attrs.content, disabled: attrs.disabled}
+ end
+
+ def as_body(content) when is_list(content) do
+ Enum.reduce(content, [], &(&2 ++ [as_body(&1)]))
+ end
+
+ def as_body(%__MODULE__{} = record_attrs) do
+ Map.from_struct(record_attrs)
+ end
+
+ def as_body(record_attrs) when is_tuple(record_attrs) do
+ %{content: elem(record_attrs, 0), disabled: elem(record_attrs, 1)}
+ end
+end
diff --git a/lib/powerdnsex/models/resource_record_set.ex b/lib/powerdnsex/models/resource_record_set.ex
new file mode 100644
index 0000000..f4338a2
--- /dev/null
+++ b/lib/powerdnsex/models/resource_record_set.ex
@@ -0,0 +1,40 @@
+defmodule PowerDNSex.Models.ResourceRecordSet do
+
+ alias PowerDNSex.Models.Record
+
+ defstruct [:name, :type, :ttl, :records, :changetype]
+
+ def build(rrset_attrs) when is_map(rrset_attrs) do
+ rrset = %__MODULE__{}
+
+ rrset
+ |> Map.keys
+ |> Enum.reduce(rrset, &(set_attrs(&2, &1, rrset_attrs)))
+ end
+
+ def as_body(%__MODULE__{} = rrset) do
+ %{ rrsets: [
+ %{
+ name: rrset.name,
+ type: rrset.type,
+ ttl: rrset.ttl,
+ changetype: rrset.changetype,
+ records: Record.as_body(rrset.records)
+ }
+ ]}
+ |> Poison.encode!
+ end
+
+ defp set_attrs(rrset, attr_name, attrs) do
+ if Map.has_key?(attrs, attr_name) do
+ attr_value = case attr_name do
+ :records -> Record.build(Map.fetch!(attrs, attr_name))
+ _ -> Map.fetch!(attrs, attr_name)
+ end
+
+ %{ rrset | attr_name => attr_value }
+ else
+ rrset
+ end
+ end
+end
diff --git a/lib/powerdnsex/models/zone.ex b/lib/powerdnsex/models/zone.ex
new file mode 100644
index 0000000..62a5a2a
--- /dev/null
+++ b/lib/powerdnsex/models/zone.ex
@@ -0,0 +1,28 @@
+defmodule PowerDNSex.Models.Zone do
+ @moduledoc """
+ Model for PowerDns zones, create and validate format
+ """
+
+ @body_attrs ~w(account dns kind masters name nameservers records serial
+ soa_edit soa_edit_api)a
+
+ defstruct name: nil, kind: "Native", masters: [], nameservers: [], rrsets: [],
+ account: nil, comments: [], dnssec: false, id: nil, last_check: 0,
+ notified_serial: 0, serial: nil, soa_edit: "", soa_edit_api: "",
+ url: nil
+
+ def as_body(%__MODULE__{} = zone) do
+ get_valid_attrs = fn({attr, value}, body) ->
+ if Enum.member?(@body_attrs, attr) do
+ Map.merge(body, %{attr => value})
+ else
+ body
+ end
+ end
+
+ zone
+ |> Map.from_struct
+ |> Enum.reduce(%{}, get_valid_attrs)
+ |> Poison.encode!
+ end
+end
diff --git a/lib/powerdnsx.ex b/lib/powerdnsx.ex
deleted file mode 100644
index 711fde6..0000000
--- a/lib/powerdnsx.ex
+++ /dev/null
@@ -1,2 +0,0 @@
-defmodule PowerDNSx do
-end
diff --git a/lib/powerdnsx/managers/zones_manager.ex b/lib/powerdnsx/managers/zones_manager.ex
deleted file mode 100644
index 6e313d6..0000000
--- a/lib/powerdnsx/managers/zones_manager.ex
+++ /dev/null
@@ -1,40 +0,0 @@
-defmodule PowerDNSx.ZonesManager do
-
- @default_server "localhost"
-
- alias PowerDNSx.HttpClient
- alias HTTPoison.Response, as: PoisonResp
- alias PowerDNSx.Models.Zone
-
- def create(%Zone{} = zone, server_name \\ @default_server) do
- case Zone.is_valid?(zone) do
- true ->
- zone_path(server_name)
- |> HttpClient.post!(zone)
- |> process_request_response
- {false, errors} -> {:error, errors}
- end
- end
-
- def show(zone_name, server_name \\ @default_server) when is_bitstring(zone_name) do
- zone_path(server_name, zone_name)
- |> HttpClient.get!
- |> process_request_response
- end
-
- ###
- # Private
- ###
-
- defp zone_path(server_name) when is_bitstring(server_name) do
- "/servers/#{server_name}/zones"
- end
-
- defp zone_path(server_name, zone_name) when is_bitstring(server_name) do
- zone_path(server_name) <> "/#{zone_name}"
- end
-
- defp process_request_response(%PoisonResp{body: body, status_code: status} ) do
- body |> Poison.decode!(as: %Zone{})
- end
-end
diff --git a/lib/powerdnsx/models/zone.ex b/lib/powerdnsx/models/zone.ex
deleted file mode 100644
index b2a9249..0000000
--- a/lib/powerdnsx/models/zone.ex
+++ /dev/null
@@ -1,25 +0,0 @@
-defmodule PowerDNSx.Models.Zone do
- @moduledoc """
- Model for PowerDns zones, create and validate format
- """
-
- @valid_hostname_regex ~r/^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$/
-
- defstruct name: nil,
- kind: "Native",
- masters: [],
- nameservers: [],
- records: [],
- account: nil,
- comments: [],
- dnssec: false,
- id: nil,
- last_check: 0,
- notified_serial: 0,
- serial: nil,
- soa_edit: "",
- soa_edit_api: "",
- url: nil
-
-
-end
diff --git a/lib/powerdnsx/validations/zone_validation.ex b/lib/powerdnsx/validations/zone_validation.ex
deleted file mode 100644
index a2abc6e..0000000
--- a/lib/powerdnsx/validations/zone_validation.ex
+++ /dev/null
@@ -1,38 +0,0 @@
-defmodule PowerDNSx.ZoneValidator do
- alias PowerDNSx.Models.Zone
-
- @valid_zone_name_reg ~r/^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$/
-
- def check(%Zone{} = zone) do
- verify_attr = fn({attr, value}, errors)->
- validate_attr_value(attr, value)
- end
-
- errors = Enum.reduce(zone, nil, verify_attr)
- if errors, do: {:error, errors}, else: :ok
- end
-
- ###
- # Private
- ###
-
- defp validate_attr_value(:name, zone_name) do
- case validate_zone_name(zone_name) do
- {true, true} -> nil
- {false, _} -> {:error, %{name: "#{zone_name} is invalid."}}
- {_, false} -> {:error, %{name: "#{zone_name} is invalid. Max lenght is 64."}}
- {:format_error} -> {:error, %{name: "Name MUST be a string."}}
- end
- end
-
- defp validate_zone_name(zone_name) when is_bitstring(zone_name) do
- {String.match?(zone_name, @valid_zone_name_reg), correct_length?(zone_name)}
- end
-
- defp validate_zone_name(_), do: {:format_error}
-
- defp correct_length?(zone_name) do
- name = zone_name |> String.split(".") |> hd
- name |> String.length <= 63
- end
-end
diff --git a/mix.exs b/mix.exs
index b6069f5..88dc757 100644
--- a/mix.exs
+++ b/mix.exs
@@ -1,8 +1,8 @@
-defmodule PowerDNSx.Mixfile do
+defmodule PowerDNSex.Mixfile do
use Mix.Project
def project do
- [app: :powerdnsx,
+ [app: :powerdnsex,
version: "0.1.0",
elixir: "~> 1.3",
build_embedded: Mix.env == :prod,
diff --git a/mix.lock b/mix.lock
index 6e6118c..328bf04 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,8 +1,8 @@
%{"certifi": {:hex, :certifi, "0.4.0", "a7966efb868b179023618d29a407548f70c52466bf1849b9e8ebd0e34b7ea11f", [:rebar3], []},
"exactor": {:hex, :exactor, "2.2.0", "2a7418b82d974fe8276edd62c1facf4a9dc06339cdf11b5dcd10359e107fe5c3", [:mix], []},
"exjsx": {:hex, :exjsx, "3.2.0", "7136cc739ace295fc74c378f33699e5145bead4fdc1b4799822d0287489136fb", [:mix], [{:jsx, "~> 2.6.2", [hex: :jsx, optional: false]}]},
- "exvcr": {:hex, :exvcr, "0.8.0", "61b8da4723150938f612af8a2f885709af7e486e4deac4b454a161de3430e699", [:mix], [{:httpoison, "~> 0.8", [hex: :httpoison, optional: true]}, {:httpotion, "~> 3.0", [hex: :httpotion, optional: true]}, {:ibrowse, "~> 4.2.2", [hex: :ibrowse, optional: true]}, {:exjsx, "~> 3.2", [hex: :exjsx, optional: false]}, {:exactor, "~> 2.2", [hex: :exactor, optional: false]}, {:meck, "~> 0.8.3", [hex: :meck, optional: false]}]},
- "hackney": {:hex, :hackney, "1.6.0", "8d1e9440c9edf23bf5e5e2fe0c71de03eb265103b72901337394c840eec679ac", [:rebar3], [{:ssl_verify_fun, "1.1.0", [hex: :ssl_verify_fun, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:idna, "1.2.0", [hex: :idna, optional: false]}, {:certifi, "0.4.0", [hex: :certifi, optional: false]}]},
+ "exvcr": {:hex, :exvcr, "0.8.0", "61b8da4723150938f612af8a2f885709af7e486e4deac4b454a161de3430e699", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, optional: false]}, {:exjsx, "~> 3.2", [hex: :exjsx, optional: false]}, {:httpoison, "~> 0.8", [hex: :httpoison, optional: true]}, {:httpotion, "~> 3.0", [hex: :httpotion, optional: true]}, {:ibrowse, "~> 4.2.2", [hex: :ibrowse, optional: true]}, {:meck, "~> 0.8.3", [hex: :meck, optional: false]}]},
+ "hackney": {:hex, :hackney, "1.6.0", "8d1e9440c9edf23bf5e5e2fe0c71de03eb265103b72901337394c840eec679ac", [:rebar3], [{:certifi, "0.4.0", [hex: :certifi, optional: false]}, {:idna, "1.2.0", [hex: :idna, optional: false]}, {:metrics, "1.0.1", [hex: :metrics, optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, optional: false]}, {:ssl_verify_fun, "1.1.0", [hex: :ssl_verify_fun, optional: false]}]},
"httpoison": {:hex, :httpoison, "0.9.0", "68187a2daddfabbe7ca8f7d75ef227f89f0e1507f7eecb67e4536b3c516faddb", [:mix], [{:hackney, "~> 1.6.0", [hex: :hackney, optional: false]}]},
"idna": {:hex, :idna, "1.2.0", "ac62ee99da068f43c50dc69acf700e03a62a348360126260e87f2b54eced86b2", [:rebar3], []},
"jsx": {:hex, :jsx, "2.6.2", "213721e058da0587a4bce3cc8a00ff6684ced229c8f9223245c6ff2c88fbaa5a", [:mix, :rebar], []},
diff --git a/test/lib/powerdnsx/config_test.exs b/test/lib/powerdnsex/config_test.exs
index 4a9a732..adb212a 100644
--- a/test/lib/powerdnsx/config_test.exs
+++ b/test/lib/powerdnsex/config_test.exs
@@ -1,55 +1,59 @@
-defmodule PowerDNSx.ConfigTest do
+defmodule PowerDNSex.ConfigTest do
use ExUnit.Case, async: true
- alias PowerDNSx.FakeConfig, as: Config
+ alias PowerDNSex.FakeConfig, as: Config
setup with_valid_url, do: Config.set_url
setup with_valid_token, do: Config.set_token
setup with_valid_token_and_url, do: Config.set_url && Config.set_token
describe "Config.powerdns_token/0" do
+ @tag :configs
test "Using Env vars", with_valid_url do
env_token = "3nv_S3cr37_T0k3n"
System.put_env("POWERDNS_TOKEN", env_token)
Application.put_env(:powerdns, :token, {:system, "POWERDNS_TOKEN"})
- assert PowerDNSx.Config.powerdns_token == env_token
+ assert PowerDNSex.Config.powerdns_token == env_token
end
+ @tag :configs
test "using application config", with_valid_token_and_url do
- assert PowerDNSx.Config.powerdns_token == "4pp_S3cr37_T0k3n"
+ assert PowerDNSex.Config.powerdns_token == Config.token
end
+ @tag :configs
test "given none token config", with_valid_url do
Application.delete_env(:powerdns, :token)
- expected_error = "[PowerDNSx] PowerDNS token not configured."
+ expected_error = "[PowerDNSex] PowerDNS token not configured."
assert_raise RuntimeError, expected_error, fn ->
- PowerDNSx.Config.powerdns_token
+ PowerDNSex.Config.powerdns_token
end
end
end
describe "Config.powerdns_url/0" do
+ @tag :configs
test "Using Env vars", with_valid_token do
env_url = "https://env-powerdns.test"
System.put_env("POWERDNS_URL", env_url)
Application.put_env(:powerdns, :url, {:system, "POWERDNS_URL"})
- assert PowerDNSx.Config.powerdns_url == env_url
+ assert PowerDNSex.Config.powerdns_url == env_url
end
+ @tag :configs
test "using application config", with_valid_token_and_url do
- assert PowerDNSx.Config.powerdns_url == "https://app-config-powerdns.test"
+ assert PowerDNSex.Config.powerdns_url == Config.url
end
+ @tag :configs
test "given none url config", with_valid_token do
Application.delete_env(:powerdns, :url)
- expected_error = "[PowerDNSx] PowerDNS url not configured."
+ expected_error = "[PowerDNSex] PowerDNS url not configured."
assert_raise RuntimeError, expected_error, fn ->
- PowerDNSx.Config.powerdns_url
+ PowerDNSex.Config.powerdns_url
end
end
end
-
-
end
diff --git a/test/lib/powerdnsex/managers/records_manager_test.exs b/test/lib/powerdnsex/managers/records_manager_test.exs
new file mode 100644
index 0000000..3b91fc2
--- /dev/null
+++ b/test/lib/powerdnsex/managers/records_manager_test.exs
@@ -0,0 +1,73 @@
+defmodule PowerDNSex.RecordsManagerTest do
+
+ use ExUnit.Case, async: false
+ use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
+
+ alias PowerDNSex.Models.{Zone, ResourceRecordSet, Record}
+ alias PowerDNSex.RecordsManager
+
+ @valid_zone %Zone{name: "my-domain.art.",
+ url: "api/v1/servers/localhost/zones/my-domain.art."}
+ @new_record %{
+ name: "new-record.my-domain.art.",
+ type: "A",
+ ttl: 86400,
+ records: [
+ {"127.0.0.1", false},
+ {"192.168.0.1", true}
+ ]
+ }
+
+ @updated_record %{
+ name: "updated-record.my-domain.art.",
+ type: "A",
+ ttl: 86800,
+ records: [{"127.0.0.1", true}]
+ }
+
+ setup do
+ # Config.set_url
+ # Config.set_token
+
+ pwdns_url_loca = "http://cpro36999.systemintegration.locaweb.com.br/"
+ Application.put_env(:powerdns, :url, pwdns_url_loca)
+
+ pwdns_token_loca = "Locaweb2016"
+ Application.put_env(:powerdns, :token, pwdns_token_loca)
+
+ ExVCR.Config.cassette_library_dir("test/support/cassettes",
+ "test/support/custom_cassettes")
+ HTTPoison.start
+ end
+
+ describe "create/2" do
+ test "exception given empty zones url" do
+ raise_msg = "[Records Manager] Zone URL attribute is empty!"
+ assert_raise RuntimeError, raise_msg, fn() ->
+ RecordsManager.create(%Zone{}, %Record{})
+ end
+ end
+
+ test "content and value of the return given correct params" do
+ use_cassette "records_manager/create/success" do
+ assert RecordsManager.create(@valid_zone, @new_record) == :ok
+ end
+ end
+ end
+
+ describe "update/2" do
+ @tag :records_manager_update
+ test "exception given empty zones url" do
+ raise_msg = "[Records Manager] Zone URL attribute is empty!"
+ assert_raise RuntimeError, raise_msg, fn() ->
+ RecordsManager.update(%Zone{}, %Record{})
+ end
+ end
+
+ test "the return given correct params" do
+ use_cassette "records_manager/update/success" do
+ assert RecordsManager.update(@valid_zone, @updated_record) == :ok
+ end
+ end
+ end
+end
diff --git a/test/lib/powerdnsex/managers/zones_manager_test.exs b/test/lib/powerdnsex/managers/zones_manager_test.exs
new file mode 100644
index 0000000..42bace0
--- /dev/null
+++ b/test/lib/powerdnsex/managers/zones_manager_test.exs
@@ -0,0 +1,102 @@
+defmodule PowerDNSex.ZonesManagerTest do
+
+ use ExUnit.Case, async: false
+ use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
+
+ alias PowerDNSex.ZonesManager
+ alias PowerDNSex.Models.{Zone, Record}
+ alias PowerDNSex.Models.ResourceRecordSet, as: RRSet
+ alias PowerDNSex.FakeConfig, as: Config
+
+ @invalid_not_canonical %Zone{name: "not-canonical-domain.tst"}
+ @unknown_name "it-will-never-exist.on.the.art."
+
+ @valid_zone_test %Zone{name: "my-domain.art.",
+ serial: 2016060601,
+ comments: ["Test comment"] }
+
+ @expected_rrset [
+ %RRSet{
+ name: "my-domain.art.",
+ ttl: 3600,
+ type: "SOA",
+ records: [
+ %Record{content: "a.misconfigured.powerdns.server. " <>
+ "hostmaster.my-domain.art. " <>
+ "2016060601 10800 3600 604800 3600",
+ disabled: false}
+ ]
+ }
+ ]
+
+ @expected_zone %Zone{name: "my-domain.art.",
+ id: "my-domain.art.",
+ account: "",
+ serial: 2016060601,
+ url: "api/v1/servers/localhost/zones/my-domain.art.",
+ rrsets: @expected_rrset}
+
+ setup do
+ # Config.set_url
+ # Config.set_token
+
+ pwdns_url_loca = "http://cpro36999.systemintegration.locaweb.com.br/"
+ Application.put_env(:powerdns, :url, pwdns_url_loca)
+
+ pwdns_token_loca = "Locaweb2016"
+ Application.put_env(:powerdns, :token, pwdns_token_loca)
+
+ ExVCR.Config.cassette_library_dir("test/support/cassettes",
+ "test/support/custom_cassettes")
+ HTTPoison.start
+ end
+
+ describe "ZoneManager.create/2" do
+ @tag :zones_manager_create
+ test "return given correct parameters" do
+ use_cassette "zones_manager/create/success" do
+ zone = ZonesManager.create(@valid_zone_test)
+ assert zone.__struct__ == PowerDNSex.Models.Zone
+ assert zone.name == @valid_zone_test.name
+ end
+ end
+
+ @tag :zones_manager_create
+ test "return error given invalid name" do
+ use_cassette "zones_manager/create/invalid_not_canonical" do
+ error_msg = "DNS Name 'not-canonical-domain.tst' is not canonical"
+ response = ZonesManager.create(@invalid_not_canonical)
+ assert response.__struct__ == PowerDNSex.Models.Error
+ assert response.error == error_msg
+ end
+ end
+ end
+
+ describe "ZonesManager.show/2" do
+ @tag :zones_manager_show
+ test "type of return given a correct zone name" do
+ use_cassette "zones_manager/show/success" do
+ zone = ZonesManager.show(@valid_zone_test.name)
+ assert zone.__struct__ == PowerDNSex.Models.Zone
+ end
+ end
+
+ @tag :zones_manager_show
+ test "values in return given a correct zone name" do
+ use_cassette "zones_manager/show/success" do
+ zone = ZonesManager.show(@valid_zone_test.name)
+ assert zone == @expected_zone
+ end
+ end
+
+ @tag :zones_manager_show
+ test "values in return given a unknown zone name" do
+ use_cassette "zones_manager/show/not_found" do
+ error_msg = "Could not find domain 'it-will-never-exist.on.the.art.'"
+ response = ZonesManager.show(@unknown_name)
+ assert response.__struct__ == PowerDNSex.Models.Error
+ assert response.error == error_msg
+ end
+ end
+ end
+end
diff --git a/test/lib/powerdnsex/models/zone_test.exs b/test/lib/powerdnsex/models/zone_test.exs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/lib/powerdnsex/models/zone_test.exs
diff --git a/test/lib/powerdnsx/managers/zones_manager_test.exs b/test/lib/powerdnsx/managers/zones_manager_test.exs
deleted file mode 100644
index cc793d0..0000000
--- a/test/lib/powerdnsx/managers/zones_manager_test.exs
+++ /dev/null
@@ -1,80 +0,0 @@
-defmodule PowerDNSx.ZonesManagerTest do
-
- use ExUnit.Case, async: true
- use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
-
- alias PowerDNSx.ZonesManager
- alias PowerDNSx.Models.Zone
- alias PowerDNSx.FakeConfig, as: Config
-
- @valid_zone_loca %Zone{name: "devtiagofreire.art.br"}
-
- @valid_zone_test %Zone{name: "my-domain.tst",
- serial: 2016060601,
- comments: ["Test comment"] }
-
- @expected_records [
- %{"content" => "ns2.my-powerdns.api", "disabled" => false,
- "name" => "my-domain.tst", "ttl" => 3600, "type" => "NS"},
- %{"content" => "ns1.my-powerdns.api", "disabled" => false,
- "name" => "my-domain.tst", "ttl" => 3600, "type" => "NS"},
- %{"content" => "a.misconfigured.powerdns.server " <>
- "hostmaster.my-domain.tst " <>
- "2016060601 10800 3600 604800 3600",
- "disabled" => false, "name" => "my-domain.tst", "ttl" => 3600,
- "type" => "SOA"}
- ]
-
- @expected_zone %Zone{name: "my-domain.tst",
- id: "my-domain.tst.",
- account: "",
- serial: 2016060601,
- url: "/servers/localhost/zones/my-domain.tst.",
- records: @expected_records}
-
- setup_all do
- #Config.set_url
- #Config.set_token
-
- pwdns_url_loca = "http://cpro36999.systemintegration.locaweb.com.br"
- pwdns_url_test = "http://my-powerdns.api"
- Application.put_env(:powerdns, :url, pwdns_url_test)
-
- pwdns_token_loca = "Locaweb2016"
- pwdns_token_test = "S3cr3t-T0k3n"
- Application.put_env(:powerdns, :token, pwdns_token_test)
-
- ExVCR.Config.cassette_library_dir("test/support/cassettes",
- "test/support/custom_cassettes")
- HTTPoison.start
- end
-
- describe "ZoneManager.create/2" do
- @tag :zones_manager_create
- test "type of return given correct parameters" do
- use_cassette "zones_manager/create/valid_parameters" do
- zone = ZonesManager.create(@valid_zone_test)
- assert zone.__struct__ == PowerDNSx.Models.Zone
- end
- end
- end
-
- describe "ZonesManager.show/2" do
- @tag :zones_manager_show
- test "type of return given a correct zone name" do
- use_cassette "zones_manager/show/valid_record" do
- zone = ZonesManager.show(@valid_zone_test.name)
- assert zone.__struct__ == PowerDNSx.Models.Zone
- end
- end
-
- @tag :zones_manager_show
- test "values in return given a correct zone name" do
- use_cassette "zones_manager/show/valid_record" do
- zone = ZonesManager.show(@valid_zone_test.name)
- assert zone == @expected_zone
- end
- end
- end
-
-end
diff --git a/test/lib/powerdnsx/models/zone_test.exs b/test/lib/powerdnsx/models/zone_test.exs
deleted file mode 100644
index 8a61602..0000000
--- a/test/lib/powerdnsx/models/zone_test.exs
+++ /dev/null
@@ -1,27 +0,0 @@
-# defmodule PowerDNSx.Models.ZoneTest do
-#
-# use ExUnit.Case, async: true
-#
-# alias PowerDNSx.Models.Zone
-#
-# describe "Zone.build/1" do
-# test "build zone with all attributes" do
-# ns_servers = ["ns1.powerdnsx.tst", "ns2.powerdnsx.tst"]
-#
-# zone_params = %{id: nil,
-# name: "test.tst",
-# nameservers: ns_servers,
-# account: "pdnaccount",
-# kind: "Native",
-# masters: [],
-# records: [],
-# serial: nil,
-# comments: [],
-# soa_edit: nil,
-# soa_edit_api: nil}
-#
-# zone_built = Zone.build(zone_params)
-# assert zone_params === Map.from_struct(zone_built)
-# end
-# end
-# end
diff --git a/test/support/cassettes/records_manager/create/success.json b/test/support/cassettes/records_manager/create/success.json
new file mode 100644
index 0000000..73bdc22
--- /dev/null
+++ b/test/support/cassettes/records_manager/create/success.json
@@ -0,0 +1,30 @@
+[
+ {
+ "request": {
+ "body": "{\"rrsets\":[{\"type\":\"A\",\"ttl\":86400,\"records\":[{\"disabled\":false,\"content\":\"127.0.0.1\"},{\"disabled\":true,\"content\":\"192.168.0.1\"}],\"name\":\"new-record.my-domain.art.\",\"changetype\":\"REPLACE\"}]}",
+ "headers": {
+ "X-API-Key": "Locaweb2016"
+ },
+ "method": "patch",
+ "options": [],
+ "request_body": "",
+ "url": "http://cpro36999.systemintegration.locaweb.com.br/api/v1/servers/localhost/zones/my-domain.art."
+ },
+ "response": {
+ "body": "",
+ "headers": {
+ "Access-Control-Allow-Origin": "*",
+ "Connection": "close",
+ "Content-Length": "0",
+ "Content-Security-Policy": "default-src 'self'; style-src 'self' 'unsafe-inline'",
+ "Server": "PowerDNS/4.0.1",
+ "X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "deny",
+ "X-Permitted-Cross-Domain-Policies": "none",
+ "X-Xss-Protection": "1; mode=block"
+ },
+ "status_code": 204,
+ "type": "ok"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/support/cassettes/records_manager/update/success.json b/test/support/cassettes/records_manager/update/success.json
new file mode 100644
index 0000000..d6a5112
--- /dev/null
+++ b/test/support/cassettes/records_manager/update/success.json
@@ -0,0 +1,30 @@
+[
+ {
+ "request": {
+ "body": "{\"rrsets\":[{\"type\":\"A\",\"ttl\":86800,\"records\":[{\"disabled\":true,\"content\":\"127.0.0.1\"}],\"name\":\"updated-record.my-domain.art.\",\"changetype\":\"REPLACE\"}]}",
+ "headers": {
+ "X-API-Key": "Locaweb2016"
+ },
+ "method": "patch",
+ "options": [],
+ "request_body": "",
+ "url": "http://cpro36999.systemintegration.locaweb.com.br/api/v1/servers/localhost/zones/my-domain.art."
+ },
+ "response": {
+ "body": "",
+ "headers": {
+ "Access-Control-Allow-Origin": "*",
+ "Connection": "close",
+ "Content-Length": "0",
+ "Content-Security-Policy": "default-src 'self'; style-src 'self' 'unsafe-inline'",
+ "Server": "PowerDNS/4.0.1",
+ "X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "deny",
+ "X-Permitted-Cross-Domain-Policies": "none",
+ "X-Xss-Protection": "1; mode=block"
+ },
+ "status_code": 204,
+ "type": "ok"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/support/cassettes/zones_manager/create/invalid_not_canonical.json b/test/support/cassettes/zones_manager/create/invalid_not_canonical.json
new file mode 100644
index 0000000..353115d
--- /dev/null
+++ b/test/support/cassettes/zones_manager/create/invalid_not_canonical.json
@@ -0,0 +1,31 @@
+[
+ {
+ "request": {
+ "body": "{\"soa_edit_api\":\"\",\"soa_edit\":\"\",\"serial\":2016060601,\"records\":[],\"nameservers\":[],\"name\":\"not-canonical-domain.tst\",\"masters\":[],\"kind\":\"Native\",\"account\":null}",
+ "headers": {
+ "X-API-Key": "Locaweb2016"
+ },
+ "method": "post",
+ "options": [],
+ "request_body": "",
+ "url": "http://cpro36999.systemintegration.locaweb.com.br/api/v1/servers/localhost/zones"
+ },
+ "response": {
+ "body": "{\"error\": \"DNS Name 'not-canonical-domain.tst' is not canonical\"}",
+ "headers": {
+ "Access-Control-Allow-Origin": "*",
+ "Connection": "close",
+ "Content-Length": "54",
+ "Content-Security-Policy": "default-src 'self'; style-src 'self' 'unsafe-inline'",
+ "Content-Type": "application/json",
+ "Server": "PowerDNS/4.0.1",
+ "X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "deny",
+ "X-Permitted-Cross-Domain-Policies": "none",
+ "X-Xss-Protection": "1; mode=block"
+ },
+ "status_code": 422,
+ "type": "ok"
+ }
+ }
+]
diff --git a/test/support/cassettes/zones_manager/create/success.json b/test/support/cassettes/zones_manager/create/success.json
new file mode 100644
index 0000000..e7880c8
--- /dev/null
+++ b/test/support/cassettes/zones_manager/create/success.json
@@ -0,0 +1,31 @@
+[
+ {
+ "request": {
+ "body": "{\"soa_edit_api\":\"\",\"soa_edit\":\"\",\"serial\":2016060601,\"records\":[],\"nameservers\":[],\"name\":\"my-domain.art.\",\"masters\":[],\"kind\":\"Native\",\"account\":null}",
+ "headers": {
+ "X-API-Key": "Locaweb2016"
+ },
+ "method": "post",
+ "options": [],
+ "request_body": "",
+ "url": "http://cpro36999.systemintegration.locaweb.com.br/api/v1/servers/localhost/zones"
+ },
+ "response": {
+ "body": "{\"account\": \"\", \"dnssec\": false, \"id\": \"my-domain.art.\", \"kind\": \"Native\", \"last_check\": 0, \"masters\": [], \"name\": \"my-domain.art.\", \"notified_serial\": 0, \"rrsets\": [{\"comments\": [], \"name\": \"my-domain.art.\", \"records\": [{\"content\": \"a.misconfigured.powerdns.server. hostmaster.my-domain.art. 2016060601 10800 3600 604800 3600\", \"disabled\": false}], \"ttl\": 3600, \"type\": \"SOA\"}], \"serial\": 2016060601, \"soa_edit\": \"\", \"soa_edit_api\": \"\", \"url\": \"api/v1/servers/localhost/zones/my-domain.art.\"}",
+ "headers": {
+ "Access-Control-Allow-Origin": "*",
+ "Connection": "close",
+ "Content-Length": "493",
+ "Content-Security-Policy": "default-src 'self'; style-src 'self' 'unsafe-inline'",
+ "Content-Type": "application/json",
+ "Server": "PowerDNS/4.0.1",
+ "X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "deny",
+ "X-Permitted-Cross-Domain-Policies": "none",
+ "X-Xss-Protection": "1; mode=block"
+ },
+ "status_code": 201,
+ "type": "ok"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/support/cassettes/zones_manager/create/valid_parameters.json b/test/support/cassettes/zones_manager/create/valid_parameters.json
deleted file mode 100644
index 0637a08..0000000
--- a/test/support/cassettes/zones_manager/create/valid_parameters.json
+++ /dev/null
@@ -1 +0,0 @@
-[] \ No newline at end of file
diff --git a/test/support/cassettes/zones_manager/show/not_found.json b/test/support/cassettes/zones_manager/show/not_found.json
new file mode 100644
index 0000000..a989d91
--- /dev/null
+++ b/test/support/cassettes/zones_manager/show/not_found.json
@@ -0,0 +1,31 @@
+[
+ {
+ "request": {
+ "body": "",
+ "headers": {
+ "X-API-Key": "Locaweb2016"
+ },
+ "method": "get",
+ "options": [],
+ "request_body": "",
+ "url": "http://cpro36999.systemintegration.locaweb.com.br/api/v1/servers/localhost/zones/it-will-never-exist.on.the.art."
+ },
+ "response": {
+ "body": "{\"error\": \"Could not find domain 'it-will-never-exist.on.the.art.'\"}",
+ "headers": {
+ "Access-Control-Allow-Origin": "*",
+ "Connection": "close",
+ "Content-Length": "68",
+ "Content-Security-Policy": "default-src 'self'; style-src 'self' 'unsafe-inline'",
+ "Content-Type": "application/json",
+ "Server": "PowerDNS/4.0.1",
+ "X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "deny",
+ "X-Permitted-Cross-Domain-Policies": "none",
+ "X-Xss-Protection": "1; mode=block"
+ },
+ "status_code": 422,
+ "type": "ok"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/support/cassettes/zones_manager/show/success.json b/test/support/cassettes/zones_manager/show/success.json
new file mode 100644
index 0000000..8f9a935
--- /dev/null
+++ b/test/support/cassettes/zones_manager/show/success.json
@@ -0,0 +1,31 @@
+[
+ {
+ "request": {
+ "body": "",
+ "headers": {
+ "X-API-Key": "Locaweb2016"
+ },
+ "method": "get",
+ "options": [],
+ "request_body": "",
+ "url": "http://cpro36999.systemintegration.locaweb.com.br/api/v1/servers/localhost/zones/my-domain.art."
+ },
+ "response": {
+ "body": "{\"account\": \"\", \"dnssec\": false, \"id\": \"my-domain.art.\", \"kind\": \"Native\", \"last_check\": 0, \"masters\": [], \"name\": \"my-domain.art.\", \"notified_serial\": 0, \"rrsets\": [{\"comments\": [], \"name\": \"my-domain.art.\", \"records\": [{\"content\": \"a.misconfigured.powerdns.server. hostmaster.my-domain.art. 2016060601 10800 3600 604800 3600\", \"disabled\": false}], \"ttl\": 3600, \"type\": \"SOA\"}], \"serial\": 2016060601, \"soa_edit\": \"\", \"soa_edit_api\": \"\", \"url\": \"api/v1/servers/localhost/zones/my-domain.art.\"}",
+ "headers": {
+ "Access-Control-Allow-Origin": "*",
+ "Connection": "close",
+ "Content-Length": "493",
+ "Content-Security-Policy": "default-src 'self'; style-src 'self' 'unsafe-inline'",
+ "Content-Type": "application/json",
+ "Server": "PowerDNS/4.0.1",
+ "X-Content-Type-Options": "nosniff",
+ "X-Frame-Options": "deny",
+ "X-Permitted-Cross-Domain-Policies": "none",
+ "X-Xss-Protection": "1; mode=block"
+ },
+ "status_code": 200,
+ "type": "ok"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/support/cassettes/zones_manager/show/valid_record.json b/test/support/cassettes/zones_manager/show/valid_record.json
deleted file mode 100644
index 75d348d..0000000
--- a/test/support/cassettes/zones_manager/show/valid_record.json
+++ /dev/null
@@ -1,27 +0,0 @@
-[
- {
- "request": {
- "body": "",
- "headers": {
- "X-API-Key": "S3cr3t-T0k3n"
- },
- "method": "get",
- "options": [],
- "request_body": "",
- "url": "http://my-powerdns.api/servers/localhost/zones/my-domain.tst"
- },
- "response": {
- "body": "{\"id\":\"my-domain.tst.\",\"url\":\"/servers/localhost/zones/my-domain.tst.\",\"name\":\"my-domain.tst\",\"kind\":\"Native\",\"dnssec\":false,\"account\":\"\",\"masters\":[],\"serial\":2016060601,\"notified_serial\":0,\"last_check\":0,\"soa_edit_api\":\"\",\"soa_edit\":\"\",\"records\":[{\"name\":\"my-domain.tst\",\"type\":\"NS\",\"ttl\":3600,\"disabled\":false,\"content\":\"ns2.my-powerdns.api\"},{\"name\":\"my-domain.tst\",\"type\":\"NS\",\"ttl\":3600,\"disabled\":false,\"content\":\"ns1.my-powerdns.api\"},{\"name\":\"my-domain.tst\",\"type\":\"SOA\",\"ttl\":3600,\"disabled\":false,\"content\":\"a.misconfigured.powerdns.server hostmaster.my-domain.tst 2016060601 10800 3600 604800 3600\"}],\"comments\":[]}",
- "headers": {
- "Transfer-Encoding": "chunked",
- "Access-Control-Allow-Origin": "*",
- "Connection": "close",
- "Content-Length": "717",
- "Content-Type": "application/json",
- "Server": "PowerDNS/3.4.8"
- },
- "status_code": 200,
- "type": "ok"
- }
- }
-]
diff --git a/test/support/fake_config.exs b/test/support/fake_config.exs
index e624d8e..9f95fc2 100644
--- a/test/support/fake_config.exs
+++ b/test/support/fake_config.exs
@@ -1,8 +1,11 @@
-defmodule PowerDNSx.FakeConfig do
- @app_config_token "4pp_S3cr37_T0k3n"
- @app_config_url "https://app-config-powerdns.test"
+defmodule PowerDNSex.FakeConfig do
+ @app_config_token "S3cr37_70k3n"
+ @app_config_url "https://my-powerdns.api"
def set_url, do: Application.put_env(:powerdns, :url, @app_config_url)
def set_token, do: Application.put_env(:powerdns, :token, @app_config_token)
+
+ def token, do: @app_config_token
+ def url, do: @app_config_url
end