Conditionally support switching between v1 and v2 clickhouse schemas (#2780)

* Remove ClickhouseSetup module

This has been an implicit point of contact to many
tests. From now on the goal is for each test to maintain
its own, isolated setup so that no accidental clashes
and implicit assumptions are relied upon.

* Implement v2 schema check

An environment variable V2_MIGRATION_DONE acts like
a feature flag, switching plausible from using old events/sessions
schemas to v2 schemas introduced by NumericIDs migration.

* Run both test suites sequentially

While the code for v1 and v2 schemas must be kept still,
we will from now on run tests against both code paths.
Secondary test run will set V2_MIGRATION_DONE=1 variable,
thus making all `Plausible.v2?()` checks return `true'.

* Remove unused function

This is a remnant from the short period when
we would check for existing events before allowing
creating a new site.

* Update test setups/factories with v2 migration check

* Make GateKeeper return site id along with :allow

* Make Billing module check for v2 schema

* Make ingestion aware of v2 schema

* Disable site transfers for when v2 is live

In a separate changeset we will implement simplified
site transfer for when v2 migration is complete.
The new transfer will only rename the site domain in postgres
and keep track of the original site prior to the transfer
so we keep an ingestion grace period until the customers
redeploy their scripting.

* Make Stats base queries aware of v2 schema switch

* Update breakdown with v2 conditionals

* Update pageview local start with v2 check

* Update current visitoris with v2 check

* Update stats controller with v2 checks

* Update external controller with v2 checks

* Update remaining tests with proper fixtures

* Rewrite redundant assignment

* Remove unused alias

* Mute credo, this is not the right time

* Add test_helper prompt

* Fetch priv dir so it works with a release

* Fetch distinct partitions only

* Don't limit inspect output for partitions

* Ensure SQL is printed to IO

* Remove redundant domain fixture
This commit is contained in:
hq1 2023-03-27 13:52:42 +02:00 committed by GitHub
parent a75d0b35b0
commit d2f2c69387
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 1211 additions and 1185 deletions

View File

@ -70,8 +70,12 @@ jobs:
run: npm run deploy --prefix ./tracker run: npm run deploy --prefix ./tracker
- name: Check Credo Warnings - name: Check Credo Warnings
run: mix credo diff --from-git-merge-base origin/master run: mix credo diff --from-git-merge-base origin/master
- name: Run tests - name: Run tests (against v1 schema)
run: mix test --include slow --max-failures 1 --warnings-as-errors run: mix test --include slow --max-failures 1 --warnings-as-errors
- name: Run tests (against v2 schema)
run: mix test --include slow --max-failures 1 --warnings-as-errors
env:
V2_MIGRATION_DONE: 1
- name: Check Dialyzer - name: Check Dialyzer
run: mix dialyzer run: mix dialyzer
env: env:

View File

@ -99,6 +99,8 @@ ch_db_url =
|> get_var_from_path_or_env("CLICKHOUSE_MAX_BUFFER_SIZE", "10000") |> get_var_from_path_or_env("CLICKHOUSE_MAX_BUFFER_SIZE", "10000")
|> Integer.parse() |> Integer.parse()
v2_migration_done = get_var_from_path_or_env(config_dir, "V2_MIGRATION_DONE")
### Mandatory params End ### Mandatory params End
build_metadata_raw = get_var_from_path_or_env(config_dir, "BUILD_METADATA", "{}") build_metadata_raw = get_var_from_path_or_env(config_dir, "BUILD_METADATA", "{}")
@ -131,6 +133,8 @@ runtime_metadata = [
config :plausible, :runtime_metadata, runtime_metadata config :plausible, :runtime_metadata, runtime_metadata
config :plausible, :v2_migration_done, v2_migration_done
sentry_dsn = get_var_from_path_or_env(config_dir, "SENTRY_DSN") sentry_dsn = get_var_from_path_or_env(config_dir, "SENTRY_DSN")
honeycomb_api_key = get_var_from_path_or_env(config_dir, "HONEYCOMB_API_KEY") honeycomb_api_key = get_var_from_path_or_env(config_dir, "HONEYCOMB_API_KEY")
honeycomb_dataset = get_var_from_path_or_env(config_dir, "HONEYCOMB_DATASET") honeycomb_dataset = get_var_from_path_or_env(config_dir, "HONEYCOMB_DATASET")

View File

@ -6,4 +6,9 @@ defmodule Plausible do
Contexts are also responsible for managing your data, regardless Contexts are also responsible for managing your data, regardless
if it comes from the database, an external API or others. if it comes from the database, an external API or others.
""" """
@spec v2?() :: boolean()
def v2?() do
Plausible.DataMigration.NumericIDs.ready?()
end
end end

View File

@ -113,10 +113,28 @@ defmodule Plausible.Billing do
def last_two_billing_months_usage(user, today \\ Timex.today()) do def last_two_billing_months_usage(user, today \\ Timex.today()) do
{first, second} = last_two_billing_cycles(user, today) {first, second} = last_two_billing_cycles(user, today)
if Plausible.v2?() do
site_ids = Plausible.Sites.owned_site_ids(user)
usage_for_sites = fn site_ids, date_range ->
{pageviews, custom_events} =
Plausible.Stats.Clickhouse.usage_breakdown(site_ids, date_range)
pageviews + custom_events
end
{
usage_for_sites.(site_ids, first),
usage_for_sites.(site_ids, second)
}
else
domains = Plausible.Sites.owned_sites_domains(user) domains = Plausible.Sites.owned_sites_domains(user)
usage_for_sites = fn domains, date_range -> usage_for_sites = fn domains, date_range ->
{pageviews, custom_events} = Plausible.Stats.Clickhouse.usage_breakdown(domains, date_range) {pageviews, custom_events} =
Plausible.Stats.Clickhouse.usage_breakdown(domains, date_range)
pageviews + custom_events pageviews + custom_events
end end
@ -125,6 +143,7 @@ defmodule Plausible.Billing do
usage_for_sites.(domains, second) usage_for_sites.(domains, second)
} }
end end
end
def last_two_billing_cycles(user, today \\ Timex.today()) do def last_two_billing_cycles(user, today \\ Timex.today()) do
last_bill_date = user.subscription.last_bill_date last_bill_date = user.subscription.last_bill_date
@ -147,9 +166,14 @@ defmodule Plausible.Billing do
end end
def usage_breakdown(user) do def usage_breakdown(user) do
if Plausible.v2?() do
site_ids = Plausible.Sites.owned_site_ids(user)
Plausible.Stats.Clickhouse.usage_breakdown(site_ids)
else
domains = Plausible.Sites.owned_sites_domains(user) domains = Plausible.Sites.owned_sites_domains(user)
Plausible.Stats.Clickhouse.usage_breakdown(domains) Plausible.Stats.Clickhouse.usage_breakdown(domains)
end end
end
@doc """ @doc """
Returns the number of sites that an account is allowed to have. Accounts for Returns the number of sites that an account is allowed to have. Accounts for

View File

@ -13,7 +13,7 @@ defmodule Plausible.DataMigration do
@repo repo @repo repo
def run_sql_confirm(name, assigns \\ []) do def run_sql_confirm(name, assigns \\ []) do
query = unwrap(name, assigns) query = unwrap_with_io(name, assigns)
confirm("Execute?", fn -> do_run(name, query) end) confirm("Execute?", fn -> do_run(name, query) end)
end end
@ -30,7 +30,9 @@ defmodule Plausible.DataMigration do
end end
defp unwrap(name, assigns) do defp unwrap(name, assigns) do
"priv/data_migrations" :plausible
|> :code.priv_dir()
|> Path.join("data_migrations")
|> Path.join(@dir) |> Path.join(@dir)
|> Path.join("sql") |> Path.join("sql")
|> Path.join(name <> ".sql.eex") |> Path.join(name <> ".sql.eex")

View File

@ -7,6 +7,10 @@ defmodule Plausible.DataMigration.NumericIDs do
@table_settings "SETTINGS index_granularity = 8192, storage_policy = 'tiered'" @table_settings "SETTINGS index_granularity = 8192, storage_policy = 'tiered'"
def ready?() do
Application.get_env(:plausible, :v2_migration_done) || false
end
# credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity # credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity
def run(opts \\ []) do def run(opts \\ []) do
interactive? = Keyword.get(opts, :interactive?, true) interactive? = Keyword.get(opts, :interactive?, true)
@ -65,7 +69,7 @@ defmodule Plausible.DataMigration.NumericIDs do
- table_settings: #{table_settings} - table_settings: #{table_settings}
- db url: #{db_url} - db url: #{db_url}
- cluster?: #{cluster?} - cluster?: #{cluster?}
- partitions to do: #{inspect(partitions, pretty: true, width: 80)} - partitions to do: #{inspect(partitions, pretty: true, limit: :infinity, width: 80)}
- start from: #{start_from} - start from: #{start_from}
- stop at: #{stop_at} - stop at: #{stop_at}
""") """)

View File

@ -64,9 +64,14 @@ defmodule Plausible.Event.WriteBuffer do
events -> events ->
Logger.info("Flushing #{length(events)} events") Logger.info("Flushing #{length(events)} events")
events = Enum.map(events, &(Map.from_struct(&1) |> Map.delete(:__meta__))) events = Enum.map(events, &(Map.from_struct(&1) |> Map.delete(:__meta__)))
if Plausible.v2?() do
IngestRepo.insert_all(Plausible.ClickhouseEventV2, events)
else
IngestRepo.insert_all(Plausible.ClickhouseEvent, events) IngestRepo.insert_all(Plausible.ClickhouseEvent, events)
end end
end end
end
defp flush_interval_ms() do defp flush_interval_ms() do
Keyword.fetch!(Application.get_env(:plausible, IngestRepo), :flush_interval_ms) Keyword.fetch!(Application.get_env(:plausible, IngestRepo), :flush_interval_ms)

View File

@ -7,9 +7,11 @@ defmodule Plausible.Ingestion.Event do
""" """
alias Plausible.Ingestion.Request alias Plausible.Ingestion.Request
alias Plausible.ClickhouseEvent alias Plausible.ClickhouseEvent
alias Plausible.ClickhouseEventV2
alias Plausible.Site.GateKeeper alias Plausible.Site.GateKeeper
defstruct domain: nil, defstruct domain: nil,
site_id: nil,
clickhouse_event_attrs: %{}, clickhouse_event_attrs: %{},
clickhouse_event: nil, clickhouse_event: nil,
dropped?: false, dropped?: false,
@ -26,8 +28,9 @@ defmodule Plausible.Ingestion.Event do
@type t() :: %__MODULE__{ @type t() :: %__MODULE__{
domain: String.t() | nil, domain: String.t() | nil,
site_id: pos_integer() | nil,
clickhouse_event_attrs: map(), clickhouse_event_attrs: map(),
clickhouse_event: %ClickhouseEvent{} | nil, clickhouse_event: %ClickhouseEvent{} | %ClickhouseEventV2{} | nil,
dropped?: boolean(), dropped?: boolean(),
drop_reason: drop_reason(), drop_reason: drop_reason(),
request: Request.t(), request: Request.t(),
@ -43,10 +46,10 @@ defmodule Plausible.Ingestion.Event do
else else
Enum.reduce(domains, [], fn domain, acc -> Enum.reduce(domains, [], fn domain, acc ->
case GateKeeper.check(domain) do case GateKeeper.check(domain) do
:allow -> {:allow, site_id} ->
processed = processed =
domain domain
|> new(request) |> new(site_id, request)
|> process_unless_dropped(pipeline()) |> process_unless_dropped(pipeline())
[processed | acc] [processed | acc]
@ -117,6 +120,10 @@ defmodule Plausible.Ingestion.Event do
struct!(__MODULE__, domain: domain, request: request) struct!(__MODULE__, domain: domain, request: request)
end end
defp new(domain, site_id, request) do
struct!(__MODULE__, domain: domain, site_id: site_id, request: request)
end
defp drop(%__MODULE__{} = event, reason, attrs \\ []) do defp drop(%__MODULE__{} = event, reason, attrs \\ []) do
fields = fields =
attrs attrs
@ -156,6 +163,7 @@ defmodule Plausible.Ingestion.Event do
defp put_basic_info(%__MODULE__{} = event) do defp put_basic_info(%__MODULE__{} = event) do
update_attrs(event, %{ update_attrs(event, %{
domain: event.domain, domain: event.domain,
site_id: event.site_id,
timestamp: event.request.timestamp, timestamp: event.request.timestamp,
name: event.request.event_name, name: event.request.event_name,
hostname: event.request.hostname, hostname: event.request.hostname,
@ -217,9 +225,15 @@ defmodule Plausible.Ingestion.Event do
defp validate_clickhouse_event(%__MODULE__{} = event) do defp validate_clickhouse_event(%__MODULE__{} = event) do
clickhouse_event = clickhouse_event =
if Plausible.v2?() do
event
|> Map.fetch!(:clickhouse_event_attrs)
|> ClickhouseEventV2.new()
else
event event
|> Map.fetch!(:clickhouse_event_attrs) |> Map.fetch!(:clickhouse_event_attrs)
|> ClickhouseEvent.new() |> ClickhouseEvent.new()
end
case Ecto.Changeset.apply_action(clickhouse_event, nil) do case Ecto.Changeset.apply_action(clickhouse_event, nil) do
{:ok, valid_clickhouse_event} -> {:ok, valid_clickhouse_event} ->

View File

@ -22,7 +22,14 @@ defmodule Plausible.Session.CacheStore do
defp find_session(_domain, nil), do: nil defp find_session(_domain, nil), do: nil
defp find_session(event, user_id) do defp find_session(event, user_id) do
case Cachex.get(:sessions, {event.domain, user_id}) do from_cache =
if Plausible.v2?() do
Cachex.get(:sessions, {event.site_id, user_id})
else
Cachex.get(:sessions, {event.domain, user_id})
end
case from_cache do
{:ok, nil} -> {:ok, nil} ->
nil nil
@ -38,7 +45,13 @@ defmodule Plausible.Session.CacheStore do
end end
defp persist_session(session) do defp persist_session(session) do
key = {session.domain, session.user_id} key =
if Plausible.v2?() do
{session.site_id, session.user_id}
else
{session.domain, session.user_id}
end
Cachex.put(:sessions, key, session, ttl: :timer.minutes(30)) Cachex.put(:sessions, key, session, ttl: :timer.minutes(30))
session session
end end
@ -68,6 +81,41 @@ defmodule Plausible.Session.CacheStore do
end end
defp new_session_from_event(event) do defp new_session_from_event(event) do
if Plausible.v2?() do
%Plausible.ClickhouseSessionV2{
sign: 1,
session_id: Plausible.ClickhouseSession.random_uint64(),
hostname: event.hostname,
site_id: event.site_id,
user_id: event.user_id,
entry_page: event.pathname,
exit_page: event.pathname,
is_bounce: true,
duration: 0,
pageviews: if(event.name == "pageview", do: 1, else: 0),
events: 1,
referrer: event.referrer,
referrer_source: event.referrer_source,
utm_medium: event.utm_medium,
utm_source: event.utm_source,
utm_campaign: event.utm_campaign,
utm_content: event.utm_content,
utm_term: event.utm_term,
country_code: event.country_code,
subdivision1_code: event.subdivision1_code,
subdivision2_code: event.subdivision2_code,
city_geoname_id: event.city_geoname_id,
screen_size: event.screen_size,
operating_system: event.operating_system,
operating_system_version: event.operating_system_version,
browser: event.browser,
browser_version: event.browser_version,
timestamp: event.timestamp,
start: event.timestamp,
"entry_meta.key": Map.get(event, :"meta.key"),
"entry_meta.value": Map.get(event, :"meta.value")
}
else
%Plausible.ClickhouseSession{ %Plausible.ClickhouseSession{
sign: 1, sign: 1,
session_id: Plausible.ClickhouseSession.random_uint64(), session_id: Plausible.ClickhouseSession.random_uint64(),
@ -103,3 +151,4 @@ defmodule Plausible.Session.CacheStore do
} }
end end
end end
end

View File

@ -69,9 +69,13 @@ defmodule Plausible.Session.WriteBuffer do
|> Enum.map(&(Map.from_struct(&1) |> Map.delete(:__meta__))) |> Enum.map(&(Map.from_struct(&1) |> Map.delete(:__meta__)))
|> Enum.reverse() |> Enum.reverse()
if Plausible.v2?() do
IngestRepo.insert_all(Plausible.ClickhouseSessionV2, sessions)
else
IngestRepo.insert_all(Plausible.ClickhouseSession, sessions) IngestRepo.insert_all(Plausible.ClickhouseSession, sessions)
end end
end end
end
defp flush_interval_ms() do defp flush_interval_ms() do
Keyword.fetch!(Application.get_env(:plausible, IngestRepo), :flush_interval_ms) Keyword.fetch!(Application.get_env(:plausible, IngestRepo), :flush_interval_ms)

View File

@ -84,6 +84,9 @@ defmodule Plausible.SiteAdmin do
end end
def transfer_data([from_site], params) do def transfer_data([from_site], params) do
if Plausible.v2?() do
{:error, "Transfers temporarily unspported with v2"}
else
to_site = Repo.get_by(Plausible.Site, domain: params["domain"]) to_site = Repo.get_by(Plausible.Site, domain: params["domain"])
if to_site do if to_site do
@ -91,7 +94,9 @@ defmodule Plausible.SiteAdmin do
{:ok, _} = Ecto.Adapters.SQL.query(Plausible.ClickhouseRepo, event_q, [], timeout: 30_000) {:ok, _} = Ecto.Adapters.SQL.query(Plausible.ClickhouseRepo, event_q, [], timeout: 30_000)
session_q = session_transfer_query(from_site.domain, to_site.domain) session_q = session_transfer_query(from_site.domain, to_site.domain)
{:ok, _} = Ecto.Adapters.SQL.query(Plausible.ClickhouseRepo, session_q, [], timeout: 30_000)
{:ok, _} =
Ecto.Adapters.SQL.query(Plausible.ClickhouseRepo, session_q, [], timeout: 30_000)
start_date = Plausible.Stats.Clickhouse.pageview_start_date_local(from_site) start_date = Plausible.Stats.Clickhouse.pageview_start_date_local(from_site)
@ -106,6 +111,7 @@ defmodule Plausible.SiteAdmin do
{:error, "Cannot transfer to non-existing domain"} {:error, "Cannot transfer to non-existing domain"}
end end
end end
end
def transfer_data(_, _), do: {:error, "Please select exactly one site for this action"} def transfer_data(_, _), do: {:error, "Please select exactly one site for this action"}

View File

@ -1,9 +1,9 @@
defmodule Plausible.Site.GateKeeper do defmodule Plausible.Site.GateKeeper do
@type policy() :: :allow | :not_found | :block | :throttle @type policy() :: :allow | :not_found | :block | :throttle
@type site_id() :: pos_integer()
@policy_for_non_existing_sites :not_found @policy_for_non_existing_sites :not_found
@policy_on_rate_limiting_backend_error :allow
@type t() :: :allow | {:deny, policy()} @type t() :: {:allow, site_id()} | {:deny, policy()}
@moduledoc """ @moduledoc """
Thin wrapper around Hammer for gate keeping domain-specific events Thin wrapper around Hammer for gate keeping domain-specific events
@ -23,7 +23,7 @@ defmodule Plausible.Site.GateKeeper do
The module defines two policies outside the regular bucket inspection: The module defines two policies outside the regular bucket inspection:
* when the the site is not found in cache: #{@policy_for_non_existing_sites} * when the the site is not found in cache: #{@policy_for_non_existing_sites}
* when the underlying rate limiting mechanism returns * when the underlying rate limiting mechanism returns
an internal error: #{@policy_on_rate_limiting_backend_error} an internal error: :allow
""" """
alias Plausible.Site alias Plausible.Site
alias Plausible.Site.Cache alias Plausible.Site.Cache
@ -33,7 +33,7 @@ defmodule Plausible.Site.GateKeeper do
@spec check(String.t(), Keyword.t()) :: t() @spec check(String.t(), Keyword.t()) :: t()
def check(domain, opts \\ []) when is_binary(domain) do def check(domain, opts \\ []) when is_binary(domain) do
case policy(domain, opts) do case policy(domain, opts) do
:allow -> :allow {:allow, site_id} -> {:allow, site_id}
other -> {:deny, other} other -> {:deny, other}
end end
end end
@ -56,15 +56,15 @@ defmodule Plausible.Site.GateKeeper do
result result
end end
defp check_rate_limit(%Site{ingest_rate_limit_threshold: nil}, _opts) do defp check_rate_limit(%Site{id: site_id, ingest_rate_limit_threshold: nil}, _opts) do
:allow {:allow, site_id}
end end
defp check_rate_limit(%Site{ingest_rate_limit_threshold: 0}, _opts) do defp check_rate_limit(%Site{ingest_rate_limit_threshold: 0}, _opts) do
:block :block
end end
defp check_rate_limit(%Site{ingest_rate_limit_threshold: threshold} = site, opts) defp check_rate_limit(%Site{id: site_id, ingest_rate_limit_threshold: threshold} = site, opts)
when is_integer(threshold) do when is_integer(threshold) do
key = Keyword.get(opts, :key, key(site.domain)) key = Keyword.get(opts, :key, key(site.domain))
scale_ms = site.ingest_rate_limit_scale_seconds * 1_000 scale_ms = site.ingest_rate_limit_scale_seconds * 1_000
@ -74,14 +74,14 @@ defmodule Plausible.Site.GateKeeper do
:throttle :throttle
{:allow, _} -> {:allow, _} ->
:allow {:allow, site_id}
{:error, reason} -> {:error, reason} ->
Logger.error( Logger.error(
"Error checking rate limit for '#{key}': #{inspect(reason)}. Falling back to: #{@policy_on_rate_limiting_backend_error}" "Error checking rate limit for '#{key}': #{inspect(reason)}. Falling back to: :allow"
) )
@policy_on_rate_limiting_backend_error {:allow, site_id}
end end
end end
end end

View File

@ -1,6 +1,5 @@
defmodule Plausible.Sites do defmodule Plausible.Sites do
use Plausible.Repo use Plausible.Repo
alias Plausible.ClickhouseRepo
alias Plausible.Site alias Plausible.Site
alias Plausible.Site.SharedLink alias Plausible.Site.SharedLink
import Ecto.Query import Ecto.Query
@ -77,11 +76,6 @@ defmodule Plausible.Sites do
!!stats_start_date(site) !!stats_start_date(site)
end end
def has_events?(domain) do
q = from e in "events", where: e.domain == ^domain, select: true, limit: 1
ClickhouseRepo.one(q) == true
end
def create_shared_link(site, name, password \\ nil) do def create_shared_link(site, name, password \\ nil) do
changes = changes =
SharedLink.changeset( SharedLink.changeset(
@ -158,6 +152,13 @@ defmodule Plausible.Sites do
|> Repo.all() |> Repo.all()
end end
def owned_site_ids(user) do
user
|> owned_sites_query()
|> select([site], site.id)
|> Repo.all()
end
defp owned_sites_query(user) do defp owned_sites_query(user) do
from(s in Site, from(s in Site,
join: sm in Site.Membership, join: sm in Site.Membership,

View File

@ -35,11 +35,19 @@ defmodule Plausible.Stats.Base do
{first_datetime, last_datetime} = utc_boundaries(query, site) {first_datetime, last_datetime} = utc_boundaries(query, site)
q = q =
if Plausible.v2?() do
from(
e in "events_v2",
where: e.site_id == ^site.id,
where: e.timestamp >= ^first_datetime and e.timestamp < ^last_datetime
)
else
from( from(
e in "events", e in "events",
where: e.domain == ^site.domain, where: e.domain == ^site.domain,
where: e.timestamp >= ^first_datetime and e.timestamp < ^last_datetime where: e.timestamp >= ^first_datetime and e.timestamp < ^last_datetime
) )
end
|> add_sample_hint(query) |> add_sample_hint(query)
q = q =
@ -190,11 +198,19 @@ defmodule Plausible.Stats.Base do
{first_datetime, last_datetime} = utc_boundaries(query, site) {first_datetime, last_datetime} = utc_boundaries(query, site)
sessions_q = sessions_q =
if Plausible.v2?() do
from(
s in "sessions_v2",
where: s.site_id == ^site.id,
where: s.start >= ^first_datetime and s.start < ^last_datetime
)
else
from( from(
s in "sessions", s in "sessions",
where: s.domain == ^site.domain, where: s.domain == ^site.domain,
where: s.start >= ^first_datetime and s.start < ^last_datetime where: s.start >= ^first_datetime and s.start < ^last_datetime
) )
end
|> add_sample_hint(query) |> add_sample_hint(query)
|> filter_by_entry_props(query) |> filter_by_entry_props(query)

View File

@ -312,7 +312,7 @@ defmodule Plausible.Stats.Breakdown do
end end
defp do_group_by( defp do_group_by(
%Ecto.Query{from: %Ecto.Query.FromExpr{source: {"events", _}}} = q, %Ecto.Query{from: %Ecto.Query.FromExpr{source: {"events" <> _, _}}} = q,
"event:props:" <> prop "event:props:" <> prop
) do ) do
q = q =
@ -336,7 +336,7 @@ defmodule Plausible.Stats.Breakdown do
end end
defp do_group_by( defp do_group_by(
%Ecto.Query{from: %Ecto.Query.FromExpr{source: {"events", _}}} = q, %Ecto.Query{from: %Ecto.Query.FromExpr{source: {"events" <> _, _}}} = q,
"event:name" "event:name"
) do ) do
from( from(
@ -348,7 +348,7 @@ defmodule Plausible.Stats.Breakdown do
end end
defp do_group_by( defp do_group_by(
%Ecto.Query{from: %Ecto.Query.FromExpr{source: {"events", _}}} = q, %Ecto.Query{from: %Ecto.Query.FromExpr{source: {"events" <> _, _}}} = q,
"event:page" "event:page"
) do ) do
from( from(
@ -360,7 +360,7 @@ defmodule Plausible.Stats.Breakdown do
end end
defp do_group_by( defp do_group_by(
%Ecto.Query{from: %Ecto.Query.FromExpr{source: {"events", _}}} = q, %Ecto.Query{from: %Ecto.Query.FromExpr{source: {"events" <> _, _}}} = q,
"event:page_match" "event:page_match"
) do ) do
case Map.get(q, :__private_match_sources__) do case Map.get(q, :__private_match_sources__) do

View File

@ -8,12 +8,23 @@ defmodule Plausible.Stats.Clickhouse do
@spec pageview_start_date_local(Plausible.Site.t()) :: Date.t() | nil @spec pageview_start_date_local(Plausible.Site.t()) :: Date.t() | nil
def pageview_start_date_local(site) do def pageview_start_date_local(site) do
datetime = datetime =
if Plausible.v2?() do
ClickhouseRepo.one( ClickhouseRepo.one(
from e in "events", from(e in "events_v2",
select: fragment("min(?)", e.timestamp),
where: e.site_id == ^site.id,
where: e.timestamp >= ^site.native_stats_start_at
)
)
else
ClickhouseRepo.one(
from(e in "events",
select: fragment("min(?)", e.timestamp), select: fragment("min(?)", e.timestamp),
where: e.domain == ^site.domain, where: e.domain == ^site.domain,
where: e.timestamp >= ^site.native_stats_start_at where: e.timestamp >= ^site.native_stats_start_at
) )
)
end
case datetime do case datetime do
# no stats for this domain yet # no stats for this domain yet
@ -29,28 +40,29 @@ defmodule Plausible.Stats.Clickhouse do
def imported_pageview_count(site) do def imported_pageview_count(site) do
Plausible.ClickhouseRepo.one( Plausible.ClickhouseRepo.one(
from i in "imported_visitors", from(i in "imported_visitors",
where: i.site_id == ^site.id, where: i.site_id == ^site.id,
select: sum(i.pageviews) select: sum(i.pageviews)
) )
)
end end
def usage_breakdown(domains) do def usage_breakdown(domains_or_site_ids) do
range = range =
Date.range( Date.range(
Timex.shift(Timex.today(), days: -30), Timex.shift(Timex.today(), days: -30),
Timex.today() Timex.today()
) )
usage_breakdown(domains, range) usage_breakdown(domains_or_site_ids, range)
end end
def usage_breakdown(domains, date_range) do def usage_breakdown([d | _] = domains, date_range) when is_binary(d) do
Enum.chunk_every(domains, 300) Enum.chunk_every(domains, 300)
|> Enum.reduce({0, 0}, fn domains, {pageviews_total, custom_events_total} -> |> Enum.reduce({0, 0}, fn domains, {pageviews_total, custom_events_total} ->
{chunk_pageviews, chunk_custom_events} = {chunk_pageviews, chunk_custom_events} =
ClickhouseRepo.one( ClickhouseRepo.one(
from e in "events", from(e in "events",
where: e.domain in ^domains, where: e.domain in ^domains,
where: fragment("toDate(?)", e.timestamp) >= ^date_range.first, where: fragment("toDate(?)", e.timestamp) >= ^date_range.first,
where: fragment("toDate(?)", e.timestamp) <= ^date_range.last, where: fragment("toDate(?)", e.timestamp) <= ^date_range.last,
@ -59,11 +71,34 @@ defmodule Plausible.Stats.Clickhouse do
fragment("countIf(? != 'pageview')", e.name) fragment("countIf(? != 'pageview')", e.name)
} }
) )
)
{pageviews_total + chunk_pageviews, custom_events_total + chunk_custom_events} {pageviews_total + chunk_pageviews, custom_events_total + chunk_custom_events}
end) end)
end end
def usage_breakdown([sid | _] = site_ids, date_range) when is_integer(sid) do
Enum.chunk_every(site_ids, 300)
|> Enum.reduce({0, 0}, fn site_ids, {pageviews_total, custom_events_total} ->
{chunk_pageviews, chunk_custom_events} =
ClickhouseRepo.one(
from(e in "events_v2",
where: e.site_id in ^site_ids,
where: fragment("toDate(?)", e.timestamp) >= ^date_range.first,
where: fragment("toDate(?)", e.timestamp) <= ^date_range.last,
select: {
fragment("countIf(? = 'pageview')", e.name),
fragment("countIf(? != 'pageview')", e.name)
}
)
)
{pageviews_total + chunk_pageviews, custom_events_total + chunk_custom_events}
end)
end
def usage_breakdown([], _date_range), do: {0, 0}
def top_sources(site, query, limit, page, show_noref \\ false, include_details) do def top_sources(site, query, limit, page, show_noref \\ false, include_details) do
offset = (page - 1) * limit offset = (page - 1) * limit
@ -151,12 +186,24 @@ defmodule Plausible.Stats.Clickhouse do
def current_visitors(site, query) do def current_visitors(site, query) do
Plausible.ClickhouseRepo.one( Plausible.ClickhouseRepo.one(
from e in base_query(site, query), from(e in base_query(site, query),
select: uniq(e.user_id) select: uniq(e.user_id)
) )
)
end end
def has_pageviews?(site) do def has_pageviews?(site) do
if Plausible.v2?() do
ClickhouseRepo.exists?(
from(e in "events_v2",
where:
e.site_id == ^site.id and
e.name == "pageview" and
e.timestamp >=
^site.native_stats_start_at
)
)
else
ClickhouseRepo.exists?( ClickhouseRepo.exists?(
from(e in "events", from(e in "events",
where: where:
@ -167,31 +214,59 @@ defmodule Plausible.Stats.Clickhouse do
) )
) )
end end
end
def last_24h_visitors([]), do: %{} def last_24h_visitors([]), do: %{}
def last_24h_visitors(sites) do def last_24h_visitors(sites) do
if Plausible.v2?() do
site_id_to_domain_mapping = for site <- sites, do: {site.id, site.domain}, into: %{}
ClickhouseRepo.all(
from(e in "events_v2",
group_by: e.site_id,
where: e.site_id in ^Map.keys(site_id_to_domain_mapping),
where: e.timestamp > fragment("now() - INTERVAL 24 HOUR"),
select: {e.site_id, fragment("uniq(user_id)")}
)
)
|> Enum.map(fn {site_id, user_id} ->
{site_id_to_domain_mapping[site_id], user_id}
end)
|> Enum.into(%{})
else
domains = Enum.map(sites, & &1.domain) domains = Enum.map(sites, & &1.domain)
ClickhouseRepo.all( ClickhouseRepo.all(
from e in "events", from(e in "events",
group_by: e.domain, group_by: e.domain,
where: e.domain in ^domains, where: e.domain in ^domains,
where: e.timestamp > fragment("now() - INTERVAL 24 HOUR"), where: e.timestamp > fragment("now() - INTERVAL 24 HOUR"),
select: {e.domain, fragment("uniq(user_id)")} select: {e.domain, fragment("uniq(user_id)")}
) )
)
|> Enum.into(%{}) |> Enum.into(%{})
end end
end
# credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity
defp base_session_query(site, query) do defp base_session_query(site, query) do
{first_datetime, last_datetime} = utc_boundaries(query, site) {first_datetime, last_datetime} = utc_boundaries(query, site)
q = q =
if Plausible.v2?() do
from(s in "sessions_v2",
hints: ["SAMPLE 10000000"],
where: s.site_id == ^site.id,
where: s.timestamp >= ^first_datetime and s.start < ^last_datetime
)
else
from(s in "sessions", from(s in "sessions",
hints: ["SAMPLE 10000000"], hints: ["SAMPLE 10000000"],
where: s.domain == ^site.domain, where: s.domain == ^site.domain,
where: s.timestamp >= ^first_datetime and s.start < ^last_datetime where: s.timestamp >= ^first_datetime and s.start < ^last_datetime
) )
end
q = q =
if query.filters["source"] do if query.filters["source"] do
@ -302,15 +377,24 @@ defmodule Plausible.Stats.Clickhouse do
end end
end end
# credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity
defp base_query_bare(site, query) do defp base_query_bare(site, query) do
{first_datetime, last_datetime} = utc_boundaries(query, site) {first_datetime, last_datetime} = utc_boundaries(query, site)
q = q =
if Plausible.v2?() do
from(e in "events_v2",
hints: ["SAMPLE 10000000"],
where: e.site_id == ^site.id,
where: e.timestamp >= ^first_datetime and e.timestamp < ^last_datetime
)
else
from(e in "events", from(e in "events",
hints: ["SAMPLE 10000000"], hints: ["SAMPLE 10000000"],
where: e.domain == ^site.domain, where: e.domain == ^site.domain,
where: e.timestamp >= ^first_datetime and e.timestamp < ^last_datetime where: e.timestamp >= ^first_datetime and e.timestamp < ^last_datetime
) )
end
q = q =
if query.filters["screen"] do if query.filters["screen"] do

View File

@ -8,6 +8,14 @@ defmodule Plausible.Stats.CurrentVisitors do
|> Timex.shift(minutes: -5) |> Timex.shift(minutes: -5)
|> NaiveDateTime.truncate(:second) |> NaiveDateTime.truncate(:second)
if Plausible.v2?() do
ClickhouseRepo.one(
from e in "events_v2",
where: e.site_id == ^site.id,
where: e.timestamp >= ^first_datetime,
select: uniq(e.user_id)
)
else
ClickhouseRepo.one( ClickhouseRepo.one(
from e in "events", from e in "events",
where: e.domain == ^site.domain, where: e.domain == ^site.domain,
@ -16,3 +24,4 @@ defmodule Plausible.Stats.CurrentVisitors do
) )
end end
end end
end

View File

@ -1161,9 +1161,14 @@ defmodule PlausibleWeb.Api.StatsController do
site = conn.assigns[:site] site = conn.assigns[:site]
with :ok <- validate_params(params) do with :ok <- validate_params(params) do
query = Query.from(site, params) |> Filters.add_prefix() query =
Query.from(site, params)
|> Filters.add_prefix()
json(conn, Stats.filter_suggestions(site, query, params["filter_name"], params["q"])) json(
conn,
Stats.filter_suggestions(site, query, params["filter_name"], params["q"])
)
else else
{:error, message} when is_binary(message) -> bad_request(conn, message) {:error, message} when is_binary(message) -> bad_request(conn, message)
end end

View File

@ -10,7 +10,7 @@
"cachex": {:hex, :cachex, "3.4.0", "868b2959ea4aeb328c6b60ff66c8d5123c083466ad3c33d3d8b5f142e13101fb", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "370123b1ab4fba4d2965fb18f87fd758325709787c8c5fce35b3fe80645ccbe5"}, "cachex": {:hex, :cachex, "3.4.0", "868b2959ea4aeb328c6b60ff66c8d5123c083466ad3c33d3d8b5f142e13101fb", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "370123b1ab4fba4d2965fb18f87fd758325709787c8c5fce35b3fe80645ccbe5"},
"castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"}, "castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"},
"certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
"ch": {:git, "https://github.com/ruslandoga/ch.git", "5894f81e246c049b9db5186497189cce226947aa", []}, "ch": {:git, "https://github.com/plausible/ch.git", "f411daa07c6310d3308f81397905df65330aeb64", []},
"chatterbox": {:hex, :ts_chatterbox, "0.13.0", "6f059d97bcaa758b8ea6fffe2b3b81362bd06b639d3ea2bb088335511d691ebf", [:rebar3], [{:hpack, "~> 0.2.3", [hex: :hpack_erl, repo: "hexpm", optional: false]}], "hexpm", "b93d19104d86af0b3f2566c4cba2a57d2e06d103728246ba1ac6c3c0ff010aa7"}, "chatterbox": {:hex, :ts_chatterbox, "0.13.0", "6f059d97bcaa758b8ea6fffe2b3b81362bd06b639d3ea2bb088335511d691ebf", [:rebar3], [{:hpack, "~> 0.2.3", [hex: :hpack_erl, repo: "hexpm", optional: false]}], "hexpm", "b93d19104d86af0b3f2566c4cba2a57d2e06d103728246ba1ac6c3c0ff010aa7"},
"chto": {:git, "https://github.com/plausible/chto.git", "316421ede947541bac32a853d70b0ca8ba003220", []}, "chto": {:git, "https://github.com/plausible/chto.git", "316421ede947541bac32a853d70b0ca8ba003220", []},
"combination": {:hex, :combination, "0.0.3", "746aedca63d833293ec6e835aa1f34974868829b1486b1e1cb0685f0b2ae1f41", [:mix], [], "hexpm", "72b099f463df42ef7dc6371d250c7070b57b6c5902853f69deb894f79eda18ca"}, "combination": {:hex, :combination, "0.0.3", "746aedca63d833293ec6e835aa1f34974868829b1486b1e1cb0685f0b2ae1f41", [:mix], [], "hexpm", "72b099f463df42ef7dc6371d250c7070b57b6c5902853f69deb894f79eda18ca"},

View File

@ -1,4 +1,4 @@
SELECT partition SELECT distinct(partition)
FROM system.parts FROM system.parts
WHERE table = 'events' WHERE table = 'events'
<%= if @start_from do %>AND partition >= '<%= @start_from %>'<% end %> <%= if @start_from do %>AND partition >= '<%= @start_from %>'<% end %>

View File

@ -18,7 +18,11 @@ defmodule Plausible.AuthTest do
test "is true if user does have events" do test "is true if user does have events" do
user = insert(:user) user = insert(:user)
insert(:site, members: [user], domain: "test-site.com") site = insert(:site, members: [user])
populate_stats(site, [
build(:pageview)
])
assert Auth.has_active_sites?(user) assert Auth.has_active_sites?(user)
end end

View File

@ -133,10 +133,10 @@ defmodule Plausible.BillingTest do
site = insert(:site, members: [user]) site = insert(:site, members: [user])
create_pageviews([ create_pageviews([
%{domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]}, %{site: site, timestamp: ~N[2021-01-01 00:00:00]},
%{domain: site.domain, timestamp: ~N[2020-12-31 00:00:00]}, %{site: site, timestamp: ~N[2020-12-31 00:00:00]},
%{domain: site.domain, timestamp: ~N[2020-11-01 00:00:00]}, %{site: site, timestamp: ~N[2020-11-01 00:00:00]},
%{domain: site.domain, timestamp: ~N[2020-10-31 00:00:00]} %{site: site, timestamp: ~N[2020-10-31 00:00:00]}
]) ])
assert Billing.last_two_billing_months_usage(user, today) == {1, 1} assert Billing.last_two_billing_months_usage(user, today) == {1, 1}
@ -163,10 +163,10 @@ defmodule Plausible.BillingTest do
) )
create_pageviews([ create_pageviews([
%{domain: owner_site.domain, timestamp: ~N[2020-12-31 00:00:00]}, %{site: owner_site, timestamp: ~N[2020-12-31 00:00:00]},
%{domain: admin_site.domain, timestamp: ~N[2020-12-31 00:00:00]}, %{site: admin_site, timestamp: ~N[2020-12-31 00:00:00]},
%{domain: owner_site.domain, timestamp: ~N[2020-11-01 00:00:00]}, %{site: owner_site, timestamp: ~N[2020-11-01 00:00:00]},
%{domain: admin_site.domain, timestamp: ~N[2020-11-01 00:00:00]} %{site: admin_site, timestamp: ~N[2020-11-01 00:00:00]}
]) ])
assert Billing.last_two_billing_months_usage(user, today) == {1, 1} assert Billing.last_two_billing_months_usage(user, today) == {1, 1}

View File

@ -37,7 +37,13 @@ defmodule Plausible.Session.CacheStoreTest do
assert_receive({WriteBuffer, :insert, [sessions]}) assert_receive({WriteBuffer, :insert, [sessions]})
assert [session] = sessions assert [session] = sessions
assert session.hostname == event.hostname assert session.hostname == event.hostname
if Plausible.v2?() do
assert session.site_id == event.site_id
else
assert session.domain == event.domain assert session.domain == event.domain
end
assert session.user_id == event.user_id assert session.user_id == event.user_id
assert session.entry_page == event.pathname assert session.entry_page == event.pathname
assert session.exit_page == event.pathname assert session.exit_page == event.pathname
@ -68,12 +74,9 @@ defmodule Plausible.Session.CacheStoreTest do
timestamp = Timex.now() timestamp = Timex.now()
event1 = build(:event, name: "pageview", timestamp: timestamp |> Timex.shift(seconds: -10)) event1 = build(:event, name: "pageview", timestamp: timestamp |> Timex.shift(seconds: -10))
event2 = event2 = %{
build(:event, event1
domain: event1.domain, | timestamp: timestamp,
user_id: event1.user_id,
name: "pageview",
timestamp: timestamp,
country_code: "US", country_code: "US",
subdivision1_code: "SUB1", subdivision1_code: "SUB1",
subdivision2_code: "SUB2", subdivision2_code: "SUB2",
@ -83,7 +86,7 @@ defmodule Plausible.Session.CacheStoreTest do
operating_system_version: "11", operating_system_version: "11",
browser: "Firefox", browser: "Firefox",
browser_version: "10" browser_version: "10"
) }
CacheStore.on_event(event1, nil, buffer) CacheStore.on_event(event1, nil, buffer)
CacheStore.on_event(event2, nil, buffer) CacheStore.on_event(event2, nil, buffer)
@ -107,13 +110,7 @@ defmodule Plausible.Session.CacheStoreTest do
timestamp = Timex.now() timestamp = Timex.now()
event1 = build(:event, name: "pageview", timestamp: timestamp |> Timex.shift(seconds: 10)) event1 = build(:event, name: "pageview", timestamp: timestamp |> Timex.shift(seconds: 10))
event2 = event2 = %{event1 | timestamp: timestamp}
build(:event,
domain: event1.domain,
user_id: event1.user_id,
name: "pageview",
timestamp: timestamp
)
CacheStore.on_event(event1, nil, buffer) CacheStore.on_event(event1, nil, buffer)
CacheStore.on_event(event2, nil, buffer) CacheStore.on_event(event2, nil, buffer)

View File

@ -1,10 +1,18 @@
defmodule Plausible.SiteAdminTest do defmodule Plausible.SiteAdminTest do
use Plausible.DataCase, async: true use Plausible.DataCase, async: true
alias Plausible.{SiteAdmin, ClickhouseRepo, ClickhouseEvent, ClickhouseSession} alias Plausible.{
SiteAdmin,
ClickhouseRepo,
ClickhouseEvent,
ClickhouseSession
}
describe "transfer_data" do describe "transfer_data" do
test "event and session structs remain the same after transfer" do test "event and session structs remain the same after transfer" do
if Plausible.v2?() do
:ok
else
from_site = insert(:site) from_site = insert(:site)
to_site = insert(:site) to_site = insert(:site)
@ -18,13 +26,18 @@ defmodule Plausible.SiteAdminTest do
event_after = get_event_by_domain(to_site.domain) event_after = get_event_by_domain(to_site.domain)
session_after = get_session_by_domain(to_site.domain) session_after = get_session_by_domain(to_site.domain)
assert event_before == %ClickhouseEvent{event_after | transferred_from: ""}
assert event_before == %ClickhouseEvent{event_after | transferred_from: ""} assert event_before == %ClickhouseEvent{event_after | transferred_from: ""}
assert session_before == %ClickhouseSession{session_after | transferred_from: ""} assert session_before == %ClickhouseSession{session_after | transferred_from: ""}
assert event_after.transferred_from == from_site.domain assert event_after.transferred_from == from_site.domain
assert session_after.transferred_from == from_site.domain assert session_after.transferred_from == from_site.domain
end end
end
test "transfers all events and sessions" do test "transfers all events and sessions" do
if Plausible.v2?() do
:ok
else
from_site = insert(:site) from_site = insert(:site)
to_site = insert(:site) to_site = insert(:site)
@ -50,8 +63,12 @@ defmodule Plausible.SiteAdminTest do
assert length(transferred_events) == 4 assert length(transferred_events) == 4
assert length(transferred_sessions) == 3 assert length(transferred_sessions) == 3
end end
end
test "updates stats_start_date on site record" do test "updates stats_start_date on site record" do
if Plausible.v2?() do
:ok
else
from_site = insert(:site) from_site = insert(:site)
to_site = insert(:site) to_site = insert(:site)
@ -61,8 +78,12 @@ defmodule Plausible.SiteAdminTest do
assert Repo.reload(to_site).stats_start_date == ~D[2022-01-01] assert Repo.reload(to_site).stats_start_date == ~D[2022-01-01]
end end
end
test "updates native_stats_start_date on based on the from_site record" do test "updates native_stats_start_date on based on the from_site record" do
if Plausible.v2?() do
:ok
else
from_site = insert(:site, native_stats_start_at: ~N[2022-01-01 01:00:00]) from_site = insert(:site, native_stats_start_at: ~N[2022-01-01 01:00:00])
to_site = insert(:site) to_site = insert(:site)
@ -72,6 +93,7 @@ defmodule Plausible.SiteAdminTest do
assert Repo.reload(to_site).native_stats_start_at == ~N[2022-01-01 01:00:00] assert Repo.reload(to_site).native_stats_start_at == ~N[2022-01-01 01:00:00]
end end
end
test "session_transfer_query" do test "session_transfer_query" do
actual = SiteAdmin.session_transfer_query("from.com", "to.com") actual = SiteAdmin.session_transfer_query("from.com", "to.com")

View File

@ -19,20 +19,21 @@ defmodule Plausible.Site.GateKeeperTest do
test "site from cache with no ingest_rate_limit_threshold is allowed", %{test: test, opts: opts} do test "site from cache with no ingest_rate_limit_threshold is allowed", %{test: test, opts: opts} do
domain = "site1.example.com" domain = "site1.example.com"
add_site_and_refresh_cache(test, domain: domain) %{id: site_id} = add_site_and_refresh_cache(test, domain: domain)
assert :allow = GateKeeper.check(domain, opts) assert {:allow, ^site_id} = GateKeeper.check(domain, opts)
end end
test "rate limiting works with threshold", %{test: test, opts: opts} do test "rate limiting works with threshold", %{test: test, opts: opts} do
domain = "site1.example.com" domain = "site1.example.com"
%{id: site_id} =
add_site_and_refresh_cache(test, add_site_and_refresh_cache(test,
domain: domain, domain: domain,
ingest_rate_limit_threshold: 1, ingest_rate_limit_threshold: 1,
ingest_rate_limit_scale_seconds: 60 ingest_rate_limit_scale_seconds: 60
) )
assert :allow = GateKeeper.check(domain, opts) assert {:allow, ^site_id} = GateKeeper.check(domain, opts)
assert {:deny, :throttle} = GateKeeper.check(domain, opts) assert {:deny, :throttle} = GateKeeper.check(domain, opts)
assert {:deny, :throttle} = GateKeeper.check(domain, opts) assert {:deny, :throttle} = GateKeeper.check(domain, opts)
end end
@ -40,17 +41,18 @@ defmodule Plausible.Site.GateKeeperTest do
test "rate limiting works with scale window", %{test: test, opts: opts} do test "rate limiting works with scale window", %{test: test, opts: opts} do
domain = "site1.example.com" domain = "site1.example.com"
%{id: site_id} =
add_site_and_refresh_cache(test, add_site_and_refresh_cache(test,
domain: domain, domain: domain,
ingest_rate_limit_threshold: 1, ingest_rate_limit_threshold: 1,
ingest_rate_limit_scale_seconds: 1 ingest_rate_limit_scale_seconds: 1
) )
assert :allow = GateKeeper.check(domain, opts) assert {:allow, ^site_id} = GateKeeper.check(domain, opts)
Process.sleep(1) Process.sleep(1)
assert {:deny, :throttle} = GateKeeper.check(domain, opts) assert {:deny, :throttle} = GateKeeper.check(domain, opts)
Process.sleep(1_000) Process.sleep(1_000)
assert :allow = GateKeeper.check(domain, opts) assert {:allow, ^site_id} = GateKeeper.check(domain, opts)
end end
test "rate limiting prioritises cache lookups", %{test: test, opts: opts} do test "rate limiting prioritises cache lookups", %{test: test, opts: opts} do
@ -67,8 +69,9 @@ defmodule Plausible.Site.GateKeeperTest do
# We need some dummy site, otherwise the cache won't refresh in case the DB # We need some dummy site, otherwise the cache won't refresh in case the DB
# is completely empty # is completely empty
insert(:site) insert(:site)
deleted_site_id = site.id
assert :allow = GateKeeper.check(domain, opts) assert {:allow, ^deleted_site_id} = GateKeeper.check(domain, opts)
:ok = Cache.refresh_all(opts[:cache_opts]) :ok = Cache.refresh_all(opts[:cache_opts])
assert {:deny, :not_found} = GateKeeper.check(domain, opts) assert {:deny, :not_found} = GateKeeper.check(domain, opts)
end end
@ -86,18 +89,19 @@ defmodule Plausible.Site.GateKeeperTest do
ingest_rate_limit_scale_seconds: 600 ingest_rate_limit_scale_seconds: 600
) )
assert :allow = GateKeeper.check(domain, opts) site_id = site.id
assert {:allow, ^site_id} = GateKeeper.check(domain, opts)
assert {:deny, :throttle} = GateKeeper.check(domain, opts) assert {:deny, :throttle} = GateKeeper.check(domain, opts)
{:ok, :broken} = break_hammer(site) {:ok, :broken} = break_hammer(site)
log = log =
capture_log(fn -> capture_log(fn ->
assert :allow = GateKeeper.check(domain, opts) assert {:allow, ^site_id} = GateKeeper.check(domain, opts)
end) end)
assert log =~ "Error checking rate limit for 'ingest:site:causingerrors.example.com'" assert log =~ "Error checking rate limit for 'ingest:site:causingerrors.example.com'"
assert log =~ "Falling back to: allow" assert log =~ "Falling back to: :allow"
end end
# We need a way to force Hammer to error-out on Hammer.check_rate/3. # We need a way to force Hammer to error-out on Hammer.check_rate/3.

View File

@ -97,10 +97,10 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "aggregates a single metric", %{conn: conn, site: site} do test "aggregates a single metric", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, user_id: @user_id, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, user_id: @user_id, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, user_id: @user_id, domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, user_id: @user_id, timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -120,12 +120,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
conn: conn, conn: conn,
site: site site: site
} do } do
populate_stats([ populate_stats(site, [
build(:pageview, user_id: @user_id, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, user_id: @user_id, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, user_id: @user_id, domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, user_id: @user_id, timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, user_id: 456, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, user_id: 456, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, user_id: 456, domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, user_id: 456, timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -145,10 +145,10 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
conn: conn, conn: conn,
site: site site: site
} do } do
populate_stats([ populate_stats(site, [
build(:pageview, user_id: @user_id, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, user_id: @user_id, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, user_id: @user_id, domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, user_id: @user_id, timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -171,19 +171,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
describe "comparisons" do describe "comparisons" do
test "compare period=day with previous period", %{conn: conn, site: site} do test "compare period=day with previous period", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, domain: site.domain, timestamp: ~N[2020-12-31 00:00:00]), build(:pageview, timestamp: ~N[2020-12-31 00:00:00]),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -204,19 +202,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "compare period=6mo with previous period", %{conn: conn, site: site} do test "compare period=6mo with previous period", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, domain: site.domain, timestamp: ~N[2020-12-31 00:00:00]), build(:pageview, timestamp: ~N[2020-12-31 00:00:00]),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-02-01 00:25:00] timestamp: ~N[2021-02-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-03-01 00:00:00]) build(:pageview, timestamp: ~N[2021-03-01 00:00:00])
]) ])
conn = conn =
@ -239,19 +235,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
describe "filters" do describe "filters" do
test "can filter by source", %{conn: conn, site: site} do test "can filter by source", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
referrer_source: "Google", referrer_source: "Google",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -272,20 +266,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by no source/referrer", %{conn: conn, site: site} do test "can filter by no source/referrer", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
referrer_source: "Google", referrer_source: "Google",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -308,19 +299,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by referrer", %{conn: conn, site: site} do test "can filter by referrer", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
referrer: "https://facebook.com", referrer: "https://facebook.com",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -341,19 +330,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by utm_medium", %{conn: conn, site: site} do test "can filter by utm_medium", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
utm_medium: "social", utm_medium: "social",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -374,19 +361,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by utm_source", %{conn: conn, site: site} do test "can filter by utm_source", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
utm_source: "Twitter", utm_source: "Twitter",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -407,19 +392,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by utm_campaign", %{conn: conn, site: site} do test "can filter by utm_campaign", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
utm_campaign: "profile", utm_campaign: "profile",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -440,19 +423,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by device type", %{conn: conn, site: site} do test "can filter by device type", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
screen_size: "Desktop", screen_size: "Desktop",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -473,19 +454,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by browser", %{conn: conn, site: site} do test "can filter by browser", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
browser: "Chrome", browser: "Chrome",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -506,20 +485,18 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by browser version", %{conn: conn, site: site} do test "can filter by browser version", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
browser: "Chrome", browser: "Chrome",
browser_version: "56", browser_version: "56",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -540,19 +517,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by operating system", %{conn: conn, site: site} do test "can filter by operating system", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
operating_system: "Mac", operating_system: "Mac",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -573,19 +548,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by operating system version", %{conn: conn, site: site} do test "can filter by operating system version", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
operating_system_version: "10.5", operating_system_version: "10.5",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -606,19 +579,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "can filter by country", %{conn: conn, site: site} do test "can filter by country", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
country_code: "EE", country_code: "EE",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -642,22 +613,19 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
conn: conn, conn: conn,
site: site site: site
} do } do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
pathname: "/blogpost", pathname: "/blogpost",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, build(:pageview,
pathname: "/blogpost", pathname: "/blogpost",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -680,25 +648,22 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "filtering by event:name", %{conn: conn, site: site} do test "filtering by event:name", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Signup", name: "Signup",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
domain: site.domain,
user_id: @user_id, user_id: @user_id,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
domain: site.domain,
user_id: @user_id, user_id: @user_id,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -717,23 +682,20 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
end end
test "combining filters", %{conn: conn, site: site} do test "combining filters", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
pathname: "/blogpost", pathname: "/blogpost",
country_code: "EE", country_code: "EE",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, build(:pageview,
pathname: "/blogpost", pathname: "/blogpost",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -830,15 +792,54 @@ defmodule PlausibleWeb.Api.ExternalStatsController.AggregateTest do
site: site site: site
} do } do
create_sessions([ create_sessions([
%{domain: site.domain, session_id: 1000, country_code: "EE", sign: 1, events: 1}, %{
%{domain: site.domain, session_id: 1000, country_code: "EE", sign: -1, events: 1}, domain: site.domain,
%{domain: site.domain, session_id: 1000, country_code: "EE", sign: 1, events: 2} site_id: site.id,
session_id: 1000,
country_code: "EE",
sign: 1,
events: 1
},
%{
domain: site.domain,
site_id: site.id,
session_id: 1000,
country_code: "EE",
sign: -1,
events: 1
},
%{
domain: site.domain,
site_id: site.id,
session_id: 1000,
country_code: "EE",
sign: 1,
events: 2
}
]) ])
create_events([ create_events([
%{domain: site.domain, session_id: 1000, country_code: "EE", name: "pageview"}, %{
%{domain: site.domain, session_id: 1000, country_code: "EE", name: "pageview"}, domain: site.domain,
%{domain: site.domain, session_id: 1000, country_code: "EE", name: "pageview"} site_id: site.id,
session_id: 1000,
country_code: "EE",
name: "pageview"
},
%{
domain: site.domain,
site_id: site.id,
session_id: 1000,
country_code: "EE",
name: "pageview"
},
%{
domain: site.domain,
site_id: site.id,
session_id: 1000,
country_code: "EE",
name: "pageview"
}
]) ])
conn = conn =

View File

@ -131,20 +131,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:source", %{conn: conn, site: site} do test "breakdown by visit:source", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
referrer_source: "Google", referrer_source: "Google",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
referrer_source: "Google", referrer_source: "Google",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
referrer_source: "", referrer_source: "",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -166,10 +163,10 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:country", %{conn: conn, site: site} do test "breakdown by visit:country", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, country_code: "EE", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, country_code: "EE", timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, country_code: "EE", domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, country_code: "EE", timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, country_code: "US", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, country_code: "US", timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -189,20 +186,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:referrer", %{conn: conn, site: site} do test "breakdown by visit:referrer", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
referrer: "https://ref.com", referrer: "https://ref.com",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
referrer: "https://ref.com", referrer: "https://ref.com",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
referrer: "", referrer: "",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -224,20 +218,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:utm_medium", %{conn: conn, site: site} do test "breakdown by visit:utm_medium", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
utm_medium: "Search", utm_medium: "Search",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
utm_medium: "Search", utm_medium: "Search",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
utm_medium: "", utm_medium: "",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -259,20 +250,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:utm_source", %{conn: conn, site: site} do test "breakdown by visit:utm_source", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
utm_source: "Google", utm_source: "Google",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
utm_source: "Google", utm_source: "Google",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
utm_source: "", utm_source: "",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -390,20 +378,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:device", %{conn: conn, site: site} do test "breakdown by visit:device", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
screen_size: "Desktop", screen_size: "Desktop",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
screen_size: "Desktop", screen_size: "Desktop",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
screen_size: "Mobile", screen_size: "Mobile",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -425,20 +410,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:os", %{conn: conn, site: site} do test "breakdown by visit:os", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
operating_system: "Mac", operating_system: "Mac",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
operating_system: "Mac", operating_system: "Mac",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
operating_system: "Windows", operating_system: "Windows",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -460,20 +442,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:os_version", %{conn: conn, site: site} do test "breakdown by visit:os_version", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
operating_system_version: "10.5", operating_system_version: "10.5",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
operating_system_version: "10.5", operating_system_version: "10.5",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
operating_system_version: "10.6", operating_system_version: "10.6",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -495,10 +474,10 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:browser", %{conn: conn, site: site} do test "breakdown by visit:browser", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, browser: "Firefox", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, browser: "Firefox", timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, browser: "Firefox", domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, browser: "Firefox", timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, browser: "Safari", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, browser: "Safari", timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -518,20 +497,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by visit:browser_version", %{conn: conn, site: site} do test "breakdown by visit:browser_version", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
browser_version: "56", browser_version: "56",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
browser_version: "56", browser_version: "56",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
browser_version: "57", browser_version: "57",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -553,12 +529,11 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by event:page", %{conn: conn, site: site} do test "breakdown by event:page", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, pathname: "/", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, pathname: "/", timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, pathname: "/", domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, pathname: "/", timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -583,12 +558,11 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
conn: conn, conn: conn,
site: site site: site
} do } do
populate_stats([ populate_stats(site, [
build(:pageview, pathname: "/", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, pathname: "/", timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, pathname: "/", domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, pathname: "/", timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -609,19 +583,16 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
describe "custom events" do describe "custom events" do
test "can breakdown by event:name", %{conn: conn, site: site} do test "can breakdown by event:name", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Signup", name: "Signup",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
) )
]) ])
@ -643,40 +614,34 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "can breakdown by event:name with visitors and events metrics", %{conn: conn, site: site} do test "can breakdown by event:name with visitors and events metrics", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
domain: site.domain,
pathname: "/non-existing", pathname: "/non-existing",
user_id: @user_id, user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "404", name: "404",
domain: site.domain,
pathname: "/non-existing", pathname: "/non-existing",
user_id: @user_id, user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
domain: site.domain,
pathname: "/non-existing", pathname: "/non-existing",
timestamp: ~N[2021-01-01 00:00:01] timestamp: ~N[2021-01-01 00:00:01]
), ),
build(:pageview, build(:pageview,
domain: site.domain,
pathname: "/non-existing", pathname: "/non-existing",
user_id: @user_id, user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:02] timestamp: ~N[2021-01-01 00:00:02]
), ),
build(:event, build(:event,
name: "404", name: "404",
domain: site.domain,
pathname: "/non-existing", pathname: "/non-existing",
user_id: @user_id, user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:02] timestamp: ~N[2021-01-01 00:00:02]
), ),
build(:pageview, build(:pageview,
domain: site.domain,
pathname: "/non-existing", pathname: "/non-existing",
user_id: @user_id, user_id: @user_id,
timestamp: ~N[2021-01-01 00:00:03] timestamp: ~N[2021-01-01 00:00:03]
@ -701,39 +666,34 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "can breakdown by event:name while filtering for something", %{conn: conn, site: site} do test "can breakdown by event:name while filtering for something", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Signup", name: "Signup",
pathname: "/pageA", pathname: "/pageA",
browser: "Chrome", browser: "Chrome",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
pathname: "/pageA", pathname: "/pageA",
browser: "Chrome", browser: "Chrome",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
pathname: "/pageA", pathname: "/pageA",
browser: "Safari", browser: "Safari",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
pathname: "/pageB", pathname: "/pageB",
browser: "Chrome", browser: "Chrome",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/pageA", pathname: "/pageA",
browser: "Chrome", browser: "Chrome",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
) )
]) ])
@ -759,21 +719,18 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
conn: conn, conn: conn,
site: site site: site
} do } do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
referrer_source: "Google", referrer_source: "Google",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
domain: site.domain,
referrer_source: "Twitter", referrer_source: "Twitter",
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
) )
@ -796,26 +753,22 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "can breakdown by event:name when filtering by event:page", %{conn: conn, site: site} do test "can breakdown by event:name when filtering by event:page", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
pathname: "/pageA", pathname: "/pageA",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/pageA", pathname: "/pageA",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
pathname: "/pageA", pathname: "/pageA",
name: "Signup", name: "Signup",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/pageB", pathname: "/pageB",
domain: site.domain,
referrer_source: "Twitter", referrer_source: "Twitter",
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
) )
@ -839,28 +792,24 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "can breakdown by event:page when filtering by event:name", %{conn: conn, site: site} do test "can breakdown by event:page when filtering by event:name", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Signup", name: "Signup",
pathname: "/pageA", pathname: "/pageA",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
pathname: "/pageA", pathname: "/pageA",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
pathname: "/pageB", pathname: "/pageB",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/pageB", pathname: "/pageB",
domain: site.domain,
referrer_source: "Twitter", referrer_source: "Twitter",
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
) )
@ -911,33 +860,29 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by custom event property", %{conn: conn, site: site} do test "breakdown by custom event property", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["business"], "meta.value": ["business"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["personal"], "meta.value": ["personal"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["business"], "meta.value": ["business"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
name: "Some other event", name: "Some other event",
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["business"], "meta.value": ["business"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
) )
]) ])
@ -960,45 +905,39 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by custom event property, with (none)", %{conn: conn, site: site} do test "breakdown by custom event property, with (none)", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["16"], "meta.value": ["16"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["16"], "meta.value": ["16"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["16"], "meta.value": ["16"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["14"], "meta.value": ["14"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["14"], "meta.value": ["14"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:26:00] timestamp: ~N[2021-01-01 00:26:00]
) )
]) ])
@ -1022,33 +961,29 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by custom event property, limited", %{conn: conn, site: site} do test "breakdown by custom event property, limited", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["16"], "meta.value": ["16"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["18"], "meta.value": ["18"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["14"], "meta.value": ["14"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["14"], "meta.value": ["14"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:26:00] timestamp: ~N[2021-01-01 00:26:00]
) )
]) ])
@ -1072,40 +1007,35 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "breakdown by custom event property, paginated", %{conn: conn, site: site} do test "breakdown by custom event property, paginated", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["16"], "meta.value": ["16"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["16"], "meta.value": ["16"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["18"], "meta.value": ["18"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["14"], "meta.value": ["14"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["cost"], "meta.key": ["cost"],
"meta.value": ["14"], "meta.value": ["14"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:26:00] timestamp: ~N[2021-01-01 00:26:00]
) )
]) ])
@ -1135,14 +1065,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
insert(:goal, %{domain: site.domain, event_name: "Purchase"}) insert(:goal, %{domain: site.domain, event_name: "Purchase"})
insert(:goal, %{domain: site.domain, page_path: "/test"}) insert(:goal, %{domain: site.domain, page_path: "/test"})
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00], timestamp: ~N[2021-01-01 00:00:00],
pathname: "/test" pathname: "/test"
), ),
build(:pageview, build(:pageview,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:01], timestamp: ~N[2021-01-01 00:00:01],
pathname: "/test", pathname: "/test",
"meta.key": ["method"], "meta.key": ["method"],
@ -1150,14 +1078,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
), ),
build(:event, build(:event,
name: "404", name: "404",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:02], timestamp: ~N[2021-01-01 00:00:02],
"meta.key": ["method"], "meta.key": ["method"],
"meta.value": ["HTTP"] "meta.value": ["HTTP"]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:02], timestamp: ~N[2021-01-01 00:00:02],
"meta.key": ["method"], "meta.key": ["method"],
"meta.value": ["HTTPS"] "meta.value": ["HTTPS"]
@ -1165,14 +1091,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
build(:event, build(:event,
name: "404", name: "404",
timestamp: ~N[2021-01-01 00:00:03], timestamp: ~N[2021-01-01 00:00:03],
domain: site.domain,
"meta.key": ["OS", "method"], "meta.key": ["OS", "method"],
"meta.value": ["Linux", "HTTP"] "meta.value": ["Linux", "HTTP"]
), ),
build(:event, build(:event,
name: "404", name: "404",
timestamp: ~N[2021-01-01 00:00:04], timestamp: ~N[2021-01-01 00:00:04],
domain: site.domain,
"meta.key": ["version"], "meta.key": ["version"],
"meta.value": ["1"] "meta.value": ["1"]
) )
@ -1213,29 +1137,25 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
describe "filtering" do describe "filtering" do
test "event:page filter for breakdown by session props", %{conn: conn, site: site} do test "event:page filter for breakdown by session props", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
pathname: "/ignore", pathname: "/ignore",
browser: "Chrome", browser: "Chrome",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
browser: "Chrome", browser: "Chrome",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
browser: "Chrome", browser: "Chrome",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:pageview, build(:pageview,
browser: "Safari", browser: "Safari",
pathname: "/plausible.io", pathname: "/plausible.io",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -1409,25 +1329,21 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "IN filter for event:page", %{conn: conn, site: site} do test "IN filter for event:page", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
pathname: "/ignore", pathname: "/ignore",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/important-page", pathname: "/important-page",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -1450,29 +1366,25 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "IN filter for visit:browser", %{conn: conn, site: site} do test "IN filter for visit:browser", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
pathname: "/ignore", pathname: "/ignore",
browser: "Firefox", browser: "Firefox",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
browser: "Chrome", browser: "Chrome",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
browser: "Safari", browser: "Safari",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/important-page", pathname: "/important-page",
browser: "Safari", browser: "Safari",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -1495,25 +1407,21 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "IN filter for visit:entry_page", %{conn: conn, site: site} do test "IN filter for visit:entry_page", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
pathname: "/ignore", pathname: "/ignore",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/important-page", pathname: "/important-page",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -1537,25 +1445,21 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "IN filter for event:name", %{conn: conn, site: site} do test "IN filter for event:name", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Signup", name: "Signup",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Signup", name: "Signup",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Login", name: "Login",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Irrelevant", name: "Irrelevant",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -1603,10 +1507,10 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
describe "pagination" do describe "pagination" do
test "can limit results", %{conn: conn, site: site} do test "can limit results", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, pathname: "/a", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, pathname: "/a", timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, pathname: "/b", domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, pathname: "/b", timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, pathname: "/c", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, pathname: "/c", timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -1623,11 +1527,11 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "does not repeat results", %{conn: conn, site: site} do test "does not repeat results", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, %{domain: site.domain, "meta.key": ["item"], "meta.value": ["apple"]}), build(:pageview, %{"meta.key": ["item"], "meta.value": ["apple"]}),
build(:pageview, %{domain: site.domain, "meta.key": ["item"], "meta.value": ["kiwi"]}), build(:pageview, %{"meta.key": ["item"], "meta.value": ["kiwi"]}),
build(:pageview, %{domain: site.domain, "meta.key": ["item"], "meta.value": ["pineapple"]}), build(:pageview, %{"meta.key": ["item"], "meta.value": ["pineapple"]}),
build(:pageview, %{domain: site.domain, "meta.key": ["item"], "meta.value": ["grapes"]}) build(:pageview, %{"meta.key": ["item"], "meta.value": ["grapes"]})
]) ])
params = %{ params = %{
@ -1693,10 +1597,10 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "can paginate results", %{conn: conn, site: site} do test "can paginate results", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, pathname: "/a", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, pathname: "/a", timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, pathname: "/b", domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, pathname: "/b", timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, pathname: "/c", domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, pathname: "/c", timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -1820,13 +1724,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "filter by custom event property", %{conn: conn, site: site} do test "filter by custom event property", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["business"], "meta.value": ["business"],
browser: "Chrome", browser: "Chrome",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
@ -1834,7 +1737,6 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["business"], "meta.value": ["business"],
browser: "Safari", browser: "Safari",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
@ -1842,7 +1744,6 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["business"], "meta.value": ["business"],
browser: "Safari", browser: "Safari",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
@ -1850,7 +1751,6 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["personal"], "meta.value": ["personal"],
browser: "IE", browser: "IE",
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
) )
]) ])
@ -1873,23 +1773,20 @@ defmodule PlausibleWeb.Api.ExternalStatsController.BreakdownTest do
end end
test "all metrics for breakdown by event prop", %{conn: conn, site: site} do test "all metrics for breakdown by event prop", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
user_id: 1, user_id: 1,
pathname: "/", pathname: "/",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: 1, user_id: 1,
pathname: "/plausible.io", pathname: "/plausible.io",
domain: site.domain,
timestamp: ~N[2021-01-01 00:10:00] timestamp: ~N[2021-01-01 00:10:00]
), ),
build(:pageview, pathname: "/", domain: site.domain, timestamp: ~N[2021-01-01 00:25:00]), build(:pageview, pathname: "/", timestamp: ~N[2021-01-01 00:25:00]),
build(:pageview, build(:pageview,
pathname: "/plausible.io", pathname: "/plausible.io",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])

View File

@ -261,9 +261,9 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "shows last 7 days of visitors", %{conn: conn, site: site} do test "shows last 7 days of visitors", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-07 23:59:00]) build(:pageview, timestamp: ~N[2021-01-07 23:59:00])
]) ])
conn = conn =
@ -287,10 +287,10 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "shows last 6 months of visitors", %{conn: conn, site: site} do test "shows last 6 months of visitors", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, domain: site.domain, timestamp: ~N[2020-12-31 00:00:00]), build(:pageview, timestamp: ~N[2020-12-31 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -313,11 +313,11 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "shows last 12 months of visitors", %{conn: conn, site: site} do test "shows last 12 months of visitors", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, domain: site.domain, timestamp: ~N[2020-02-01 00:00:00]), build(:pageview, timestamp: ~N[2020-02-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2020-12-31 00:00:00]), build(:pageview, timestamp: ~N[2020-12-31 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -346,11 +346,11 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "shows last 12 months of visitors with interval daily", %{conn: conn, site: site} do test "shows last 12 months of visitors with interval daily", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, domain: site.domain, timestamp: ~N[2020-02-01 00:00:00]), build(:pageview, timestamp: ~N[2020-02-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2020-12-31 00:00:00]), build(:pageview, timestamp: ~N[2020-12-31 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -365,10 +365,10 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "shows a custom range with daily interval", %{conn: conn, site: site} do test "shows a custom range with daily interval", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-02 00:00:00]) build(:pageview, timestamp: ~N[2021-01-02 00:00:00])
]) ])
conn = conn =
@ -387,11 +387,11 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "shows a custom range with monthly interval", %{conn: conn, site: site} do test "shows a custom range with monthly interval", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, user_id: @user_id, domain: site.domain, timestamp: ~N[2020-12-01 00:00:00]), build(:pageview, user_id: @user_id, timestamp: ~N[2020-12-01 00:00:00]),
build(:pageview, user_id: @user_id, domain: site.domain, timestamp: ~N[2020-12-01 00:05:00]), build(:pageview, user_id: @user_id, timestamp: ~N[2020-12-01 00:05:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-02 00:00:00]) build(:pageview, timestamp: ~N[2021-01-02 00:00:00])
]) ])
conn = conn =
@ -425,13 +425,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
describe "filters" do describe "filters" do
test "can filter by source", %{conn: conn, site: site} do test "can filter by source", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
referrer_source: "Google", referrer_source: "Google",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -447,11 +446,10 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by no source/referrer", %{conn: conn, site: site} do test "can filter by no source/referrer", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, build(:pageview,
referrer_source: "Google", referrer_source: "Google",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -469,13 +467,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by referrer", %{conn: conn, site: site} do test "can filter by referrer", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
referrer: "https://facebook.com", referrer: "https://facebook.com",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -491,13 +488,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by utm_medium", %{conn: conn, site: site} do test "can filter by utm_medium", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
utm_medium: "social", utm_medium: "social",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -513,13 +509,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by utm_source", %{conn: conn, site: site} do test "can filter by utm_source", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
utm_source: "Twitter", utm_source: "Twitter",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -535,13 +530,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by utm_campaign", %{conn: conn, site: site} do test "can filter by utm_campaign", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
utm_campaign: "profile", utm_campaign: "profile",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -557,13 +551,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by device type", %{conn: conn, site: site} do test "can filter by device type", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
screen_size: "Desktop", screen_size: "Desktop",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -579,20 +572,18 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by browser", %{conn: conn, site: site} do test "can filter by browser", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
browser: "Chrome", browser: "Chrome",
browser_version: "56.1", browser_version: "56.1",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
browser: "Chrome", browser: "Chrome",
browser_version: "55", browser_version: "55",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -608,26 +599,23 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by operating system", %{conn: conn, site: site} do test "can filter by operating system", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
operating_system: "Mac", operating_system: "Mac",
operating_system_version: "10.5", operating_system_version: "10.5",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
operating_system: "Something else", operating_system: "Something else",
operating_system_version: "10.5", operating_system_version: "10.5",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
operating_system: "Mac", operating_system: "Mac",
operating_system_version: "10.4", operating_system_version: "10.4",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -643,22 +631,20 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by country", %{conn: conn, site: site} do test "can filter by country", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
country_code: "EE", country_code: "EE",
operating_system_version: "10.5", operating_system_version: "10.5",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
country_code: "EE", country_code: "EE",
operating_system_version: "10.5", operating_system_version: "10.5",
domain: site.domain,
timestamp: ~N[2021-01-01 00:15:00] timestamp: ~N[2021-01-01 00:15:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -685,26 +671,22 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
conn: conn, conn: conn,
site: site site: site
} do } do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/hello", pathname: "/hello",
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:05:00] timestamp: ~N[2021-01-01 00:05:00]
), ),
build(:pageview, build(:pageview,
pathname: "/hello", pathname: "/hello",
domain: site.domain,
timestamp: ~N[2021-01-01 05:00:00] timestamp: ~N[2021-01-01 05:00:00]
), ),
build(:pageview, build(:pageview,
pathname: "/goobye", pathname: "/goobye",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
) )
]) ])
@ -732,13 +714,12 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "can filter by event:name", %{conn: conn, site: site} do test "can filter by event:name", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Signup", name: "Signup",
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]) build(:pageview, timestamp: ~N[2021-01-01 00:00:00])
]) ])
conn = conn =
@ -754,33 +735,29 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
end end
test "filter by custom event property", %{conn: conn, site: site} do test "filter by custom event property", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["business"], "meta.value": ["business"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["business"], "meta.value": ["business"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["personal"], "meta.value": ["personal"],
domain: site.domain,
timestamp: ~N[2021-01-01 00:25:00] timestamp: ~N[2021-01-01 00:25:00]
), ),
build(:event, build(:event,
name: "Purchase", name: "Purchase",
"meta.key": ["package"], "meta.key": ["package"],
"meta.value": ["business"], "meta.value": ["business"],
domain: site.domain,
timestamp: ~N[2021-01-02 00:25:00] timestamp: ~N[2021-01-02 00:25:00]
) )
]) ])
@ -801,19 +778,17 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
describe "metrics" do describe "metrics" do
test "shows pageviews,visits,views_per_visit for last 7d", %{conn: conn, site: site} do test "shows pageviews,visits,views_per_visit for last 7d", %{conn: conn, site: site} do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:05:00] timestamp: ~N[2021-01-01 00:05:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-01 00:00:00]), build(:pageview, timestamp: ~N[2021-01-01 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-07 23:59:00]) build(:pageview, timestamp: ~N[2021-01-07 23:59:00])
]) ])
conn = conn =
@ -876,30 +851,26 @@ defmodule PlausibleWeb.Api.ExternalStatsController.TimeseriesTest do
conn: conn, conn: conn,
site: site site: site
} do } do
populate_stats([ populate_stats(site, [
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:00:00] timestamp: ~N[2021-01-01 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-01 00:05:00] timestamp: ~N[2021-01-01 00:05:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-03 00:00:00] timestamp: ~N[2021-01-03 00:00:00]
), ),
build(:pageview, build(:pageview,
user_id: @user_id, user_id: @user_id,
domain: site.domain,
timestamp: ~N[2021-01-03 00:01:00] timestamp: ~N[2021-01-03 00:01:00]
), ),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-03 00:00:00]), build(:pageview, timestamp: ~N[2021-01-03 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-03 00:00:00]), build(:pageview, timestamp: ~N[2021-01-03 00:00:00]),
build(:pageview, domain: site.domain, timestamp: ~N[2021-01-07 23:59:00]) build(:pageview, timestamp: ~N[2021-01-07 23:59:00])
]) ])
conn = conn =

View File

@ -14,7 +14,7 @@ defmodule PlausibleWeb.Api.InternalControllerTest do
test "is READY when site has at least 1 pageview", %{conn: conn, user: user} do test "is READY when site has at least 1 pageview", %{conn: conn, user: user} do
site = insert(:site, members: [user]) site = insert(:site, members: [user])
Plausible.TestUtils.create_pageviews([%{domain: site.domain}]) Plausible.TestUtils.create_pageviews([%{site: site}])
conn = get(conn, "/api/#{site.domain}/status") conn = get(conn, "/api/#{site.domain}/status")

View File

@ -653,6 +653,41 @@ defmodule PlausibleWeb.Api.StatsController.ConversionsTest do
insert(:goal, %{domain: site.domain, page_path: "/*"}) insert(:goal, %{domain: site.domain, page_path: "/*"})
insert(:goal, %{domain: site.domain, page_path: "/**"}) insert(:goal, %{domain: site.domain, page_path: "/**"})
populate_stats(site, [
build(:pageview,
pathname: "/hum",
timestamp: ~N[2019-07-01 23:00:00]
),
build(:pageview,
pathname: "/register",
timestamp: ~N[2019-07-01 23:00:00]
),
build(:pageview,
pathname: "/reg",
timestamp: ~N[2019-07-01 23:00:00]
),
build(:pageview,
pathname: "/billing/success",
timestamp: ~N[2019-07-01 23:00:00]
),
build(:pageview,
pathname: "/billing/upgrade/success",
timestamp: ~N[2019-07-01 23:00:00]
),
build(:pageview,
pathname: "/signup/new",
timestamp: ~N[2019-07-01 23:00:00]
),
build(:pageview,
pathname: "/signup/new/2",
timestamp: ~N[2019-07-01 23:00:00]
),
build(:pageview,
pathname: "/signup/new/3",
timestamp: ~N[2019-07-01 23:00:00]
)
])
conn = conn =
get( get(
conn, conn,

View File

@ -5,6 +5,11 @@ defmodule PlausibleWeb.Api.StatsController.CurrentVisitorsTest do
setup [:create_user, :log_in, :create_site] setup [:create_user, :log_in, :create_site]
test "returns unique users in the last 5 minutes", %{conn: conn, site: site} do test "returns unique users in the last 5 minutes", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview, user_id: 123),
build(:pageview, user_id: 456)
])
conn = get(conn, "/api/stats/#{site.domain}/current-visitors") conn = get(conn, "/api/stats/#{site.domain}/current-visitors")
assert json_response(conn, 200) == 2 assert json_response(conn, 200) == 2

View File

@ -5,23 +5,37 @@ defmodule PlausibleWeb.Api.StatsController.SuggestionsTest do
setup [:create_user, :log_in, :create_site] setup [:create_user, :log_in, :create_site]
test "returns suggestions for pages without a query", %{conn: conn, site: site} do test "returns suggestions for pages without a query", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview, timestamp: ~N[2019-01-01 23:00:00], pathname: "/"),
build(:pageview, timestamp: ~N[2019-01-01 23:00:00], pathname: "/register"),
build(:pageview, timestamp: ~N[2019-01-01 23:00:01], pathname: "/contact"),
build(:pageview, timestamp: ~N[2019-01-01 23:00:01], pathname: "/irrelevant")
])
conn = get(conn, "/api/stats/#{site.domain}/suggestions/page?period=month&date=2019-01-01") conn = get(conn, "/api/stats/#{site.domain}/suggestions/page?period=month&date=2019-01-01")
assert json_response(conn, 200) == [ assert json_response(conn, 200) == [
%{"label" => "/", "value" => "/"}, %{"label" => "/", "value" => "/"},
%{"label" => "/register", "value" => "/register"},
%{"label" => "/contact", "value" => "/contact"}, %{"label" => "/contact", "value" => "/contact"},
%{"label" => "/irrelevant", "value" => "/irrelevant"} %{"label" => "/irrelevant", "value" => "/irrelevant"},
%{"label" => "/register", "value" => "/register"}
] ]
end end
test "returns suggestions for pages with a query", %{conn: conn, site: site} do test "returns suggestions for pages with a query", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview, timestamp: ~N[2019-01-01 23:00:00], pathname: "/"),
build(:pageview, timestamp: ~N[2019-01-01 23:00:00], pathname: "/register"),
build(:pageview, timestamp: ~N[2019-01-01 23:00:01], pathname: "/contact"),
build(:pageview, timestamp: ~N[2019-01-01 23:00:01], pathname: "/irrelevant")
])
conn = conn =
get(conn, "/api/stats/#{site.domain}/suggestions/page?period=month&date=2019-01-01&q=re") get(conn, "/api/stats/#{site.domain}/suggestions/page?period=month&date=2019-01-01&q=re")
assert json_response(conn, 200) == [ assert json_response(conn, 200) == [
%{"label" => "/register", "value" => "/register"}, %{"label" => "/irrelevant", "value" => "/irrelevant"},
%{"label" => "/irrelevant", "value" => "/irrelevant"} %{"label" => "/register", "value" => "/register"}
] ]
end end
@ -42,16 +56,25 @@ defmodule PlausibleWeb.Api.StatsController.SuggestionsTest do
end end
test "returns suggestions for sources", %{conn: conn, site: site} do test "returns suggestions for sources", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview, timestamp: ~N[2019-01-01 23:00:00], referrer_source: "Bing"),
build(:pageview, timestamp: ~N[2019-01-01 23:00:00], referrer_source: "10words")
])
conn = conn =
get(conn, "/api/stats/#{site.domain}/suggestions/source?period=month&date=2019-01-01") get(conn, "/api/stats/#{site.domain}/suggestions/source?period=month&date=2019-01-01")
assert json_response(conn, 200) == [ assert json_response(conn, 200) == [
%{"label" => "10words", "value" => "10words"}, %{"label" => "Bing", "value" => "Bing"},
%{"label" => "Bing", "value" => "Bing"} %{"label" => "10words", "value" => "10words"}
] ]
end end
test "returns suggestions for countries", %{conn: conn, site: site} do test "returns suggestions for countries", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview, timestamp: ~N[2019-01-01 23:00:01], pathname: "/", country_code: "US")
])
conn = conn =
get( get(
conn, conn,
@ -106,6 +129,10 @@ defmodule PlausibleWeb.Api.StatsController.SuggestionsTest do
end end
test "returns suggestions for screen sizes", %{conn: conn, site: site} do test "returns suggestions for screen sizes", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview, timestamp: ~N[2019-01-01 23:00:00], pathname: "/", screen_size: "Desktop")
])
conn = conn =
get(conn, "/api/stats/#{site.domain}/suggestions/screen?period=month&date=2019-01-01") get(conn, "/api/stats/#{site.domain}/suggestions/screen?period=month&date=2019-01-01")
@ -113,6 +140,10 @@ defmodule PlausibleWeb.Api.StatsController.SuggestionsTest do
end end
test "returns suggestions for browsers", %{conn: conn, site: site} do test "returns suggestions for browsers", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview, timestamp: ~N[2019-01-01 23:00:00], pathname: "/", browser: "Chrome")
])
conn = conn =
get(conn, "/api/stats/#{site.domain}/suggestions/browser?period=month&date=2019-01-01") get(conn, "/api/stats/#{site.domain}/suggestions/browser?period=month&date=2019-01-01")
@ -122,6 +153,14 @@ defmodule PlausibleWeb.Api.StatsController.SuggestionsTest do
test "returns suggestions for browser versions", %{conn: conn, site: site} do test "returns suggestions for browser versions", %{conn: conn, site: site} do
filters = Jason.encode!(%{browser: "Chrome"}) filters = Jason.encode!(%{browser: "Chrome"})
populate_stats(site, [
build(:pageview,
timestamp: ~N[2019-01-01 00:00:00],
browser: "Chrome",
browser_version: "78.0"
)
])
conn = conn =
get( get(
conn, conn,
@ -132,6 +171,10 @@ defmodule PlausibleWeb.Api.StatsController.SuggestionsTest do
end end
test "returns suggestions for OS", %{conn: conn, site: site} do test "returns suggestions for OS", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview, timestamp: ~N[2019-01-01 00:00:00], operating_system: "Mac")
])
conn = get(conn, "/api/stats/#{site.domain}/suggestions/os?period=month&date=2019-01-01") conn = get(conn, "/api/stats/#{site.domain}/suggestions/os?period=month&date=2019-01-01")
assert json_response(conn, 200) == [%{"value" => "Mac", "label" => "Mac"}] assert json_response(conn, 200) == [%{"value" => "Mac", "label" => "Mac"}]
@ -140,6 +183,14 @@ defmodule PlausibleWeb.Api.StatsController.SuggestionsTest do
test "returns suggestions for OS versions", %{conn: conn, site: site} do test "returns suggestions for OS versions", %{conn: conn, site: site} do
filters = Jason.encode!(%{os: "Mac"}) filters = Jason.encode!(%{os: "Mac"})
populate_stats(site, [
build(:pageview,
timestamp: ~N[2019-01-01 00:00:00],
operating_system: "Mac",
operating_system_version: "10.15"
)
])
conn = conn =
get( get(
conn, conn,
@ -162,6 +213,14 @@ defmodule PlausibleWeb.Api.StatsController.SuggestionsTest do
end end
test "returns suggestions for referrers", %{conn: conn, site: site} do test "returns suggestions for referrers", %{conn: conn, site: site} do
populate_stats(site, [
build(:pageview,
timestamp: ~N[2019-01-01 23:00:00],
pathname: "/",
referrer: "10words.com/page1"
)
])
conn = conn =
get(conn, "/api/stats/#{site.domain}/suggestions/referrer?period=month&date=2019-01-01") get(conn, "/api/stats/#{site.domain}/suggestions/referrer?period=month&date=2019-01-01")

View File

@ -41,10 +41,12 @@ defmodule PlausibleWeb.SiteControllerTest do
end end
test "lists all of your sites with last 24h visitors", %{conn: conn, user: user} do test "lists all of your sites with last 24h visitors", %{conn: conn, user: user} do
insert(:site, members: [user], domain: "test-site.com") site = insert(:site, members: [user])
populate_stats(site, [build(:pageview), build(:pageview), build(:pageview)])
conn = get(conn, "/sites") conn = get(conn, "/sites")
assert html_response(conn, 200) =~ "test-site.com" assert html_response(conn, 200) =~ site.domain
assert html_response(conn, 200) =~ "<b>3</b> visitors in last 24h" assert html_response(conn, 200) =~ "<b>3</b> visitors in last 24h"
end end

View File

@ -4,9 +4,10 @@ defmodule PlausibleWeb.StatsControllerTest do
describe "GET /:website - anonymous user" do describe "GET /:website - anonymous user" do
test "public site - shows site stats", %{conn: conn} do test "public site - shows site stats", %{conn: conn} do
insert(:site, domain: "public-site.io", public: true) site = insert(:site, public: true)
populate_stats(site, [build(:pageview)])
conn = get(conn, "/public-site.io") conn = get(conn, "/#{site.domain}")
assert html_response(conn, 200) =~ "stats-react-container" assert html_response(conn, 200) =~ "stats-react-container"
end end
@ -27,6 +28,7 @@ defmodule PlausibleWeb.StatsControllerTest do
setup [:create_user, :log_in, :create_site] setup [:create_user, :log_in, :create_site]
test "can view stats of a website I've created", %{conn: conn, site: site} do test "can view stats of a website I've created", %{conn: conn, site: site} do
populate_stats(site, [build(:pageview)])
conn = get(conn, "/" <> site.domain) conn = get(conn, "/" <> site.domain)
assert html_response(conn, 200) =~ "stats-react-container" assert html_response(conn, 200) =~ "stats-react-container"
end end

View File

@ -1,337 +0,0 @@
defmodule Plausible.Test.ClickhouseSetup do
@conversion_1_session_id 123
@conversion_2_session_id 234
def run() do
Plausible.TestUtils.create_events([
%{
name: "pageview",
domain: "test-site.com",
pathname: "/",
country_code: "EE",
browser: "Chrome",
browser_version: "78.0",
operating_system: "Mac",
operating_system_version: "10.15",
screen_size: "Desktop",
referrer_source: "10words",
referrer: "10words.com/page1",
timestamp: ~N[2019-01-01 00:00:00],
session_id: @conversion_1_session_id
},
%{
name: "pageview",
domain: "test-site.com",
pathname: "/",
country_code: "EE",
browser: "Chrome",
browser_version: "78.0",
operating_system: "Mac",
operating_system_version: "10.15",
screen_size: "Desktop",
referrer_source: "10words",
referrer: "10words.com/page2",
timestamp: ~N[2019-01-01 00:00:00]
},
%{
name: "pageview",
domain: "test-site.com",
pathname: "/",
country_code: "US",
browser: "Chrome",
browser_version: "79.0",
operating_system: "Mac",
operating_system_version: "10.16",
screen_size: "Laptop",
referrer_source: "",
referrer: "",
timestamp: ~N[2019-01-01 00:00:00]
},
%{
name: "pageview",
domain: "test-site.com",
pathname: "/contact",
country_code: "GB",
browser: "Firefox",
operating_system: "Android",
screen_size: "Mobile",
referrer_source: "Bing",
timestamp: ~N[2019-01-01 00:00:00]
},
%{name: "pageview", domain: "test-site.com", timestamp: ~N[2019-01-31 00:00:00]},
%{
name: "Signup",
domain: "test-site.com",
session_id: @conversion_1_session_id,
timestamp: ~N[2019-01-01 01:00:00],
"meta.key": ["variant"],
"meta.value": ["A"]
},
%{
name: "Signup",
domain: "test-site.com",
session_id: @conversion_1_session_id,
timestamp: ~N[2019-01-01 02:00:00],
"meta.key": ["variant"],
"meta.value": ["B"]
},
%{
name: "Signup",
domain: "test-site.com",
session_id: @conversion_2_session_id,
timestamp: ~N[2019-01-01 02:00:00],
"meta.key": ["variant"],
"meta.value": ["B"]
},
%{
name: "pageview",
pathname: "/register",
domain: "test-site.com",
session_id: @conversion_1_session_id,
timestamp: ~N[2019-01-01 23:00:00]
},
%{
name: "pageview",
pathname: "/register",
domain: "test-site.com",
session_id: @conversion_2_session_id,
timestamp: ~N[2019-01-01 23:00:00]
},
%{
name: "pageview",
pathname: "/irrelevant",
domain: "test-site.com",
session_id: @conversion_1_session_id,
timestamp: ~N[2019-01-01 23:00:01]
},
%{
name: "pageview",
domain: "test-site.com",
referrer_source: "Google",
timestamp: ~N[2019-02-01 01:00:00]
},
%{
name: "pageview",
domain: "test-site.com",
referrer_source: "Google",
timestamp: ~N[2019-02-01 02:00:00]
},
%{
name: "pageview",
domain: "test-site.com",
referrer: "t.co/some-link",
referrer_source: "Twitter",
timestamp: ~N[2019-03-01 01:00:00]
},
%{
name: "pageview",
domain: "test-site.com",
referrer: "t.co/some-link",
referrer_source: "Twitter",
timestamp: ~N[2019-03-01 01:00:00]
},
%{
name: "pageview",
domain: "test-site.com",
referrer: "t.co/nonexistent-link",
referrer_source: "Twitter",
timestamp: ~N[2019-03-01 02:00:00]
},
%{name: "pageview", domain: "test-site.com"},
%{
name: "pageview",
domain: "test-site.com",
timestamp: Timex.now() |> Timex.shift(minutes: -3)
},
%{
name: "pageview",
domain: "test-site.com",
timestamp: Timex.now() |> Timex.shift(minutes: -6)
},
%{name: "pageview", domain: "tz-test.com", timestamp: ~N[2019-01-01 00:00:00]},
%{name: "pageview", domain: "public-site.io"},
%{
name: "pageview",
domain: "fetch-tweets-test.com",
referrer: "t.co/a-link",
referrer_source: "Twitter"
},
%{
name: "pageview",
domain: "fetch-tweets-test.com",
referrer: "t.co/b-link",
referrer_source: "Twitter",
timestamp: Timex.now() |> Timex.shift(days: -5)
},
%{
name: "pageview",
pathname: "/register",
domain: "test-site.com",
timestamp: ~N[2019-07-01 23:00:00]
},
%{
name: "pageview",
pathname: "/signup/new",
domain: "test-site.com",
timestamp: ~N[2019-07-01 23:00:00]
},
%{
name: "pageview",
pathname: "/billing/success",
domain: "test-site.com",
timestamp: ~N[2019-07-01 23:00:00]
},
%{
name: "pageview",
pathname: "/",
domain: "test-site.com",
timestamp: ~N[2019-07-01 23:00:00]
},
%{
name: "pageview",
pathname: "/reg",
domain: "test-site.com",
timestamp: ~N[2019-07-01 23:00:00]
},
%{
name: "pageview",
pathname: "/signup/new/2",
domain: "test-site.com",
timestamp: ~N[2019-07-01 23:00:00]
},
%{
name: "pageview",
pathname: "/signup/new/3",
domain: "test-site.com",
timestamp: ~N[2019-07-01 23:00:00]
},
%{
name: "pageview",
pathname: "/billing/upgrade/success",
domain: "test-site.com",
timestamp: ~N[2019-07-01 23:00:00]
}
])
Plausible.TestUtils.create_sessions([
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/",
referrer_source: "10words",
referrer: "10words.com/page1",
utm_medium: "listing",
country_code: "US",
screen_size: "Desktop",
browser: "Chrome",
browser_version: "78.0",
operating_system: "Mac",
operating_system_version: "10.15",
session_id: @conversion_1_session_id,
is_bounce: true,
duration: 100,
start: ~N[2019-01-01 02:00:00],
timestamp: ~N[2019-01-01 02:00:00]
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/",
referrer_source: "10words",
referrer: "10words.com/page1",
utm_medium: "listing",
session_id: @conversion_2_session_id,
is_bounce: false,
duration: 0,
start: ~N[2019-01-01 02:00:00],
timestamp: ~N[2019-01-01 02:00:00]
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/",
referrer_source: "Bing",
referrer: "",
utm_medium: "search",
is_bounce: false,
duration: 100,
start: ~N[2019-01-01 03:00:00],
timestamp: ~N[2019-01-01 03:00:00]
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/",
referrer_source: "Google",
referrer: "",
is_bounce: false,
start: ~N[2019-02-01 01:00:00],
timestamp: ~N[2019-02-01 01:00:00]
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/",
referrer_source: "Google",
referrer: "",
is_bounce: false,
start: ~N[2019-02-01 02:00:00],
timestamp: ~N[2019-02-01 02:00:00]
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/",
referrer: "t.co/some-link",
referrer_source: "Twitter",
start: ~N[2019-03-01 01:00:00],
timestamp: ~N[2019-03-01 01:00:00]
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/",
referrer: "t.co/some-link",
referrer_source: "Twitter",
start: ~N[2019-03-01 01:00:00],
timestamp: ~N[2019-03-01 01:00:00]
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/",
referrer: "t.co/nonexistent-link",
referrer_source: "Twitter",
start: ~N[2019-03-01 02:00:00],
timestamp: ~N[2019-03-01 02:00:00]
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/",
referrer_source: "Bing",
referrer: "bing.com",
start: Timex.now() |> Timex.shift(minutes: -1),
timestamp: Timex.now() |> Timex.shift(minutes: -1)
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/exit",
referrer_source: "10words",
referrer: "10words.com",
start: Timex.now() |> Timex.shift(minutes: -2),
timestamp: Timex.now() |> Timex.shift(minutes: -2)
},
%{
domain: "test-site.com",
entry_page: "/",
exit_page: "/exit",
referrer_source: "10words",
referrer: "10words.com",
start: Timex.now() |> Timex.shift(minutes: -3),
timestamp: Timex.now() |> Timex.shift(minutes: -3)
}
])
end
end

View File

@ -38,6 +38,21 @@ defmodule Plausible.Factory do
def ch_session_factory do def ch_session_factory do
hostname = sequence(:domain, &"example-#{&1}.com") hostname = sequence(:domain, &"example-#{&1}.com")
if Plausible.v2?() do
%Plausible.ClickhouseSessionV2{
sign: 1,
session_id: SipHash.hash!(hash_key(), Ecto.UUID.generate()),
user_id: SipHash.hash!(hash_key(), Ecto.UUID.generate()),
hostname: hostname,
site_id: Enum.random(1000..10_000),
entry_page: "/",
pageviews: 1,
events: 1,
start: Timex.now(),
timestamp: Timex.now(),
is_bounce: false
}
else
%Plausible.ClickhouseSession{ %Plausible.ClickhouseSession{
sign: 1, sign: 1,
session_id: SipHash.hash!(hash_key(), Ecto.UUID.generate()), session_id: SipHash.hash!(hash_key(), Ecto.UUID.generate()),
@ -52,6 +67,7 @@ defmodule Plausible.Factory do
is_bounce: false is_bounce: false
} }
end end
end
def pageview_factory do def pageview_factory do
struct!( struct!(
@ -65,6 +81,16 @@ defmodule Plausible.Factory do
def event_factory do def event_factory do
hostname = sequence(:domain, &"example-#{&1}.com") hostname = sequence(:domain, &"example-#{&1}.com")
if Plausible.v2?() do
%Plausible.ClickhouseEventV2{
hostname: hostname,
site_id: Enum.random(1000..10_000),
pathname: "/",
timestamp: NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second),
user_id: SipHash.hash!(hash_key(), Ecto.UUID.generate()),
session_id: SipHash.hash!(hash_key(), Ecto.UUID.generate())
}
else
%Plausible.ClickhouseEvent{ %Plausible.ClickhouseEvent{
hostname: hostname, hostname: hostname,
domain: hostname, domain: hostname,
@ -74,6 +100,7 @@ defmodule Plausible.Factory do
session_id: SipHash.hash!(hash_key(), Ecto.UUID.generate()) session_id: SipHash.hash!(hash_key(), Ecto.UUID.generate())
} }
end end
end
def goal_factory do def goal_factory do
%Plausible.Goal{} %Plausible.Goal{}

View File

@ -37,7 +37,6 @@ defmodule Plausible.TestUtils do
def create_site(%{user: user}) do def create_site(%{user: user}) do
site = site =
Factory.insert(:site, Factory.insert(:site,
domain: "test-site.com",
members: [user] members: [user]
) )
@ -73,30 +72,63 @@ defmodule Plausible.TestUtils do
def create_pageviews(pageviews) do def create_pageviews(pageviews) do
pageviews = pageviews =
Enum.map(pageviews, fn pageview -> Enum.map(pageviews, fn pageview ->
pageview =
if Plausible.v2?() do
pageview
|> Map.delete(:site)
|> Map.put(:site_id, pageview.site.id)
else
pageview
|> Map.delete(:site)
|> Map.put(:domain, pageview.site.domain)
end
Factory.build(:pageview, pageview) Factory.build(:pageview, pageview)
|> Map.from_struct() |> Map.from_struct()
|> Map.delete(:__meta__) |> Map.delete(:__meta__)
|> update_in([:timestamp], &to_naive_truncate/1) |> update_in([:timestamp], &to_naive_truncate/1)
end) end)
if Plausible.v2?() do
Plausible.IngestRepo.insert_all(Plausible.ClickhouseEventV2, pageviews)
else
Plausible.IngestRepo.insert_all(Plausible.ClickhouseEvent, pageviews) Plausible.IngestRepo.insert_all(Plausible.ClickhouseEvent, pageviews)
end end
end
def create_events(events) do def create_events(events) do
events = events =
Enum.map(events, fn event -> Enum.map(events, fn event ->
event =
if Plausible.v2?() do
Map.delete(event, :domain)
else
Map.delete(event, :site_id)
end
Factory.build(:event, event) Factory.build(:event, event)
|> Map.from_struct() |> Map.from_struct()
|> Map.delete(:__meta__) |> Map.delete(:__meta__)
|> update_in([:timestamp], &to_naive_truncate/1) |> update_in([:timestamp], &to_naive_truncate/1)
end) end)
if Plausible.v2?() do
Plausible.IngestRepo.insert_all(Plausible.ClickhouseEventV2, events)
else
Plausible.IngestRepo.insert_all(Plausible.ClickhouseEvent, events) Plausible.IngestRepo.insert_all(Plausible.ClickhouseEvent, events)
end end
end
def create_sessions(sessions) do def create_sessions(sessions) do
sessions = sessions =
Enum.map(sessions, fn session -> Enum.map(sessions, fn session ->
session =
if Plausible.v2?() do
Map.delete(session, :domain)
else
Map.delete(session, :site_id)
end
Factory.build(:ch_session, session) Factory.build(:ch_session, session)
|> Map.from_struct() |> Map.from_struct()
|> Map.delete(:__meta__) |> Map.delete(:__meta__)
@ -104,8 +136,12 @@ defmodule Plausible.TestUtils do
|> update_in([:start], &to_naive_truncate/1) |> update_in([:start], &to_naive_truncate/1)
end) end)
if Plausible.v2?() do
Plausible.IngestRepo.insert_all(Plausible.ClickhouseSessionV2, sessions)
else
Plausible.IngestRepo.insert_all(Plausible.ClickhouseSession, sessions) Plausible.IngestRepo.insert_all(Plausible.ClickhouseSession, sessions)
end end
end
def log_in(%{user: user, conn: conn}) do def log_in(%{user: user, conn: conn}) do
conn = conn =
@ -134,6 +170,9 @@ defmodule Plausible.TestUtils do
def populate_stats(site, events) do def populate_stats(site, events) do
Enum.map(events, fn event -> Enum.map(events, fn event ->
case event do case event do
%Plausible.ClickhouseEventV2{} ->
Map.put(event, :site_id, site.id)
%Plausible.ClickhouseEvent{} -> %Plausible.ClickhouseEvent{} ->
Map.put(event, :domain, site.domain) Map.put(event, :domain, site.domain)
@ -158,6 +197,9 @@ defmodule Plausible.TestUtils do
end) end)
|> Enum.split_with(fn event -> |> Enum.split_with(fn event ->
case event do case event do
%Plausible.ClickhouseEventV2{} ->
true
%Plausible.ClickhouseEvent{} -> %Plausible.ClickhouseEvent{} ->
true true
@ -174,11 +216,22 @@ defmodule Plausible.TestUtils do
sessions = sessions =
Enum.reduce(events, %{}, fn event, sessions -> Enum.reduce(events, %{}, fn event, sessions ->
session_id = Plausible.Session.CacheStore.on_event(event, nil) session_id = Plausible.Session.CacheStore.on_event(event, nil)
if Plausible.v2?() do
Map.put(sessions, {event.site_id, event.user_id}, session_id)
else
Map.put(sessions, {event.domain, event.user_id}, session_id) Map.put(sessions, {event.domain, event.user_id}, session_id)
end
end) end)
Enum.each(events, fn event -> Enum.each(events, fn event ->
event = Map.put(event, :session_id, sessions[{event.domain, event.user_id}]) event =
if Plausible.v2?() do
Map.put(event, :session_id, sessions[{event.site_id, event.user_id}])
else
Map.put(event, :session_id, sessions[{event.domain, event.user_id}])
end
Plausible.Event.WriteBuffer.insert(event) Plausible.Event.WriteBuffer.insert(event)
end) end)

View File

@ -1,7 +1,14 @@
{:ok, _} = Application.ensure_all_started(:ex_machina) {:ok, _} = Application.ensure_all_started(:ex_machina)
Plausible.Test.ClickhouseSetup.run()
Mox.defmock(Plausible.HTTPClient.Mock, for: Plausible.HTTPClient.Interface) Mox.defmock(Plausible.HTTPClient.Mock, for: Plausible.HTTPClient.Interface)
FunWithFlags.enable(:visits_metric) FunWithFlags.enable(:visits_metric)
ExUnit.start(exclude: :slow) ExUnit.start(exclude: :slow)
Application.ensure_all_started(:double) Application.ensure_all_started(:double)
Ecto.Adapters.SQL.Sandbox.mode(Plausible.Repo, :manual) Ecto.Adapters.SQL.Sandbox.mode(Plausible.Repo, :manual)
if Plausible.v2?() do
IO.puts("Running tests against v2 schema")
else
IO.puts(
"Running tests against v1 schema. Use: `V2_MIGRATION_DONE=1 mix test` for secondary run."
)
end

View File

@ -25,6 +25,8 @@ defmodule Plausible.Workers.SendCheckStatsEmailsTest do
test "does not send an email if the user has configured a weekly report" do test "does not send an email if the user has configured a weekly report" do
user = insert(:user, inserted_at: days_ago(9), last_seen: days_ago(7)) user = insert(:user, inserted_at: days_ago(9), last_seen: days_ago(7))
site = insert(:site, domain: "test-site.com", members: [user]) site = insert(:site, domain: "test-site.com", members: [user])
populate_stats(site, [build(:pageview)])
insert(:weekly_report, site: site, recipients: ["user@email.com"]) insert(:weekly_report, site: site, recipients: ["user@email.com"])
perform_job(SendCheckStatsEmails, %{}) perform_job(SendCheckStatsEmails, %{})
@ -34,7 +36,8 @@ defmodule Plausible.Workers.SendCheckStatsEmailsTest do
test "sends an email after a week of signup if the user hasn't logged in" do test "sends an email after a week of signup if the user hasn't logged in" do
user = insert(:user, inserted_at: days_ago(8), last_seen: days_ago(8)) user = insert(:user, inserted_at: days_ago(8), last_seen: days_ago(8))
insert(:site, domain: "test-site.com", members: [user]) site = insert(:site, domain: "test-site.com", members: [user])
populate_stats(site, [build(:pageview)])
perform_job(SendCheckStatsEmails, %{}) perform_job(SendCheckStatsEmails, %{})

View File

@ -39,17 +39,17 @@ defmodule Plausible.Workers.SendEmailReportTest do
create_pageviews([ create_pageviews([
# Sunday before last, not counted # Sunday before last, not counted
%{domain: site.domain, timestamp: Timezone.convert(sunday_before_last, "UTC")}, %{site: site, timestamp: Timezone.convert(sunday_before_last, "UTC")},
# Sunday before last, not counted # Sunday before last, not counted
%{domain: site.domain, timestamp: Timezone.convert(sunday_before_last, "UTC")}, %{site: site, timestamp: Timezone.convert(sunday_before_last, "UTC")},
# Last monday, counted # Last monday, counted
%{domain: site.domain, timestamp: Timezone.convert(last_monday, "UTC")}, %{site: site, timestamp: Timezone.convert(last_monday, "UTC")},
# Last sunday, counted # Last sunday, counted
%{domain: site.domain, timestamp: Timezone.convert(last_sunday, "UTC")}, %{site: site, timestamp: Timezone.convert(last_sunday, "UTC")},
# This monday, not counted # This monday, not counted
%{domain: site.domain, timestamp: Timezone.convert(this_monday, "UTC")}, %{site: site, timestamp: Timezone.convert(this_monday, "UTC")},
# This monday, not counted # This monday, not counted
%{domain: site.domain, timestamp: Timezone.convert(this_monday, "UTC")} %{site: site, timestamp: Timezone.convert(this_monday, "UTC")}
]) ])
perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"}) perform_job(SendEmailReport, %{"site_id" => site.id, "interval" => "weekly"})

View File

@ -41,7 +41,9 @@ defmodule Plausible.Workers.SendSiteSetupEmailsTest do
test "sends the setup completed email as soon as possible" do test "sends the setup completed email as soon as possible" do
user = insert(:user) user = insert(:user)
insert(:site, members: [user], domain: "test-site.com") site = insert(:site, members: [user])
populate_stats(site, [build(:pageview)])
perform_job(SendSiteSetupEmails, %{}) perform_job(SendSiteSetupEmails, %{})
@ -62,7 +64,7 @@ defmodule Plausible.Workers.SendSiteSetupEmailsTest do
subject: "Your Plausible setup: Waiting for the first page views" subject: "Your Plausible setup: Waiting for the first page views"
) )
create_pageviews([%{domain: site.domain}]) create_pageviews([%{site: site}])
perform_job(SendSiteSetupEmails, %{}) perform_job(SendSiteSetupEmails, %{})
assert_email_delivered_with( assert_email_delivered_with(

View File

@ -44,7 +44,7 @@ defmodule Plausible.Workers.SendTrialNotificationsTest do
] ]
) )
populate_stats(site, [build(:pageview, domain: site.domain)]) populate_stats(site, [build(:pageview)])
perform_job(SendTrialNotifications, %{}) perform_job(SendTrialNotifications, %{})
@ -55,7 +55,7 @@ defmodule Plausible.Workers.SendTrialNotificationsTest do
test "sends a reminder 7 days before trial ends (16 days after user signed up)" do test "sends a reminder 7 days before trial ends (16 days after user signed up)" do
user = insert(:user, trial_expiry_date: Timex.now() |> Timex.shift(days: 7)) user = insert(:user, trial_expiry_date: Timex.now() |> Timex.shift(days: 7))
site = insert(:site, members: [user]) site = insert(:site, members: [user])
populate_stats(site, [build(:pageview, domain: site.domain)]) populate_stats(site, [build(:pageview)])
perform_job(SendTrialNotifications, %{}) perform_job(SendTrialNotifications, %{})
@ -67,9 +67,9 @@ defmodule Plausible.Workers.SendTrialNotificationsTest do
site = insert(:site, members: [user]) site = insert(:site, members: [user])
populate_stats(site, [ populate_stats(site, [
build(:pageview, domain: site.domain), build(:pageview),
build(:pageview, domain: site.domain), build(:pageview),
build(:pageview, domain: site.domain) build(:pageview)
]) ])
perform_job(SendTrialNotifications, %{}) perform_job(SendTrialNotifications, %{})
@ -82,9 +82,9 @@ defmodule Plausible.Workers.SendTrialNotificationsTest do
site = insert(:site, members: [user]) site = insert(:site, members: [user])
populate_stats(site, [ populate_stats(site, [
build(:pageview, domain: site.domain), build(:pageview),
build(:pageview, domain: site.domain), build(:pageview),
build(:pageview, domain: site.domain) build(:pageview)
]) ])
perform_job(SendTrialNotifications, %{}) perform_job(SendTrialNotifications, %{})
@ -115,9 +115,9 @@ defmodule Plausible.Workers.SendTrialNotificationsTest do
site = insert(:site, members: [user]) site = insert(:site, members: [user])
populate_stats(site, [ populate_stats(site, [
build(:pageview, domain: site.domain), build(:pageview),
build(:pageview, domain: site.domain), build(:pageview),
build(:pageview, domain: site.domain) build(:pageview)
]) ])
perform_job(SendTrialNotifications, %{}) perform_job(SendTrialNotifications, %{})
@ -130,9 +130,9 @@ defmodule Plausible.Workers.SendTrialNotificationsTest do
site = insert(:site, members: [user]) site = insert(:site, members: [user])
populate_stats(site, [ populate_stats(site, [
build(:pageview, domain: site.domain), build(:pageview),
build(:pageview, domain: site.domain), build(:pageview),
build(:pageview, domain: site.domain) build(:pageview)
]) ])
insert(:subscription, user: user) insert(:subscription, user: user)