This way all tenants will be able to access them instead of just the default one. The apartment gem recommends using a rake task instead of a migration, but that's a solution which is primarily meant for new installations. Migrations are easier to execute on existing installations. However, since this migration doesn't affect the `schema.rb` file, we still need to make sure the shared schema is created in tasks which do not execute migrations, like `db:schema:load` or `db:test:prepare`, just like the apartment gem recommends. That's why we're enhancing these tasks so they execute this migration. Note that there might be cases where the database user isn't a superuser (as it's usually the case on production environments), meaning commands to create, alter or drop extensions will fail. There's also the case where users don't have permissions to create schemas, which is needed in order to create the shared extensions schema and the schemas used by the tenants. For these reasons, we're minimizing the number of commands, and so we only alter or create extensions when it is really necessary. When users don't have permission, we aren't running the commands but showing a warning with the steps needed to run the migration manually. This is only necessary on installations which are going to use multitenancy; single-tenant applications upgrading don't need to run this migration, and that's why we aren't raising exceptions when we can't run it. For new installations, we'll change the CONSUL installer so extensions are automatically created in the shared schema. Also note the plpgsql extension is not handled here. This is a special extension which must be installed on the pg_catalog schema, which is always in the search path and so is shared by all tenants. Finally, we also need to change the `database.yml` file in order to search for shared extensions while running migrations or model tests, since none of our enabled extensions are executed during migrations; we're also adding a rake task for existing installations. Quoting the apartment documentation: > your database.yml file must mimic what you've set for your default and > persistent schemas in Apartment. When you run migrations with Rails, > it won't know about the extensions schema because Apartment isn't > injected into the default connection, it's done on a per-request > basis.
156 lines
4.4 KiB
Ruby
156 lines
4.4 KiB
Ruby
require "rails_helper"
|
|
|
|
describe "Multitenancy" do
|
|
before do
|
|
create(:tenant, schema: "mars")
|
|
create(:tenant, schema: "venus")
|
|
end
|
|
|
|
scenario "Disabled features", :no_js do
|
|
Tenant.switch("mars") { Setting["process.debates"] = true }
|
|
Tenant.switch("venus") { Setting["process.debates"] = nil }
|
|
|
|
with_subdomain("mars") do
|
|
visit debates_path
|
|
|
|
expect(page).to have_css "#debates"
|
|
end
|
|
|
|
with_subdomain("venus") do
|
|
expect { visit debates_path }.to raise_exception(FeatureFlags::FeatureDisabled)
|
|
end
|
|
end
|
|
|
|
scenario "Content is different for differents tenants" do
|
|
Tenant.switch("mars") { create(:poll, name: "Human rights for Martians?") }
|
|
|
|
with_subdomain("mars") do
|
|
visit polls_path
|
|
|
|
expect(page).to have_content "Human rights for Martians?"
|
|
end
|
|
|
|
with_subdomain("venus") do
|
|
visit polls_path
|
|
|
|
expect(page).to have_content "There are no open votings"
|
|
end
|
|
end
|
|
|
|
scenario "PostgreSQL extensions work for tenants" do
|
|
Tenant.switch("mars") { login_as(create(:user)) }
|
|
|
|
with_subdomain("mars") do
|
|
visit new_proposal_path
|
|
fill_in "Proposal title", with: "Use the unaccent extension in Mars"
|
|
fill_in "Proposal summary", with: "tsvector for María the Martian"
|
|
check "I agree to the Privacy Policy and the Terms and conditions of use"
|
|
|
|
click_button "Create proposal"
|
|
|
|
expect(page).to have_content "Proposal created successfully."
|
|
|
|
click_link "No, I want to publish the proposal"
|
|
|
|
expect(page).to have_content "You've created a proposal!"
|
|
|
|
visit proposals_path
|
|
click_button "Advanced search"
|
|
fill_in "With the text", with: "Maria the Martian"
|
|
click_button "Filter"
|
|
|
|
expect(page).to have_content "Search results"
|
|
expect(page).to have_content "María the Martian"
|
|
end
|
|
end
|
|
|
|
scenario "Creating content in one tenant doesn't affect other tenants" do
|
|
Tenant.switch("mars") { login_as(create(:user)) }
|
|
|
|
with_subdomain("mars") do
|
|
visit new_debate_path
|
|
fill_in "Debate title", with: "Found any water here?"
|
|
fill_in_ckeditor "Initial debate text", with: "Found any water here?"
|
|
check "I agree to the Privacy Policy and the Terms and conditions of use"
|
|
|
|
click_button "Start a debate"
|
|
|
|
expect(page).to have_content "Debate created successfully."
|
|
expect(page).to have_content "Found any water here?"
|
|
end
|
|
|
|
with_subdomain("venus") do
|
|
visit debates_path
|
|
|
|
expect(page).to have_content "Sign in"
|
|
expect(page).not_to have_css ".debate"
|
|
|
|
visit new_debate_path
|
|
|
|
expect(page).to have_content "You must sign in or register to continue."
|
|
end
|
|
end
|
|
|
|
scenario "Users from another tenant cannot vote" do
|
|
Tenant.switch("mars") { create(:proposal, title: "Earth invasion") }
|
|
Tenant.switch("venus") { login_as(create(:user)) }
|
|
|
|
with_subdomain("venus") do
|
|
visit proposals_path
|
|
|
|
expect(page).to have_content "Sign out"
|
|
expect(page).not_to have_content "Earth invasion"
|
|
end
|
|
|
|
with_subdomain("mars") do
|
|
visit proposals_path
|
|
|
|
within(".proposal", text: "Earth invasion") do
|
|
click_button "Support"
|
|
|
|
expect(page).to have_content "You must sign in or sign up to continue"
|
|
end
|
|
end
|
|
end
|
|
|
|
scenario "Sign up into subdomain" do
|
|
with_subdomain("mars") do
|
|
visit "/"
|
|
click_link "Register"
|
|
|
|
fill_in "Username", with: "Marty McMartian"
|
|
fill_in "Email", with: "marty@consul.dev"
|
|
fill_in "Password", with: "20151021"
|
|
fill_in "Confirm password", with: "20151021"
|
|
check "By registering you accept the terms and conditions of use"
|
|
click_button "Register"
|
|
|
|
confirm_email
|
|
|
|
expect(page).to have_content "Your account has been confirmed."
|
|
end
|
|
end
|
|
|
|
scenario "Users from another tenant can't sign in" do
|
|
Tenant.switch("mars") { create(:user, email: "marty@consul.dev", password: "20151021") }
|
|
|
|
with_subdomain("mars") do
|
|
visit new_user_session_path
|
|
fill_in "Email or username", with: "marty@consul.dev"
|
|
fill_in "Password", with: "20151021"
|
|
click_button "Enter"
|
|
|
|
expect(page).to have_content "You have been signed in successfully."
|
|
end
|
|
|
|
with_subdomain("venus") do
|
|
visit new_user_session_path
|
|
fill_in "Email or username", with: "marty@consul.dev"
|
|
fill_in "Password", with: "20151021"
|
|
click_button "Enter"
|
|
|
|
expect(page).to have_content "Invalid Email or username or password."
|
|
end
|
|
end
|
|
end
|