diff --git a/config/dev.exs b/config/dev.exs index 27025c0a7..e4eaf5c5f 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -60,6 +60,9 @@ config :sanbase, Sanbase.KafkaExporter, producer: Sanbase.InMemoryKafka.Producer # with. When running the app locally these values are overridden by the values # in the .env.dev or dev.secret.exs files, which are ignored by git and not # published in the repository. Please do not report these as security issues. +# To create the user for your local env: +# In psql: CREATE ROLE postgres WITH LOGIN SUPERUSER PASSWORD 'postgres'; +# In the terminal: mix ecto.setup config :sanbase, Sanbase.Repo, username: "postgres", password: "postgres", diff --git a/lib/sanbase/metric/registry/populate.ex b/lib/sanbase/metric/registry/populate.ex index e37494cfd..97c4564b7 100644 --- a/lib/sanbase/metric/registry/populate.ex +++ b/lib/sanbase/metric/registry/populate.ex @@ -161,17 +161,8 @@ defmodule Sanbase.Metric.Registry.Populate do if inserts > 0 or updates > 0 do map = %{inserts_count: inserts, updates_count: updates} - {inserted_metrics, updated_metrics} = - Enum.reduce(list, {[], []}, fn {type, record}, {insert_acc, update_acc} -> - case type do - :insert -> {[record.metric | insert_acc], update_acc} - :update -> {insert_acc, [record.metric | update_acc]} - _ -> {insert_acc, update_acc} - end - end) - - # Emit locally event with more data. The distributed events are used only to refresh the - # persistent term, the local node event will also trigger notifications + {inserted_metrics, updated_metrics} = extract_inserted_updated_metrics(list) + # Emit locally event with more data local_event_map = Map.merge(map, %{inserted_metrics: inserted_metrics, updated_metrics: updated_metrics}) @@ -181,22 +172,80 @@ defmodule Sanbase.Metric.Registry.Populate do %{} ) - # Emit distributed event only to the MetricRegistrySubscriber so it refreshed the stored data - # in persistent term - Node.list() - |> Enum.each(fn node -> - IO.puts("Emitting event :bulk_metric_registry_change to #{node}") - - Node.spawn(node, fn -> - Sanbase.Metric.Registry.EventEmitter.emit_event( - {:ok, map}, - :bulk_metric_registry_change, - %{__only_process_by__: [Sanbase.EventBus.MetricRegistrySubscriber]} - ) - end) - end) + # Emit distributed event + emit_distributed_event(map) else :ok end end + + defp extract_inserted_updated_metrics(list) do + {_inserted_metrics, _updated_metrics} = + Enum.reduce(list, {[], []}, fn {type, record}, {insert_acc, update_acc} -> + case type do + :insert -> {[record.metric | insert_acc], update_acc} + :update -> {insert_acc, [record.metric | update_acc]} + _ -> {insert_acc, update_acc} + end + end) + end + + defp emit_distributed_event(map) do + Node.list() + |> Enum.each(fn node -> + IO.puts("Emitting event :bulk_metric_registry_change to #{node}") + + Node.spawn(node, fn -> + Sanbase.Metric.Registry.EventEmitter.emit_event( + {:ok, map}, + :bulk_metric_registry_change, + %{__only_process_by__: [Sanbase.EventBus.MetricRegistrySubscriber]} + ) + end) + end) + end +end + +defmodule Stack do + use GenServer + + def start_link(initial_stack \\ []) do + GenServer.start_link(__MODULE__, initial_stack, name: __MODULE__) + end + + def push(element) do + GenServer.call(__MODULE__, {:push, element}) + end + + def pop do + GenServer.call(__MODULE__, :pop) + end + + def peek do + GenServer.call(__MODULE__, :peek) + end + + def init(initial_stack) do + {:ok, initial_stack} + end + + def handle_call({:push, element}, _from, stack) do + {:reply, :ok, [element | stack]} + end + + def handle_call(:pop, _from, [h | t]) do + {:reply, h, t} + end + + def handle_call(:pop, _from, []) do + {:reply, nil, []} + end + + def handle_call(:peek, _from, [h | _] = stack) do + {:reply, h, stack} + end + + def handle_call(:peek, _from, []) do + {:reply, nil, []} + end end diff --git a/lib/sanbase/metric/registry/registry.ex b/lib/sanbase/metric/registry/registry.ex index b7ec04b8f..28b5b1959 100644 --- a/lib/sanbase/metric/registry/registry.ex +++ b/lib/sanbase/metric/registry/registry.ex @@ -263,10 +263,13 @@ defmodule Sanbase.Metric.Registry do """ @spec all() :: [t()] def all() do - query = - from(m in __MODULE__, - order_by: [asc: m.id] - ) + query = from(m in __MODULE__, order_by: [asc: m.id]) + + Sanbase.Repo.all(query) + end + + def by_ids(ids) do + query = from(m in __MODULE__, where: m.id in ^ids) Sanbase.Repo.all(query) end diff --git a/lib/sanbase/metric/registry/sync.ex b/lib/sanbase/metric/registry/sync.ex new file mode 100644 index 000000000..2d2e0ecd7 --- /dev/null +++ b/lib/sanbase/metric/registry/sync.ex @@ -0,0 +1,119 @@ +defmodule Sanbase.Metric.Registry.Sync do + @moduledoc """ + This module is responsible for syncing the metric registry with the external + source of truth. + """ + + alias Sanbase.Metric.Registry + @process_name :metric_registry_sync + + @spec initiate(list(non_neg_integer())) :: :ok + def initiate(metric_registry_ids) when is_list(metric_registry_ids) do + case ongoing_sync?() do + true -> + {:error, "Sync process is already running"} + + false -> + pid = spawn_link(__MODULE__, :sync, [metric_registry_ids]) + Process.register(pid, @process_name) + {:ok, pid} + end + end + + def initiate_sync(metric_registry_ids) do + with :ok <- check_initiate_env(), + {:ok, content} <- get_sync_content(metric_registry_ids), + :ok <- start_sync(content), + :ok <- record_sync(content) do + {:ok, content} + end + end + + def apply_sync(json_content) do + with :ok <- check_apply_env(), + {:ok, list} when is_list(list) <- Jason.decode(json_content) do + for %{} = params <- list do + params = Map.put(params, "sync_status", "synced") + + %{"metric" => metric, "data_type" => data_type, "fixed_parameters" => fixed_parameters} = + params + + with {:ok, metric} <- Registry.by_name(metric, data_type, fixed_parameters), + {:ok, metric} <- Registry.update(metric, params) do + {:ok, metric} + end + |> dbg() + end + end + end + + defp start_sync(content) do + url = get_sync_target_url() + + case Req.post(url, json: content) do + {:ok, _} -> :ok + {:error, _} -> {:error, "Failed to sync"} + end + end + + defp get_sync_target_url() do + secret = System.get_env("METRIC_REGISTRY_SYNC_SECRET") + + case Sanbase.Utils.Config.module_get(Sanbase, :deployment_env) do + "dev" -> "http://localhost:4000/sync_metric_registry/#{secret}" + "stage" -> "http://api.santiment.net/sync_metric_registry/#{secret}" + "prod" -> raise("Cannot initiate sync from PROD") + end + end + + defp get_sync_content([]), do: {:error, "Nothing to sync"} + + defp get_sync_content(metric_registry_ids) do + structs = Sanbase.Metric.Registry.by_ids(metric_registry_ids) + content = generate_content(structs) + {:ok, content} + end + + defp check_initiate_env() do + deployment_env = Sanbase.Utils.Config.module_get(Sanbase, :deployment_env) + database_url = System.get_env("DATABASE_URL") + + # If local, the DATABASE_URL should not be set pointing to stage/prod. + # Only work if the local postgres is used + local? = deployment_env == "env" and is_nil(database_url) + stage? = deployment_env == "stage" + + if local? or stage? do + :ok + else + {:error, "Can only deploy sync from STAGE to PROD"} + end + end + + defp check_apply_env() do + deployment_env = Sanbase.Utils.Config.module_get(Sanbase, :deployment_env) + database_url = System.get_env("DATABASE_URL") + + # If local, the DATABASE_URL should not be set pointing to stage/prod. + # Only work if the local postgres is used + local? = deployment_env == "env" and is_nil(database_url) + prod? = deployment_env == "prod" + + if local? or prod? do + :ok + else + {:error, "Can only apply sync only on PROD"} + end + end + + defp generate_content(structs) do + api_url = SanbaseWeb.Endpoint.api_url() + from_host = URI.parse(api_url).host + + %{ + metric_registry_structs: Jason.encode!(structs), + generated_at: DateTime.utc_now() |> DateTime.to_iso8601(), + from_host: from_host + } + end +end diff --git a/lib/sanbase/metric/registry/sync_server.ex b/lib/sanbase/metric/registry/sync_server.ex new file mode 100644 index 000000000..b741e5d46 --- /dev/null +++ b/lib/sanbase/metric/registry/sync_server.ex @@ -0,0 +1,11 @@ +defmodule Sanbase.Metric.Registry.SyncServer do + use GenServer + @name :metric_registry_sync_server + def start_link(_opts) do + GenServer.start_link(__MODULE__, name: @name) + end + + def init(_) do + {:ok, %{}} + end +end diff --git a/lib/sanbase_web/controllers/metric_registry_controller.ex b/lib/sanbase_web/controllers/metric_registry_controller.ex index a9377c269..57b7d2fa8 100644 --- a/lib/sanbase_web/controllers/metric_registry_controller.ex +++ b/lib/sanbase_web/controllers/metric_registry_controller.ex @@ -1,13 +1,57 @@ defmodule SanbaseWeb.MetricRegistryController do use SanbaseWeb, :controller + def sync(conn, %{"secret" => secret} = params) do + case secret == get_sync_secret() do + true -> + # TODO: Remove + IO.inspect(params) + + conn + |> resp(200, "OK") + |> send_resp() + + false -> + conn + |> resp(403, "Unauthorized") + |> send_resp() + end + end + def export_json(conn, _params) do conn - |> resp(200, "ok") + |> resp(200, get_metric_registry_json()) |> send_resp() end defp get_metric_registry_json() do Sanbase.Metric.Registry.all() + |> Enum.take(1) + |> Enum.map(&transform/1) + + # |> Enum.map(&Jason.encode!/1) + # |> Enum.intersperse("\n") + end + + defp transform(struct) when is_struct(struct) do + struct + |> Map.from_struct() + |> Map.drop([:__meta__, :inserted_at, :updated_at, :change_suggestions]) + |> Map.new(fn + {k, v} when is_list(v) -> + {k, Enum.map(v, &transform/1)} + + {k, v} when is_map(v) -> + {k, transform(v)} + + {k, v} -> + {k, v} + end) + end + + defp transform(data), do: data + + defp get_sync_secret() do + Sanbase.Utils.Config.module_get(__MODULE__, :sync_secret, "no_secret") end end diff --git a/lib/sanbase_web/live/metric_registry/metric_registry_index_live.ex b/lib/sanbase_web/live/metric_registry/metric_registry_index_live.ex index c9c907918..c75ba9b7e 100644 --- a/lib/sanbase_web/live/metric_registry/metric_registry_index_live.ex +++ b/lib/sanbase_web/live/metric_registry/metric_registry_index_live.ex @@ -38,7 +38,7 @@ defmodule SanbaseWeb.MetricRegistryIndexLive do
- Showing <%= length(@visible_metrics_ids) %> metrics + Showing {length(@visible_metrics_ids)} metrics
<.navigation /> @@ -50,7 +50,7 @@ defmodule SanbaseWeb.MetricRegistryIndexLive do <:col :let={row} label="ID"> {row.id} - <:col :let={row} label="Metric Names" col_class="max-w-[720px] break-all"> + <:col :let={row} label="Metric Names" col_class="max-w-[420px]"> <.metric_names metric={row.metric} internal_metric={row.internal_metric} @@ -67,7 +67,6 @@ defmodule SanbaseWeb.MetricRegistryIndexLive do <:col :let={row} -<<<<<<< HEAD label="Table" popover_target="popover-table" popover_target_text={get_popover_text(%{key: "Clickhouse Table"})} @@ -84,25 +83,6 @@ defmodule SanbaseWeb.MetricRegistryIndexLive do <:col :let={row} -||||||| parent of e83704e2d (Add is_verified toggle to Metric Registry LiveView) - label="Table" - popover_target="popover-table" - popover_target_text={get_popover_text(%{key: "Clickhouse Table"})} - > - <.embeded_schema_show list={row.tables} key={:name} /> - - <:col - :let={row} - label="Default Aggregation" - popover_target="popover-default-aggregation" - popover_target_text={get_popover_text(%{key: "Default Aggregation"})} - > - <%= row.default_aggregation %> - - <:col - :let={row} -======= ->>>>>>> e83704e2d (Add is_verified toggle to Metric Registry LiveView) label="Access" popover_target="popover-access" popover_target_text={get_popover_text(%{key: "Access"})} @@ -212,46 +192,48 @@ defmodule SanbaseWeb.MetricRegistryIndexLive do )} end - defp list_metrics_verified_status_changed(assigns) do + defp embeded_schema_show(assigns) do ~H""" -<<<<<<< HEAD
{Map.get(item, @key)} -||||||| parent of e83704e2d (Add is_verified toggle to Metric Registry LiveView) -
-
- <%= Map.get(item, @key) %> -======= -
- No changes +
-
- <.table id="uploaded_images" rows={Enum.filter(@metrics, &(&1.id in @changed_metrics_ids))}> - <:col :let={row} label="Metric"> - <.metric_names - metric={row.metric} - internal_metric={row.internal_metric} - human_readable_name={row.human_readable_name} + """ + end + + defp list_metrics_verified_status_changed(assigns) do + ~H""" +
+
+ No changes +
+
+ <.table id="uploaded_images" rows={Enum.filter(@metrics, &(&1.id in @changed_metrics_ids))}> + <:col :let={row} label="Metric" col_class="max-w-[420px]"> + <.metric_names + metric={row.metric} + internal_metric={row.internal_metric} + human_readable_name={row.human_readable_name} + /> + + <:col :let={row} label="New Status"> + VERIFIED + UNVERIFIED + + +
+ <.phx_click_button + phx_click="confirm_verified_changes_update" + class="bg-green-500 hover:bg-green-900 text-white" + text="Confirm Changes" /> - - <:col :let={row} label="New Status"> - VERIFIED - UNVERIFIED - - -
- <.phx_click_button - phx_click="confirm_verified_changes_update" - class="bg-green-500 hover:bg-green-900 text-white" - text="Confirm Changes" - /> - <.phx_click_button - phx_click="hide_show_verified_changes_modal" - class="bg-white hover:bg-gray-100 text-gray-800" - text="Close" - /> ->>>>>>> e83704e2d (Add is_verified toggle to Metric Registry LiveView) + <.phx_click_button + phx_click="hide_show_verified_changes_modal" + class="bg-white hover:bg-gray-100 text-gray-800" + text="Close" + /> +
""" @@ -398,15 +380,15 @@ defmodule SanbaseWeb.MetricRegistryIndexLive do @class ]} > - <%= @text %> - (<%= @count %>) + {@text} + ({@count}) """ end defp metric_names(assigns) do ~H""" -
+
{@human_readable_name}
{@metric} (API)
{@internal_metric} (DB)
diff --git a/lib/sanbase_web/live/metric_registry/metric_registry_sync_live.ex b/lib/sanbase_web/live/metric_registry/metric_registry_sync_live.ex index 007fa5c96..e8f2345d7 100644 --- a/lib/sanbase_web/live/metric_registry/metric_registry_sync_live.ex +++ b/lib/sanbase_web/live/metric_registry/metric_registry_sync_live.ex @@ -4,13 +4,23 @@ defmodule SanbaseWeb.MetricRegistrySyncLive do alias SanbaseWeb.AvailableMetricsComponents @impl true def mount(_params, _session, socket) do - metrics = Sanbase.Metric.Registry.all() |> Enum.filter(&(&1.sync_status == "not_synced")) + metrics = Sanbase.Metric.Registry.all() + + syncable_metrics = + metrics + |> Enum.filter(&(&1.sync_status == "not_synced" and &1.is_verified == true)) + + not_syncable_metrics = + metrics + |> Enum.filter(&(&1.sync_status == "not_synced" and &1.is_verified == false)) {:ok, socket |> assign( - metrics: metrics, - sync_metric_ids: Enum.map(metrics, & &1.id) |> MapSet.new() + syncable_metrics: syncable_metrics, + non_syncable_metrics: not_syncable_metrics, + metric_ids_to_sync: Enum.map(syncable_metrics, & &1.id) |> MapSet.new(), + page_title: "Syncing Metrics" )} end @@ -20,7 +30,10 @@ defmodule SanbaseWeb.MetricRegistrySyncLive do
- Showing <%= length(@metrics) %> metrics that are not synced + {length(@syncable_metrics)} metric(s) available to be synced from stage to prod} +
+
+ {length(@non_syncable_metrics)} metric(s) not synced but need(s) to be verified first}
@@ -42,12 +55,12 @@ defmodule SanbaseWeb.MetricRegistrySyncLive do class="bg-white hover:bg-gray-100 text-zync-900" />
- <.table id="metrics_registry" rows={@metrics}> + <.table id="metrics_registry" rows={@syncable_metrics}> <:col :let={row} label="Should Sync"> - <.checkbox row={row} sync_metric_ids={@sync_metric_ids} /> + <.checkbox row={row} metric_ids_to_sync={@metric_ids_to_sync} /> <:col :let={row} label="ID"> - <%= row.id %> + {row.id} <:col :let={row} label="Metric Names" col_class="max-w-[720px] break-all"> <.metric_names @@ -61,7 +74,7 @@ defmodule SanbaseWeb.MetricRegistrySyncLive do text="Sync Metrics" phx_click="sync" class="bg-blue-700 hover:bg-blue-800 text-white" - count={MapSet.size(@sync_metric_ids)} + count={MapSet.size(@metric_ids_to_sync)} phx_disable_with="Syncing..." />
@@ -85,46 +98,52 @@ defmodule SanbaseWeb.MetricRegistrySyncLive do ]} phx-disable-with={@phx_disable_with} > - <%= @text %> - (<%= @count %>) + {@text} + ({@count}) """ end @impl true def handle_event("sync", _params, socket) do - Process.sleep(5000) + ids = socket.assigns.metric_ids_to_sync |> Enum.to_list() + + case Sanbase.Metric.Registry.Sync.initiate_sync(ids) do + {:ok, data} -> {:ok, data} + {:error, error} -> {:error, error} + end + {:noreply, socket} end def handle_event("update_should_sync", %{"metric_registry_id" => id} = params, socket) do checked = Map.get(params, "value") == "on" - sync_metric_ids = + metric_ids_to_sync = if checked do - MapSet.put(socket.assigns.sync_metric_ids, id) + MapSet.put(socket.assigns.metric_ids_to_sync, id) else - MapSet.delete(socket.assigns.sync_metric_ids, id) + MapSet.delete(socket.assigns.metric_ids_to_sync, id) end - {:noreply, assign(socket, sync_metric_ids: sync_metric_ids)} + {:noreply, assign(socket, metric_ids_to_sync: metric_ids_to_sync)} end def handle_event("select_all", _params, socket) do {:noreply, - assign(socket, sync_metric_ids: Enum.map(socket.assigns.metrics, & &1.id) |> MapSet.new())} + assign(socket, metric_ids_to_sync: Enum.map(socket.assigns.metrics, & &1.id) |> MapSet.new())} end def handle_event("deselect_all", _params, socket) do - {:noreply, assign(socket, sync_metric_ids: MapSet.new())} + {:noreply, assign(socket, metric_ids_to_sync: MapSet.new())} end defp metric_names(assigns) do ~H"""
-
<%= @human_readable_name %>
-
<%= @metric %> (API)
-
<%= @internal_metric %> (DB)
+
{@human_readable_name}
+
{@metric} (API)
+
{@internal_metric} (DB)
""" end @@ -136,7 +155,7 @@ defmodule SanbaseWeb.MetricRegistrySyncLive do id="not-verified-only" name={"sync-status-#{@row.id}"} type="checkbox" - checked={@row.id in @sync_metric_ids} + checked={@row.id in @metric_ids_to_sync} class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded" phx-click={JS.push("update_should_sync", value: %{metric_registry_id: @row.id})} } diff --git a/lib/sanbase_web/router.ex b/lib/sanbase_web/router.ex index 40d8b77d3..c85ecb2ba 100644 --- a/lib/sanbase_web/router.ex +++ b/lib/sanbase_web/router.ex @@ -90,8 +90,6 @@ defmodule SanbaseWeb.Router do live("/metric_registry/sync", MetricRegistrySyncLive, :new) end - get("/metric_registry_export", MetricRegistryController, :export_json) - scope "/" do pipe_through(:api) @@ -183,6 +181,9 @@ defmodule SanbaseWeb.Router do end scope "/", SanbaseWeb do + get("/metric_registry_export", MetricRegistryController, :export_json) + post("/sync_metric_registry/:secret", MetricRegistryController, :sync) + get("/api_metric_name_mapping", MetricNameController, :api_metric_name_mapping) get("/projects_data", DataController, :projects_data) get("/projects_twitter_handles", DataController, :projects_twitter_handles) diff --git a/priv/repo/migrations/20241218134556_add_metric_registry_syncs.exs b/priv/repo/migrations/20241218134556_add_metric_registry_syncs.exs new file mode 100644 index 000000000..3e181ba74 --- /dev/null +++ b/priv/repo/migrations/20241218134556_add_metric_registry_syncs.exs @@ -0,0 +1,11 @@ +defmodule Sanbase.Repo.Migrations.AddMetricRegistrySyncs do + use Ecto.Migration + + def change do + create table(:metric_registry_syncs) do + add(:state, :string) + add(:content, :map) + timestamps() + end + end +end diff --git a/priv/repo/structure.sql b/priv/repo/structure.sql index 83fc57aaa..0c74a57eb 100644 --- a/priv/repo/structure.sql +++ b/priv/repo/structure.sql @@ -2,8 +2,8 @@ -- PostgreSQL database dump -- --- Dumped from database version 15.1 (Homebrew) --- Dumped by pg_dump version 15.1 (Homebrew) +-- Dumped from database version 15.10 (Homebrew) +-- Dumped by pg_dump version 15.10 (Homebrew) SET statement_timeout = 0; SET lock_timeout = 0; @@ -2368,6 +2368,38 @@ CREATE SEQUENCE public.metric_registry_id_seq ALTER SEQUENCE public.metric_registry_id_seq OWNED BY public.metric_registry.id; +-- +-- Name: metric_registry_syncs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.metric_registry_syncs ( + id bigint NOT NULL, + state character varying(255), + content jsonb, + inserted_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: metric_registry_syncs_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.metric_registry_syncs_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: metric_registry_syncs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.metric_registry_syncs_id_seq OWNED BY public.metric_registry_syncs.id; + + -- -- Name: metrics; Type: TABLE; Schema: public; Owner: - -- @@ -5264,6 +5296,13 @@ ALTER TABLE ONLY public.metric_registry ALTER COLUMN id SET DEFAULT nextval('pub ALTER TABLE ONLY public.metric_registry_change_suggestions ALTER COLUMN id SET DEFAULT nextval('public.metric_registry_change_suggestions_id_seq'::regclass); +-- +-- Name: metric_registry_syncs id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.metric_registry_syncs ALTER COLUMN id SET DEFAULT nextval('public.metric_registry_syncs_id_seq'::regclass); + + -- -- Name: metrics id; Type: DEFAULT; Schema: public; Owner: - -- @@ -6177,6 +6216,14 @@ ALTER TABLE ONLY public.metric_registry ADD CONSTRAINT metric_registry_pkey PRIMARY KEY (id); +-- +-- Name: metric_registry_syncs metric_registry_syncs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.metric_registry_syncs + ADD CONSTRAINT metric_registry_syncs_pkey PRIMARY KEY (id); + + -- -- Name: metrics metrics_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -9724,14 +9771,15 @@ INSERT INTO public."schema_migrations" (version) VALUES (20241029080754); INSERT INTO public."schema_migrations" (version) VALUES (20241029082533); INSERT INTO public."schema_migrations" (version) VALUES (20241029151959); INSERT INTO public."schema_migrations" (version) VALUES (20241030141825); -INSERT INTO public."schema_migrations" (version) VALUES (20241104061632); INSERT INTO public."schema_migrations" (version) VALUES (20241104115340); INSERT INTO public."schema_migrations" (version) VALUES (20241108112754); INSERT INTO public."schema_migrations" (version) VALUES (20241112094924); INSERT INTO public."schema_migrations" (version) VALUES (20241114140339); INSERT INTO public."schema_migrations" (version) VALUES (20241114141110); INSERT INTO public."schema_migrations" (version) VALUES (20241116104556); +INSERT INTO public."schema_migrations" (version) VALUES (20241121133719); INSERT INTO public."schema_migrations" (version) VALUES (20241128113958); INSERT INTO public."schema_migrations" (version) VALUES (20241128161315); INSERT INTO public."schema_migrations" (version) VALUES (20241202104812); INSERT INTO public."schema_migrations" (version) VALUES (20241212054904); +INSERT INTO public."schema_migrations" (version) VALUES (20241218134556); diff --git a/test/sanbase/metric_registry/metric_registry_sync_test.exs b/test/sanbase/metric_registry/metric_registry_sync_test.exs new file mode 100644 index 000000000..943e74d5c --- /dev/null +++ b/test/sanbase/metric_registry/metric_registry_sync_test.exs @@ -0,0 +1,12 @@ +defmodule Sanbase.MetricRegistrySyncTest do + use SanbaseWeb.ConnCase + + test "syncing", context do + context.conn + |> post("/sync_metric_registry/no_secret", %{ + metrics: [%Sanbase.Metric.Registry{}, "a1", "b2", "c3"] + }) + + assert 1 == 2 + end +end