diff --git a/plugin.rb b/plugin.rb index d01cf33..5cc1dd6 100644 --- a/plugin.rb +++ b/plugin.rb @@ -54,6 +54,7 @@ after_initialize do # explain - the query def self.run_query(query, req_params={}, opts={}) # Safety checks + # see test 'doesn't allow you to modify the database #2' if query.sql =~ /;/ err = DataExplorer::ValidationError.new(I18n.t('js.errors.explorer.no_semicolons')) return {error: err, duration_nanos: 0} @@ -74,10 +75,11 @@ after_initialize do begin ActiveRecord::Base.connection.transaction do # Setting transaction to read only prevents shoot-in-foot actions like SELECT FOR UPDATE + # see test 'doesn't allow you to modify the database #1' ActiveRecord::Base.exec_sql "SET TRANSACTION READ ONLY" - # SQL comments are for the benefits of the slow queries log - sql = < ex diff --git a/spec/controllers/queries_controller_spec.rb b/spec/controllers/queries_controller_spec.rb index e69de29..88cd98d 100644 --- a/spec/controllers/queries_controller_spec.rb +++ b/spec/controllers/queries_controller_spec.rb @@ -0,0 +1,214 @@ +require 'spec_helper' + +describe DataExplorer::QueryController do + routes { ::DataExplorer::Engine.routes } + + def response_json + MultiJson.load(response.body) + end + + before do + SiteSetting.data_explorer_enabled = true + end + + let!(:admin) {log_in_user(Fabricate(:admin))} + + def make_query(sql='SELECT 1 as value') + q = DataExplorer::Query.new + q.id = Fabrication::Sequencer.sequence("query-id", 1) + q.name = "Query number #{q.id}" + q.description = "A description for query number #{q.id}" + q.sql = sql + q.save + q + end + + describe "when disabled" do + before do + SiteSetting.data_explorer_enabled = false + end + it 'denies every request' do + get :index; expect(response.body).to be_empty # check_xhr fail + expect { xhr :get, :index }.to raise_error ApplicationController::PluginDisabled + expect { xhr :get, :schema }.to raise_error ApplicationController::PluginDisabled + expect { xhr :get, :show, id: 3 }.to raise_error ApplicationController::PluginDisabled + expect { xhr :post, :create, id: 3 }.to raise_error ApplicationController::PluginDisabled + expect { xhr :post, :run, id: 3 }.to raise_error ApplicationController::PluginDisabled + expect { xhr :put, :update, id: 3 }.to raise_error ApplicationController::PluginDisabled + expect { xhr :delete, :destroy, id: 3 }.to raise_error ApplicationController::PluginDisabled + end + end + + describe "#index" do + it "behaves nicely with no queries" do + DataExplorer::Query.destroy_all + xhr :get, :index + expect(response).to be_success + expect(response_json['queries']).to eq([]) + end + + it "shows all available queries" do + DataExplorer::Query.destroy_all + q1 = make_query + q2 = make_query + xhr :get, :index + expect(response).to be_success + expect(response_json['queries'].length).to eq(2) + expect(response_json['queries'][0]['name']).to eq(q1.name) + expect(response_json['queries'][1]['name']).to eq(q2.name) + end + end + + describe "#run" do + let!(:admin) {log_in(:admin)} + + def run_query(id, params={}) + params = Hash[params.map { |a| [a[0], a[1].to_s] }] + xhr :post, :run, {id: id, _params: MultiJson.dump(params)} + end + it "can run queries" do + q = make_query('SELECT 23 as my_value') + run_query q.id + expect(response).to be_success + expect(response_json['success']).to eq(true) + expect(response_json['errors']).to eq([]) + expect(response_json['columns']).to eq(['my_value']) + expect(response_json['rows']).to eq([['23']]) + end + + it "can process parameters" do + q = make_query <