Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions app/controllers/test_utilities_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,39 @@

class TestUtilitiesController < ApplicationController
skip_before_action :verify_authenticity_token
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
before_action :ensure_allowed

ALLOWED_HOSTS = ['test-editor-api.raspberrypi.org', 'localhost'].freeze

Rails.application.load_tasks if Rake::Task.tasks.empty?

def reseed
if reseed_allowed?
Rake::Task['test_seeds:destroy'].execute
Rake::Task['test_seeds:create'].execute
render json: { message: 'Database reseeded successfully.' }, status: :ok
else
head :not_found
end
Rake::Task['test_seeds:destroy'].execute
Rake::Task['test_seeds:create'].execute
render json: { message: 'Database reseeded successfully.' }, status: :ok
end

def enable_feature
Flipper.enable(feature_key)
head :no_content
end

def disable_feature
Flipper.disable(feature_key)
head :no_content
end

private

def reseed_allowed?
def ensure_allowed
not_found unless allowed?
end

def not_found
head :not_found
end

def allowed?
api_key_valid? && host_allowed?
end

Expand All @@ -29,4 +45,8 @@ def api_key_valid?
def host_allowed?
ALLOWED_HOSTS.include?(request.host)
end

def feature_key
params.expect(:feature_key)
end
end
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
end

post '/test/reseed', to: 'test_utilities#reseed'
post '/test/enable_feature', to: 'test_utilities#enable_feature'
post '/test/disable_feature', to: 'test_utilities#disable_feature'

post '/graphql', to: 'graphql#execute'
mount GraphiQL::Rails::Engine, at: '/graphql', graphql_path: '/graphql#execute' unless Rails.env.production?
Expand Down
5 changes: 3 additions & 2 deletions lib/tasks/test_seeds.rake
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ namespace :test_seeds do
school_ids = [school_id, teacher_signup_school_id].compact
School.where(id: school_ids).destroy_all

# Clear any feature flags that may have been set
Flipper.features.each(&:remove)

Rails.logger.info 'Done...'
end
end
Expand All @@ -52,8 +55,6 @@ namespace :test_seeds do
teacher_id = ENV.fetch('SEEDING_TEACHER_ID', TEST_USERS[:john_doe])

school = create_school(creator_id, TEST_SCHOOL)
Flipper.enable_actor :cat_mode, school
Flipper.enable_actor :student_sso, school
Comment on lines -55 to -56

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully these changes mean that we no longer need to hard-code features.

And I think cat_mode is no longer in use.


verify_school(school)
assign_a_teacher(teacher_id, school)
Expand Down
16 changes: 6 additions & 10 deletions spec/lib/test_seeds_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
expect(Project.where(school_id: school.id)).not_to exist
expect(ScratchAsset.where(project_id: scratch_project_id)).not_to exist
end

it 'removes all feature flags' do
Flipper.enable(:some_feature)
task.invoke
expect(Flipper.features).to be_empty
end
end

describe ':seed_a_school_with_lessons_and_students' do
Expand All @@ -54,16 +60,6 @@
expect(School.find_by(creator_id:).verified_at).to be_truthy
end

it 'enables scratch for the school' do
school = School.find_by(creator_id:)
expect(Flipper.enabled?(:cat_mode, school)).to be(true)
end

it 'enables student sso for the school' do
school = School.find_by(creator_id:)
expect(Flipper.enabled?(:student_sso, school)).to be(true)
end

it 'creates lessons with projects' do
school = School.find_by(creator_id:)
expect(SchoolClass.where(school_id: school.id)).to exist
Expand Down
204 changes: 204 additions & 0 deletions spec/requests/test_utilities_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe TestUtilitiesController do
let(:headers) { { 'X-RESEED-API-KEY' => ENV.fetch('RESEED_API_KEY', nil) } }

before do
host! 'test-editor-api.raspberrypi.org'
ENV['RESEED_API_KEY'] = 'my_test_api_key'
end

after do
ENV.delete('RESEED_API_KEY')
end

describe 'POST /test/reseed' do
subject(:request) { post('/test/reseed', headers:) }

before do
allow(Rake::Task['test_seeds:destroy']).to receive(:execute)
allow(Rake::Task['test_seeds:create']).to receive(:execute)
end

around do |example|
DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.strategy = :transaction

DatabaseCleaner.cleaning do
Rake::Task.tasks.each(&:reenable)
example.run
ensure
Rake::Task.tasks.each(&:reenable)
end
end

it 'returns OK' do
request
expect(response).to be_ok
end

it 'destroys the test seeds' do
request
expect(Rake::Task['test_seeds:destroy']).to have_received(:execute)
end

it 'recreates the test seeds' do
request
expect(Rake::Task['test_seeds:create']).to have_received(:execute)
end

context 'when the host is not allowed' do
before do
host! 'editor-api.raspberrypi.org'
end

it 'returns not found' do
request
expect(response).to be_not_found
end

it 'does not destroy test seeds' do
request
expect(Rake::Task['test_seeds:destroy']).not_to have_received(:execute)
end

it 'does not recreate test seeds' do
request
expect(Rake::Task['test_seeds:create']).not_to have_received(:execute)
end
end

context 'when the RESEED_API_KEY is not set in the environment' do
let(:headers) { { 'X-RESEED-API-KEY' => '' } }

before do
ENV.delete('RESEED_API_KEY')
end

it 'returns not found' do
request
expect(response).to be_not_found
end

it 'does not destroy test seeds' do
request
expect(Rake::Task['test_seeds:destroy']).not_to have_received(:execute)
end

it 'does not recreate test seeds' do
request
expect(Rake::Task['test_seeds:create']).not_to have_received(:execute)
end
end

context 'when the X-RESEED_API_KEY is incorrect' do
let(:headers) { { 'X-RESEED-API-KEY' => 'my_dodgy_api_key' } }

it 'returns not found' do
request
expect(response).to be_not_found
end

it 'does not destroy test seeds' do
request
expect(Rake::Task['test_seeds:destroy']).not_to have_received(:execute)
end

it 'does not recreate test seeds' do
request
expect(Rake::Task['test_seeds:create']).not_to have_received(:execute)
end
end
end

describe 'feature toggle endpoints' do
let(:school) { create(:school) }
let(:feature_key) { :flipper_feature }
let(:params) do
{
feature_key:
}
end

shared_examples 'a rejected feature toggle request' do
it 'returns not found' do
request
expect(response).to be_not_found
end

it 'does not change the feature' do
expect { request }.not_to(change { Flipper.enabled?(feature_key, school) })
end
end

shared_examples 'a feature toggle endpoint' do
it 'returns no content' do
request
expect(response).to be_no_content
end

context 'when the feature_key param is missing' do
let(:params) { {} }

it 'returns bad request' do
request
expect(response).to be_bad_request
end

it 'does not change the feature' do
expect { request }.not_to(change { Flipper.enabled?(feature_key, school) })
end
end

context 'when the host is not allowed' do
before { host! 'editor-api.raspberrypi.org' }

it_behaves_like 'a rejected feature toggle request'
end

context 'when the RESEED_API_KEY is not set in the environment' do
let(:headers) { { 'X-RESEED-API-KEY' => '' } }

before { ENV.delete('RESEED_API_KEY') }

it_behaves_like 'a rejected feature toggle request'
end

context 'when the X-RESEED-API-KEY is incorrect' do
let(:headers) { { 'X-RESEED-API-KEY' => 'my_dodgy_api_key' } }

it_behaves_like 'a rejected feature toggle request'
end
end

describe 'POST /test/enable_feature' do
subject(:request) { post('/test/enable_feature', headers:, params:) }

before do
Flipper.disable(feature_key)
end

it 'universally enables the feature' do
expect { request }.to change { Flipper.enabled?(feature_key, school) }.from(false).to(true)
end

it_behaves_like 'a feature toggle endpoint'
end

describe 'POST /test/disable_feature' do
subject(:request) { post('/test/disable_feature', headers:, params:) }

before do
Flipper.enable_actor(feature_key, school)
end

it 'universally disables the feature' do
expect { request }.to change { Flipper.enabled?(feature_key, school) }.from(true).to(false)
end

it_behaves_like 'a feature toggle endpoint'
end
end
end
Loading
Loading