analytics/test/support/factory.ex
hq1 d2f2c69387
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
2023-03-27 13:52:42 +02:00

298 lines
6.6 KiB
Elixir

defmodule Plausible.Factory do
use ExMachina.Ecto, repo: Plausible.Repo
def user_factory(attrs) do
pw = Map.get(attrs, :password, "password")
user = %Plausible.Auth.User{
name: "Jane Smith",
email: sequence(:email, &"email-#{&1}@example.com"),
password_hash: Plausible.Auth.Password.hash(pw),
trial_expiry_date: Timex.today() |> Timex.shift(days: 30),
email_verified: true
}
merge_attributes(user, attrs)
end
def spike_notification_factory do
%Plausible.Site.SpikeNotification{
threshold: 10
}
end
def site_factory do
domain = sequence(:domain, &"example-#{&1}.com")
%Plausible.Site{
native_stats_start_at: ~N[2000-01-01 00:00:00],
domain: domain,
timezone: "UTC"
}
end
def site_membership_factory do
%Plausible.Site.Membership{}
end
def ch_session_factory do
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{
sign: 1,
session_id: SipHash.hash!(hash_key(), Ecto.UUID.generate()),
user_id: SipHash.hash!(hash_key(), Ecto.UUID.generate()),
hostname: hostname,
domain: hostname,
entry_page: "/",
pageviews: 1,
events: 1,
start: Timex.now(),
timestamp: Timex.now(),
is_bounce: false
}
end
end
def pageview_factory do
struct!(
event_factory(),
%{
name: "pageview"
}
)
end
def event_factory do
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{
hostname: hostname,
domain: hostname,
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())
}
end
end
def goal_factory do
%Plausible.Goal{}
end
def subscription_factory do
%Plausible.Billing.Subscription{
paddle_subscription_id: sequence(:paddle_subscription_id, &"subscription-#{&1}"),
paddle_plan_id: sequence(:paddle_plan_id, &"plan-#{&1}"),
cancel_url: "cancel.com",
update_url: "cancel.com",
status: "active",
next_bill_amount: "6.00",
next_bill_date: Timex.today(),
last_bill_date: Timex.today(),
currency_code: "USD"
}
end
def enterprise_plan_factory do
%Plausible.Billing.EnterprisePlan{
paddle_plan_id: sequence(:paddle_plan_id, &"plan-#{&1}"),
billing_interval: :monthly,
monthly_pageview_limit: 1_000_000,
hourly_api_request_limit: 3000,
site_limit: 100
}
end
def google_auth_factory do
%Plausible.Site.GoogleAuth{
email: sequence(:google_auth_email, &"email-#{&1}@email.com"),
refresh_token: "123",
access_token: "123",
expires: Timex.now() |> Timex.shift(days: 1)
}
end
def custom_domain_factory do
%Plausible.Site.CustomDomain{
domain: sequence(:custom_domain, &"domain-#{&1}.com")
}
end
def weekly_report_factory do
%Plausible.Site.WeeklyReport{}
end
def monthly_report_factory do
%Plausible.Site.MonthlyReport{}
end
def shared_link_factory do
%Plausible.Site.SharedLink{
name: "Link name",
slug: Nanoid.generate()
}
end
def invitation_factory do
%Plausible.Auth.Invitation{
invitation_id: Nanoid.generate(),
email: sequence(:email, &"email-#{&1}@example.com"),
role: :admin
}
end
def api_key_factory do
key = :crypto.strong_rand_bytes(64) |> Base.url_encode64() |> binary_part(0, 64)
%Plausible.Auth.ApiKey{
name: "api-key-name",
key: key,
key_hash: Plausible.Auth.ApiKey.do_hash(key),
key_prefix: binary_part(key, 0, 6)
}
end
def imported_visitors_factory do
%{
table: "imported_visitors",
date: Timex.today(),
visitors: 1,
pageviews: 1,
bounces: 0,
visits: 1,
visit_duration: 10
}
end
def imported_sources_factory do
%{
table: "imported_sources",
date: Timex.today(),
source: "",
visitors: 1,
visits: 1,
bounces: 0,
visit_duration: 10
}
end
def imported_pages_factory do
%{
table: "imported_pages",
date: Timex.today(),
page: "",
visitors: 1,
pageviews: 1,
exits: 0,
time_on_page: 10
}
end
def imported_entry_pages_factory do
%{
table: "imported_entry_pages",
date: Timex.today(),
entry_page: "",
visitors: 1,
entrances: 1,
bounces: 0,
visit_duration: 10
}
end
def imported_exit_pages_factory do
%{
table: "imported_exit_pages",
date: Timex.today(),
exit_page: "",
visitors: 1,
exits: 1
}
end
def imported_locations_factory do
%{
table: "imported_locations",
date: Timex.today(),
country: "",
region: "",
city: 0,
visitors: 1,
visits: 1,
bounces: 0,
visit_duration: 10
}
end
def imported_devices_factory do
%{
table: "imported_devices",
date: Timex.today(),
device: "",
visitors: 1,
visits: 1,
bounces: 0,
visit_duration: 10
}
end
def imported_browsers_factory do
%{
table: "imported_browsers",
date: Timex.today(),
browser: "",
visitors: 1,
visits: 1,
bounces: 0,
visit_duration: 10
}
end
def imported_operating_systems_factory do
%{
table: "imported_operating_systems",
date: Timex.today(),
operating_system: "",
visitors: 1,
visits: 1,
bounces: 0,
visit_duration: 10
}
end
defp hash_key() do
Keyword.fetch!(
Application.get_env(:plausible, PlausibleWeb.Endpoint),
:secret_key_base
)
|> binary_part(0, 16)
end
end