Skip to content

Commit

Permalink
feat: Add Metrics.set/1 resource action (#5)
Browse files Browse the repository at this point in the history
Also adds `Metrics.flush/0` and resource action param validation.
  • Loading branch information
jaredhoyt authored Aug 23, 2024
1 parent 7126284 commit fd81391
Show file tree
Hide file tree
Showing 12 changed files with 274 additions and 0 deletions.
2 changes: 2 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Config

config :kickplan, :base_url, "https://demo-control.fly.dev/api"

if File.exists?("config/config.secret.exs") do
import_config "config.secret.exs"
end
22 changes: 22 additions & 0 deletions lib/kickplan/requests/metrics/set.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule Kickplan.Requests.Metrics.Set do
@moduledoc """
TODO
"""

@options NimbleOptions.new!(
key: [
type: :string,
required: true
],
value: [
type: {:or, [:float, :integer]},
required: true
],
account_key: [type: :string],
idempotency_key: [type: :string],
time: [type: :any]
)

@doc false
def options, do: @options
end
30 changes: 30 additions & 0 deletions lib/kickplan/resource/metrics.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule Kickplan.Metrics do
@moduledoc """
TODO
"""

alias Kickplan.{Client, Requests}

@doc """
TODO
"""
def flush do
with {:ok, resp} <- Client.post("metrics/flush") do
{:ok, resp.success?}
end
end

@doc """
TODO
"""
def set(opts \\ %{}) do
with {:ok, params} <- validate(opts, Requests.Metrics.Set),
{:ok, resp} <- Client.post("metrics/set", params) do
{:ok, resp.success?}
end
end

defp validate(opts, request) do
NimbleOptions.validate(opts, request.options())
end
end
2 changes: 2 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ defmodule Kickplan.MixProject do

defp deps do
[
{:exvcr, "~> 0.11", only: :test},
{:finch, "~> 0.6", optional: true},
{:hackney, "~> 1.9", optional: true},
{:jason, "~> 1.0", optional: true},
Expand All @@ -36,6 +37,7 @@ defmodule Kickplan.MixProject do
{:ex_doc, ">= 0.0.0", only: [:dev], runtime: false},
{:gettext, ">= 0.0.0", only: [:dev], runtime: false},
{:mix_audit, ">= 0.0.0", only: [:dev], runtime: false},
{:nimble_options, "~> 1.1.0"},
{:sobelow, ">= 0.0.0", only: [:dev], runtime: false}
]
end
Expand Down
5 changes: 5 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,21 @@
"ex_check": {:hex, :ex_check, "0.14.0", "d6fbe0bcc51cf38fea276f5bc2af0c9ae0a2bb059f602f8de88709421dae4f0e", [:mix], [], "hexpm", "8a602e98c66e6a4be3a639321f1f545292042f290f91fa942a285888c6868af0"},
"ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"},
"expo": {:hex, :expo, "1.0.0", "647639267e088717232f4d4451526e7a9de31a3402af7fcbda09b27e9a10395a", [:mix], [], "hexpm", "18d2093d344d97678e8a331ca0391e85d29816f9664a25653fd7e6166827827c"},
"exactor": {:hex, :exactor, "2.2.4", "5efb4ddeb2c48d9a1d7c9b465a6fffdd82300eb9618ece5d34c3334d5d7245b1", [:mix], [], "hexpm", "1222419f706e01bfa1095aec9acf6421367dcfab798a6f67c54cf784733cd6b5"},
"exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"},
"exvcr": {:hex, :exvcr, "0.15.1", "772db4d065f5136c6a984c302799a79e4ade3e52701c95425fa2229dd6426886", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:finch, "~> 0.16", [hex: :finch, repo: "hexpm", optional: true]}, {:httpoison, "~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "de4fc18b1d672d9b72bc7468735e19779aa50ea963a1f859ef82cd9e294b13e3"},
"file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"},
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"},
"gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
"hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"},
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
Expand Down
34 changes: 34 additions & 0 deletions test/cassettes/features/resolve-all.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[
{
"request": {
"options": {
"with_body": "true"
},
"body": "{}",
"url": "https://demo-control.fly.dev/api/features/",
"headers": {
"Authorization": "***",
"Content-Type": "application/json",
"User-Agent": "Kickplan/0.1.0 (sdk-elixir)"
},
"method": "post",
"request_body": ""
},
"response": {
"binary": false,
"type": "ok",
"body": "[{\"value\":false,\"key\":\"upload-contacts\"},{\"value\":false,\"key\":\"ai-llm-generation\"},{\"value\":false,\"key\":\"fancy\"},{\"value\":\"{\\n \\\"Currency\\\": \\\"US Dollar (USD)\\\",\\n \\\"Allowed Payment Gateways\\\": [\\\"PayPal\\\", \\\"Stripe\\\", \\\"Square\\\"]\\n }\",\"key\":\"payment-configuration\"},{\"value\":0,\"key\":\"contact-limit\"}]",
"headers": {
"cache-control": "max-age=0, private, must-revalidate",
"content-length": "308",
"content-type": "application/json; charset=utf-8",
"date": "Thu, 22 Aug 2024 19:19:14 GMT",
"server": "Fly/5e55b43a7 (2024-08-21)",
"x-request-id": "F-4jJk91UgTYSXkAAAyB",
"via": "1.1 fly.io",
"fly-request-id": "01J5XREQJRTKHBC3Y5CJQAPDYK-sea"
},
"status_code": 200
}
}
]
34 changes: 34 additions & 0 deletions test/cassettes/features/resolve.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[
{
"request": {
"options": {
"with_body": "true"
},
"body": "{}",
"url": "https://demo-control.fly.dev/api/features/contact-limit",
"headers": {
"Authorization": "***",
"Content-Type": "application/json",
"User-Agent": "Kickplan/0.1.0 (sdk-elixir)"
},
"method": "post",
"request_body": ""
},
"response": {
"binary": false,
"type": "ok",
"body": "{\"value\":0,\"key\":\"contact-limit\"}",
"headers": {
"cache-control": "max-age=0, private, must-revalidate",
"content-length": "33",
"content-type": "application/json; charset=utf-8",
"date": "Thu, 22 Aug 2024 19:43:57 GMT",
"server": "Fly/5e55b43a7 (2024-08-21)",
"x-request-id": "F-4kf6KMXpujMxwAAAyx",
"via": "1.1 fly.io",
"fly-request-id": "01J5XSVZZEBDC5XTBGR0QKYXXJ-sea"
},
"status_code": 200
}
}
]
33 changes: 33 additions & 0 deletions test/cassettes/metrics/flush.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[
{
"request": {
"options": {
"with_body": "true"
},
"body": "{}",
"url": "https://demo-control.fly.dev/api/metrics/flush",
"headers": {
"Authorization": "***",
"Content-Type": "application/json",
"User-Agent": "Kickplan/0.1.0 (sdk-elixir)"
},
"method": "post",
"request_body": ""
},
"response": {
"binary": false,
"type": "ok",
"body": "",
"headers": {
"cache-control": "max-age=0, private, must-revalidate",
"date": "Thu, 22 Aug 2024 22:37:26 GMT",
"server": "Fly/5e55b43a7 (2024-08-21)",
"x-request-id": "F-4t9xPC0bL6wOQAAA0B",
"via": "1.1 fly.io",
"fly-request-id": "01J5Y3SMMC67WZPQJYTVY1ZVP0-sea",
"content-length": "0"
},
"status_code": 202
}
}
]
33 changes: 33 additions & 0 deletions test/cassettes/metrics/set.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[
{
"request": {
"options": {
"with_body": "true"
},
"body": "{\"value\":3,\"time\":\"2024-08-22T21:40:19.923716Z\",\"key\":\"sdk_elixir_test\",\"account_key\":\"9a592f57-6da0-408e-99e7-8918b48a7dbe\",\"idempotency_key\":\"004b7f07-71fd-4ea5-a43c-dcde2516305b\"}",
"url": "https://demo-control.fly.dev/api/metrics/set",
"headers": {
"Authorization": "***",
"Content-Type": "application/json",
"User-Agent": "Kickplan/0.1.0 (sdk-elixir)"
},
"method": "post",
"request_body": ""
},
"response": {
"binary": false,
"type": "ok",
"body": "",
"headers": {
"cache-control": "max-age=0, private, must-revalidate",
"date": "Thu, 22 Aug 2024 21:40:19 GMT",
"server": "Fly/5e55b43a7 (2024-08-21)",
"x-request-id": "F-4q2U-SUX7DPj0AAAzx",
"via": "1.1 fly.io",
"fly-request-id": "01J5Y0H2HYJAJ2PJVFS2D0TM7A-sea",
"content-length": "0"
},
"status_code": 202
}
}
]
28 changes: 28 additions & 0 deletions test/kickplan/resource/features_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule Kickplan.FeaturesTest do
use Kickplan.VCRCase, async: true

alias Kickplan.Features
alias Kickplan.Schema.Resolution

describe "resolve/2" do
test "success: resolves all features" do
use_cassette "features/resolve-all" do
{:ok, resolutions} = Features.resolve()

assert length(resolutions) == 5

assert Enum.all?(resolutions, fn resolution ->
%Resolution{} = resolution
end)
end
end

test "success: resolves a single feature" do
use_cassette "features/resolve" do
{:ok, resolution} = Features.resolve("contact-limit")

assert %Resolution{key: "contact-limit"} = resolution
end
end
end
end
33 changes: 33 additions & 0 deletions test/kickplan/resource/metrics_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
defmodule Kickplan.MetricsTest do
use Kickplan.VCRCase, async: true

alias Kickplan.Metrics

describe "flush/0" do
test "success: flushes the metrics" do
use_cassette "metrics/flush" do
assert {:ok, true} = Metrics.flush()
end
end
end

describe "set/1" do
test "success: resolves a single feature" do
use_cassette "metrics/set" do
assert {:ok, true} =
Metrics.set(
key: "sdk_elixir_test",
value: 3,
account_key: "9a592f57-6da0-408e-99e7-8918b48a7dbe",
time: DateTime.utc_now(),
idempotency_key: "004b7f07-71fd-4ea5-a43c-dcde2516305b"
)
end
end

test "failure: request has invalid params" do
assert {:error, %NimbleOptions.ValidationError{}} =
Metrics.set(key: "sdk_elixir_test")
end
end
end
18 changes: 18 additions & 0 deletions test/support/vcr_case.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule Kickplan.VCRCase do
@moduledoc false

use ExUnit.CaseTemplate

using do
quote do
use ExVCR.Mock, adapter: ExVCR.Adapter.Hackney
end
end

setup do
ExVCR.Config.cassette_library_dir("test/cassettes")
ExVCR.Config.filter_request_headers("Authorization")

:ok
end
end

0 comments on commit fd81391

Please sign in to comment.