diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 28dc58a49..d16eff5f2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -91,9 +91,7 @@ test:rspec:postgresql: - rake zammad:db:init - rake test:units - ruby -I test/ test/integration/object_manager_test.rb - - ruby -I test/ test/integration/object_manager_attributes_controller_test.rb - ruby -I test/ test/integration/package_test.rb - - ruby -I test/ test/integration/monitoring_controller_test.rb - rake db:drop test:unit:mysql: @@ -168,18 +166,6 @@ test:integration:user_agent: - rake db:drop allow_failure: true -test:integration:user_device: - <<: *artifacts_error - stage: test - variables: - RAILS_ENV: "test" - tags: - - core - script: - - rake zammad:db:unseeded - - ruby -I test/ test/integration/user_device_controller_test.rb - - rake db:drop - test:integration:slack: <<: *artifacts_error stage: test @@ -207,42 +193,6 @@ test:integration:clearbit: - rake db:drop allow_failure: true -test:integration:telegram: - <<: *artifacts_error - stage: test - variables: - RAILS_ENV: "test" - tags: - - core - script: - - rake zammad:db:init - - ruby -I test test/integration/telegram_controller_test.rb - - rake db:drop - -test:integration:twilio: - <<: *artifacts_error - stage: test - variables: - RAILS_ENV: "test" - tags: - - core - script: - - rake zammad:db:init - - ruby -I test test/integration/twilio_sms_controller_test.rb - - rake db:drop - -test:integration:idoit: - <<: *artifacts_error - stage: test - variables: - RAILS_ENV: "test" - tags: - - core - script: - - rake zammad:db:init - - ruby -I test test/integration/idoit_controller_test.rb - - rake db:drop - ### Elasticsearch .script_elasticsearch_template: &script_elasticsearch_definition diff --git a/.rubocop.yml b/.rubocop.yml index a0cee4e67..861bbed46 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -193,7 +193,7 @@ Lint/BooleanSymbol: Enabled: true Exclude: - "db/seeds/object_manager_attributes.rb" - - "test/integration/object_manager_attributes_controller_test.rb" + - "spec/requests/integration/object_manager_attributes_spec.rb" - "test/integration/object_manager_test.rb" Lint/InterpolationCheck: diff --git a/spec/factories/user_device.rb b/spec/factories/user_device.rb new file mode 100644 index 000000000..3ead8bc55 --- /dev/null +++ b/spec/factories/user_device.rb @@ -0,0 +1,18 @@ +FactoryBot.define do + sequence :fingerprint do |n| + "fingerprint#{n}" + end +end + +FactoryBot.define do + + factory :user_device do + user_id 1 + name 'test 1' + location 'some location' + user_agent 'some user agent' + ip '127.0.0.1' + fingerprint { generate(:fingerprint) } + end + +end diff --git a/spec/requests/integration/idoit_spec.rb b/spec/requests/integration/idoit_spec.rb new file mode 100644 index 000000000..9eac4c3fc --- /dev/null +++ b/spec/requests/integration/idoit_spec.rb @@ -0,0 +1,154 @@ +require 'rails_helper' + +RSpec.describe 'Idoit', type: :request do + + let!(:admin_user) do + create(:admin_user, groups: Group.all) + end + let!(:agent_user) do + create(:agent_user, groups: Group.all) + end + let!(:customer_user) do + create(:customer_user) + end + let!(:token) do + 'some_token' + end + let!(:endpoint) do + 'https://idoit.example.com/i-doit/' + end + + before(:each) do + Setting.set('idoit_integration', true) + Setting.set('idoit_config', { + api_token: token, + endpoint: endpoint, + client_id: '', + }) + end + + describe 'request handling' do + + it 'does unclear urls' do + + params = { + api_token: token, + endpoint: endpoint, + client_id: '', + } + authenticated_as(agent_user) + post '/api/v1/integration/idoit/verify', params: params, as: :json + expect(response).to have_http_status(401) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response).to_not be_blank + expect(json_response['error']).to eq('Not authorized (user)!') + + stub_request(:post, "#{endpoint}src/jsonrpc.php") + .with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{token}\"},\"version\":\"2.0\"}") + .to_return(status: 200, body: read_message('object_types_response'), headers: {}) + + params = { + api_token: token, + endpoint: endpoint, + client_id: '', + } + authenticated_as(admin_user) + post '/api/v1/integration/idoit/verify', params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response).to_not be_blank + expect(json_response['result']).to eq('ok') + expect(json_response['response']).to be_truthy + expect(json_response['response']['jsonrpc']).to eq('2.0') + expect(json_response['response']['result']).to be_truthy + + params = { + api_token: token, + endpoint: " #{endpoint}/", + client_id: '', + } + post '/api/v1/integration/idoit/verify', params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response).to_not be_blank + expect(json_response['result']).to eq('ok') + expect(json_response['response']).to be_truthy + expect(json_response['response']['jsonrpc']).to eq('2.0') + expect(json_response['response']['result']).to be_truthy + + end + + it 'does list all object types' do + + stub_request(:post, "#{endpoint}src/jsonrpc.php") + .with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{token}\"},\"version\":\"2.0\"}") + .to_return(status: 200, body: read_message('object_types_response'), headers: {}) + + params = { + method: 'cmdb.object_types', + } + authenticated_as(agent_user) + post '/api/v1/integration/idoit', params: params, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response).to_not be_blank + expect(json_response['result']).to eq('ok') + expect(json_response['response']).to be_truthy + expect(json_response['response']['jsonrpc']).to eq('2.0') + expect(json_response['response']['result']).to be_truthy + expect(json_response['response']['result'][0]['id']).to eq('1') + expect(json_response['response']['result'][0]['title']).to eq('System service') + + params = { + method: 'cmdb.object_types', + } + authenticated_as(admin_user) + post '/api/v1/integration/idoit', params: params, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response).to_not be_blank + expect(json_response['result']).to eq('ok') + expect(json_response['response']).to be_truthy + expect(json_response['response']['jsonrpc']).to eq('2.0') + expect(json_response['response']['result']).to be_truthy + expect(json_response['response']['result'][0]['id']).to eq('1') + expect(json_response['response']['result'][0]['title']).to eq('System service') + + end + + it 'does query objects' do + + stub_request(:post, "#{endpoint}src/jsonrpc.php") + .with(body: "{\"method\":\"cmdb.objects\",\"params\":{\"apikey\":\"#{token}\",\"filter\":{\"ids\":[\"33\"]}},\"version\":\"2.0\"}") + .to_return(status: 200, body: read_message('object_types_filter_response'), headers: {}) + + params = { + method: 'cmdb.objects', + filter: { + ids: ['33'] + }, + } + authenticated_as(agent_user) + post '/api/v1/integration/idoit', params: params, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response).to_not be_blank + expect(json_response['result']).to eq('ok') + expect(json_response['response']).to be_truthy + expect(json_response['response']['jsonrpc']).to eq('2.0') + expect(json_response['response']['result']).to be_truthy + expect(json_response['response']['result'][0]['id']).to eq('26') + expect(json_response['response']['result'][0]['title']).to eq('demo.example.com') + expect(json_response['response']['result'][0]['type_title']).to eq('Virtual server') + expect(json_response['response']['result'][0]['cmdb_status_title']).to eq('in operation') + + end + + def read_message(file) + File.read(Rails.root.join('test', 'data', 'idoit', "#{file}.json")) + end + end +end diff --git a/spec/requests/integration/monitoring_spec.rb b/spec/requests/integration/monitoring_spec.rb new file mode 100644 index 000000000..bce34009e --- /dev/null +++ b/spec/requests/integration/monitoring_spec.rb @@ -0,0 +1,680 @@ +require 'rails_helper' + +RSpec.describe 'Monitoring', type: :request do + + let!(:admin_user) do + create(:admin_user, groups: Group.all) + end + let!(:agent_user) do + create(:agent_user, groups: Group.all) + end + let!(:customer_user) do + create(:customer_user) + end + let!(:token) do + SecureRandom.urlsafe_base64(64) + end + + before(:each) do + Setting.set('monitoring_token', token) + + # channel cleanup + Channel.where.not(area: 'Email::Notification').destroy_all + Channel.all.each do |channel| + channel.status_in = 'ok' + channel.status_out = 'ok' + channel.last_log_in = nil + channel.last_log_out = nil + channel.save! + end + dir = Rails.root.join('tmp', 'unprocessable_mail') + Dir.glob("#{dir}/*.eml") do |entry| + File.delete(entry) + end + + Scheduler.where(active: true).each do |scheduler| + scheduler.last_run = Time.zone.now + scheduler.save! + end + + permission = Permission.find_by(name: 'admin.monitoring') + permission.active = true + permission.save! + end + + describe 'request handling' do + + it 'does monitoring without token' do + + # health_check + get '/api/v1/monitoring/health_check', params: {}, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['healthy']).to be_falsey + expect(json_response['error']).to eq('Not authorized') + + # status + get '/api/v1/monitoring/status', params: {}, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['agents']).to be_falsey + expect(json_response['last_login']).to be_falsey + expect(json_response['counts']).to be_falsey + expect(json_response['last_created_at']).to be_falsey + expect(json_response['error']).to eq('Not authorized') + + # token + post '/api/v1/monitoring/token', params: {}, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['token']).to be_falsey + expect(json_response['error']).to eq('authentication failed') + + end + + it 'does monitoring with wrong token' do + + # health_check + get '/api/v1/monitoring/health_check?token=abc', params: {}, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['healthy']).to be_falsey + expect(json_response['error']).to eq('Not authorized') + + # status + get '/api/v1/monitoring/status?token=abc', params: {}, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['agents']).to be_falsey + expect(json_response['last_login']).to be_falsey + expect(json_response['counts']).to be_falsey + expect(json_response['last_created_at']).to be_falsey + expect(json_response['error']).to eq('Not authorized') + + # token + post '/api/v1/monitoring/token', params: { token: 'abc' }, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['token']).to be_falsey + expect(json_response['error']).to eq('authentication failed') + + end + + it 'does monitoring with correct token' do + + # test storage usage + string = '' + 10.times do + string += 'Some Text Some Text Some Text Some Text Some Text Some Text Some Text Some Text' + end + Store.add( + object: 'User', + o_id: 1, + data: string, + filename: 'filename.txt', + created_by_id: 1, + ) + + # health_check + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response['healthy']).to eq(true) + expect(json_response['message']).to eq('success') + + # status + get "/api/v1/monitoring/status?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response.key?('agents')).to be_truthy + expect(json_response.key?('last_login')).to be_truthy + expect(json_response.key?('counts')).to be_truthy + expect(json_response.key?('last_created_at')).to be_truthy + + if ActiveRecord::Base.connection_config[:adapter] == 'postgresql' + expect(json_response['storage']).to be_truthy + expect(json_response['storage'].key?('kB')).to be_truthy + expect(json_response['storage'].key?('MB')).to be_truthy + expect(json_response['storage'].key?('GB')).to be_truthy + else + expect(json_response['storage']).to be_falsey + end + + # token + post '/api/v1/monitoring/token', params: { token: token }, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['token']).to be_falsey + expect(json_response['error']).to eq('authentication failed') + + end + + it 'does monitoring with admin user' do + + # health_check + authenticated_as(admin_user) + get '/api/v1/monitoring/health_check', params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response['healthy']).to eq(true) + expect(json_response['message']).to eq('success') + + # status + get '/api/v1/monitoring/status', params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response.key?('agents')).to be_truthy + expect(json_response.key?('last_login')).to be_truthy + expect(json_response.key?('counts')).to be_truthy + expect(json_response.key?('last_created_at')).to be_truthy + + # token + post '/api/v1/monitoring/token', params: { token: token }, as: :json + expect(response).to have_http_status(201) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['token']).to be_truthy + token = json_response['token'] + expect(json_response['error']).to be_falsey + + end + + it 'does monitoring with agent user' do + + # health_check + authenticated_as(agent_user) + get '/api/v1/monitoring/health_check', params: {}, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['healthy']).to be_falsey + expect(json_response['error']).to eq('Not authorized (user)!') + + # status + get '/api/v1/monitoring/status', params: {}, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['agents']).to be_falsey + expect(json_response['last_login']).to be_falsey + expect(json_response['counts']).to be_falsey + expect(json_response['last_created_at']).to be_falsey + expect(json_response['error']).to eq('Not authorized (user)!') + + # token + post '/api/v1/monitoring/token', params: { token: token }, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['token']).to be_falsey + expect(json_response['error']).to eq('Not authorized (user)!') + + end + + it 'does monitoring with admin user and invalid permission' do + + permission = Permission.find_by(name: 'admin.monitoring') + permission.active = false + permission.save! + + # health_check + authenticated_as(admin_user) + get '/api/v1/monitoring/health_check', params: {}, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['healthy']).to be_falsey + expect(json_response['error']).to eq('Not authorized (user)!') + + # status + get '/api/v1/monitoring/status', params: {}, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['agents']).to be_falsey + expect(json_response['last_login']).to be_falsey + expect(json_response['counts']).to be_falsey + expect(json_response['last_created_at']).to be_falsey + expect(json_response['error']).to eq('Not authorized (user)!') + + # token + post '/api/v1/monitoring/token', params: { token: token }, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['token']).to be_falsey + expect(json_response['error']).to eq('Not authorized (user)!') + + permission.active = true + permission.save! + end + + it 'does monitoring with correct token and invalid permission' do + + permission = Permission.find_by(name: 'admin.monitoring') + permission.active = false + permission.save! + + # health_check + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response['healthy']).to eq(true) + expect(json_response['message']).to eq('success') + + # status + get "/api/v1/monitoring/status?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response.key?('agents')).to be_truthy + expect(json_response.key?('last_login')).to be_truthy + expect(json_response.key?('counts')).to be_truthy + expect(json_response.key?('last_created_at')).to be_truthy + + # token + post '/api/v1/monitoring/token', params: { token: token }, as: :json + expect(response).to have_http_status(401) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['token']).to be_falsey + expect(json_response['error']).to eq('authentication failed') + + permission.active = true + permission.save! + + end + + it 'does check health false' do + + channel = Channel.find_by(active: true) + channel.status_in = 'ok' + channel.status_out = 'error' + channel.last_log_in = nil + channel.last_log_out = nil + channel.save! + + # health_check - channel + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect(json_response['message']).to eq('Channel: Email::Notification out ') + + # health_check - scheduler may not run + scheduler = Scheduler.where(active: true).last + scheduler.last_run = Time.zone.now - 20.minutes + scheduler.period = 600 + scheduler.save! + + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect(json_response['message']).to eq("Channel: Email::Notification out ;scheduler may not run (last execution of #{scheduler.method} 10 minutes over) - please contact your system administrator") + + # health_check - scheduler may not run + scheduler = Scheduler.where(active: true).last + scheduler.last_run = Time.zone.now - 1.day + scheduler.period = 600 + scheduler.save! + + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect(json_response['message']).to eq("Channel: Email::Notification out ;scheduler may not run (last execution of #{scheduler.method} about 24 hours over) - please contact your system administrator") + + # health_check - scheduler job count + travel 2.seconds + 8001.times do + Delayed::Job.enqueue( BackgroundJobSearchIndex.new('Ticket', 1)) + end + Scheduler.where(active: true).each do |local_scheduler| + local_scheduler.last_run = Time.zone.now + local_scheduler.save! + end + total_jobs = Delayed::Job.count + + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect(json_response['message']).to eq('Channel: Email::Notification out ') + + travel 20.minutes + Scheduler.where(active: true).each do |local_scheduler| + local_scheduler.last_run = Time.zone.now + local_scheduler.save! + end + + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect(json_response['message']).to eq("Channel: Email::Notification out ;#{total_jobs} background jobs in queue") + + Delayed::Job.delete_all + travel_back + + # health_check - unprocessable mail + dir = Rails.root.join('tmp', 'unprocessable_mail') + FileUtils.mkdir_p(dir) + FileUtils.touch("#{dir}/test.eml") + + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect(json_response['message']).to eq('Channel: Email::Notification out ;unprocessable mails: 1') + + # health_check - ldap + Setting.set('ldap_integration', true) + ImportJob.create( + name: 'Import::Ldap', + started_at: Time.zone.now, + finished_at: Time.zone.now, + result: { + error: 'Some bad error' + } + ) + + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect(json_response['message']).to eq("Channel: Email::Notification out ;unprocessable mails: 1;Failed to run import backend 'Import::Ldap'. Cause: Some bad error") + + stuck_updated_at_timestamp = 15.minutes.ago + ImportJob.create( + name: 'Import::Ldap', + started_at: Time.zone.now, + finished_at: nil, + updated_at: stuck_updated_at_timestamp, + ) + + # health_check + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect(json_response['message']).to eq("Channel: Email::Notification out ;unprocessable mails: 1;Failed to run import backend 'Import::Ldap'. Cause: Some bad error;Stuck import backend 'Import::Ldap' detected. Last update: #{stuck_updated_at_timestamp}") + + Setting.set('ldap_integration', false) + end + + it 'does check restart_failed_jobs' do + authenticated_as(admin_user) + post '/api/v1/monitoring/restart_failed_jobs', params: {}, as: :json + expect(response).to have_http_status(200) + end + + it 'does check failed delayed job', db_strategy: :reset do + + # disable elasticsearch + prev_es_config = Setting.get('es_url') + Setting.set('es_url', 'http://127.0.0.1:92001') + + # add a new object + object = create(:object_manager_attribute_text) + + migration = ObjectManager::Attribute.migration_execute + expect(true).to eq(migration) + + authenticated_as(admin_user) + post "/api/v1/object_manager_attributes/#{object.id}", params: {}, as: :json + token = @response.headers['CSRF-TOKEN'] + + # parameters for updating + params = { + 'name': 'test4', + 'object': 'Ticket', + 'display': 'Test 4', + 'active': true, + 'data_type': 'input', + 'data_option': { + 'default': 'test', + 'type': 'text', + 'maxlength': 120 + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + }, + 'id': 'c-196' + } + + # update the object + put "/api/v1/object_manager_attributes/#{object.id}", params: params, as: :json + + migration = ObjectManager::Attribute.migration_execute + expect(true).to eq(migration) + + expect(response).to have_http_status(200) + expect(json_response).to be_truthy + expect(json_response['data_option']['null']).to be_truthy + expect('test4').to eq(json_response['name']) + expect('Test 4').to eq(json_response['display']) + + jobs = Delayed::Job.all + + 4.times do + jobs.each do |job| + Delayed::Worker.new.run(job) + end + end + + # health_check + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect( json_response['message']).to eq("Failed to run background job #1 'BackgroundJobSearchIndex' 1 time(s) with 4 attempt(s).") + + # add another job + manual_added = Delayed::Job.enqueue( BackgroundJobSearchIndex.new('Ticket', 1)) + manual_added.update!(attempts: 10) + + # health_check + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect( json_response['message']).to eq("Failed to run background job #1 'BackgroundJobSearchIndex' 2 time(s) with 14 attempt(s).") + + # add another job + dummy_class = Class.new do + + def perform + puts 'work work' + end + end + + manual_added = Delayed::Job.enqueue( dummy_class.new ) + manual_added.update!(attempts: 5) + + # health_check + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect( json_response['message']).to eq("Failed to run background job #1 'BackgroundJobSearchIndex' 2 time(s) with 14 attempt(s).;Failed to run background job #2 'Object' 1 time(s) with 5 attempt(s).") + + # reset settings + Setting.set('es_url', prev_es_config) + + # add some more failing job + 10.times do + manual_added = Delayed::Job.enqueue( dummy_class.new ) + manual_added.update!(attempts: 5) + end + + # health_check + get "/api/v1/monitoring/health_check?token=#{token}", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['message']).to be_truthy + expect(json_response['issues']).to be_truthy + expect(json_response['healthy']).to eq(false) + expect( json_response['message']).to eq("13 failing background jobs;Failed to run background job #1 'Object' 8 time(s) with 40 attempt(s).;Failed to run background job #2 'BackgroundJobSearchIndex' 2 time(s) with 14 attempt(s).") + + # cleanup + Delayed::Job.delete_all + end + + it 'does check amount' do + Ticket.destroy_all + + # amount_check - ok + get "/api/v1/monitoring/amount_check?token=#{token}&periode=1h", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['state']).to eq('ok') + expect(json_response['message']).to eq('') + expect(json_response['count']).to eq(0) + + Ticket.destroy_all + (1..6).each do |i| + create(:ticket, title: "Ticket-#{i}") + travel 10.seconds + end + + get "/api/v1/monitoring/amount_check?token=#{token}&periode=1h&min_warning=10&min_critical=8", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['state']).to eq('critical') + expect(json_response['message']).to eq('The minimum of 8 was undercut by 6 in the last 1h') + expect(json_response['count']).to eq(6) + + get "/api/v1/monitoring/amount_check?token=#{token}&periode=1h&min_warning=7&min_critical=2", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['state']).to eq('warning') + expect(json_response['message']).to eq('The minimum of 7 was undercut by 6 in the last 1h') + expect(json_response['count']).to eq(6) + + get "/api/v1/monitoring/amount_check?token=#{token}&periode=1h&max_warning=10&max_critical=20", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['state']).to eq('ok') + expect(json_response['message']).to eq('') + expect(json_response['count']).to eq(6) + + (1..6).each do |i| + create(:ticket, title: "Ticket-#{i}") + travel 1.second + end + + get "/api/v1/monitoring/amount_check?token=#{token}&periode=1h&max_warning=10&max_critical=20", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['state']).to eq('warning') + expect(json_response['message']).to eq('The limit of 10 was exceeded with 12 in the last 1h') + expect(json_response['count']).to eq(12) + + (1..10).each do |i| + create(:ticket, title: "Ticket-#{i}") + travel 1.second + end + + get "/api/v1/monitoring/amount_check?token=#{token}&periode=1h&max_warning=10&max_critical=20", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['state']).to eq('critical') + expect(json_response['message']).to eq('The limit of 20 was exceeded with 22 in the last 1h') + expect(json_response['count']).to eq(22) + + get "/api/v1/monitoring/amount_check?token=#{token}&periode=1h", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['state']).to eq('ok') + expect(json_response['message']).to eq('') + expect(json_response['count']).to eq(22) + + travel 2.hours + + get "/api/v1/monitoring/amount_check?token=#{token}&periode=1h", params: {}, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['state']).to eq('ok') + expect(json_response['message']).to eq('') + expect(json_response['count']).to eq(0) + end + end +end diff --git a/spec/requests/integration/object_manager_attributes_spec.rb b/spec/requests/integration/object_manager_attributes_spec.rb new file mode 100644 index 000000000..3f1d47a63 --- /dev/null +++ b/spec/requests/integration/object_manager_attributes_spec.rb @@ -0,0 +1,1029 @@ +require 'rails_helper' + +RSpec.describe 'ObjectManager Attributes', type: :request do + + let(:admin_user) do + create(:admin_user) + end + + describe 'request handling' do + + it 'does add new ticket text object' do + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: {}, as: :json + token = response.headers['CSRF-TOKEN'] + + # token based on headers + params = { + 'name': 'test1', + 'object': 'Ticket', + 'display': 'Test 1', + 'active': true, + 'data_type': 'input', + 'data_option': { + 'default': 'test', + 'type': 'text', + 'maxlength': 120 + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + }, + 'id': 'c-196' + } + + post '/api/v1/object_manager_attributes', params: params, as: :json + expect(response).to have_http_status(201) + expect(json_response).to be_truthy + expect(json_response['data_option']['null']).to be_truthy + expect(json_response['data_option']['null']).to eq(true) + expect(json_response['name']).to eq('test1') + end + + it 'does add new ticket text object - no default' do + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: {}, as: :json + token = response.headers['CSRF-TOKEN'] + + # token based on headers + params = { + 'name': 'test2', + 'object': 'Ticket', + 'display': 'Test 2', + 'active': true, + 'data_type': 'input', + 'data_option': { + 'type': 'text', + 'maxlength': 120 + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + }, + 'id': 'c-196' + } + + post '/api/v1/object_manager_attributes', params: params, as: :json + expect(response).to have_http_status(201) + expect(json_response).to be_truthy + expect(json_response['data_option']['null']).to be_truthy + expect(json_response['data_option']['null']).to eq(true) + expect(json_response['name']).to eq('test2') + end + + it 'does update ticket text object', db_strategy: :reset do + + # add a new object + object = create(:object_manager_attribute_text) + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + authenticated_as(admin_user) + post "/api/v1/object_manager_attributes/#{object.id}", params: {}, as: :json + token = response.headers['CSRF-TOKEN'] + + # parameters for updating + params = { + 'name': 'test4', + 'object': 'Ticket', + 'display': 'Test 4', + 'active': true, + 'data_type': 'input', + 'data_option': { + 'default': 'test', + 'type': 'text', + 'maxlength': 120 + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + }, + 'id': 'c-196' + } + + # update the object + put "/api/v1/object_manager_attributes/#{object.id}", params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_truthy + expect(json_response['data_option']['null']).to be_truthy + expect(json_response['name']).to eq('test4') + expect(json_response['display']).to eq('Test 4') + end + + it 'does add new ticket boolean object' do + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: {}, as: :json + token = response.headers['CSRF-TOKEN'] + + # token based on headers + params = { + 'active': true, + 'data_option': { + 'options': { + 'false': 'no', + 'true': 'yes' + } + }, + 'data_type': 'boolean', + 'display': 'Boolean 2', + 'id': 'c-200', + 'name': 'bool2', + 'object': 'Ticket', + 'screens': { + 'create_middle': { + 'ticket.agent' => { + 'item_class': 'column', + 'shown': true + }, + 'ticket.customer' => { + 'item_class': 'column', + 'shown': true + } + }, + 'edit': { + 'ticket.agent' => { + 'shown': true + }, + 'ticket.customer' => { + 'shown': true + } + } + } + } + + post '/api/v1/object_manager_attributes', params: params, as: :json + expect(response).to have_http_status(201) + expect(json_response).to be_truthy + expect(json_response['data_option']['null']).to be_truthy + expect(json_response['data_option']['null']).to eq(true) + expect(json_response['name']).to eq('bool2') + end + + it 'does add new user select object' do + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: {}, as: :json + token = response.headers['CSRF-TOKEN'] + + # token based on headers + params = { + 'active': true, + 'data_option': { + 'options': { + 'key1': 'foo' + } + }, + 'data_type': 'select', + 'display': 'Test 5', + 'id': 'c-204', + 'name': 'test5', + 'object': 'User', + 'screens': { + 'create': { + 'admin.user' => { + 'shown': true + }, + 'ticket.agent' => { + 'shown': true + }, + 'ticket.customer' => { + 'shown': true + } + }, + 'edit': { + 'admin.user' => { + 'shown': true + }, + 'ticket.agent' => { + 'shown': true + } + }, + 'view': { + 'admin.user' => { + 'shown': true + }, + 'ticket.agent' => { + 'shown': true + }, + 'ticket.customer' => { + 'shown': true + } + } + } + } + + post '/api/v1/object_manager_attributes', params: params, as: :json + expect(response).to have_http_status(201) + expect(json_response).to be_truthy + expect(json_response['data_option']['null']).to be_truthy + expect(json_response['data_option']['null']).to eq(true) + expect(json_response['name']).to eq('test5') + end + + it 'does update user select object', db_strategy: :reset do + + # add a new object + object = create(:object_manager_attribute_text) + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + post "/api/v1/object_manager_attributes/#{object.id}", params: {}, as: :json + token = response.headers['CSRF-TOKEN'] + + # parameters for updating + params = { + active: true, + data_option: { + options: { + key1: 'foo', + key2: 'bar' + } + }, + data_type: 'select', + display: 'Test 7', + id: 'c-204', + name: 'test7', + object: 'User', + screens: { + create: { + 'admin.user' => { + shown: true + }, + 'ticket.agent' => { + shown: true + }, + 'ticket.customer' => { + shown: true + } + }, + edit: { + 'admin.user' => { + shown: true + }, + 'ticket.agent' => { + shown: true + } + }, + view: { + 'admin.user' => { + shown: true + }, + 'ticket.agent' => { + shown: true + }, + 'ticket.customer' => { + shown: true + } + } + } + } + + # update the object + authenticated_as(admin_user) + put "/api/v1/object_manager_attributes/#{object.id}", params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_truthy + expect(json_response['data_option']['options']).to be_truthy + expect(json_response['name']).to eq('test7') + expect(json_response['display']).to eq('Test 7') + end + + it 'does converts string to boolean for default value for boolean data type with true (01)', db_strategy: :reset do + params = { + 'name': "customerdescription#{rand(999_999_999)}", + 'object': 'Ticket', + 'display': "custom description#{rand(999_999_999)}", + 'active': true, + 'data_type': 'boolean', + 'data_option': { + 'options': { + 'true': '', + 'false': '', + }, + 'default': 'true', + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + } + }, + 'id': 'c-201' + } + + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: params, as: :json + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + expect(response).to have_http_status(201) # created + + expect(json_response).to be_truthy + expect(json_response['data_option']['default']).to be_truthy + expect(json_response['data_option']['default']).to eq(true) + expect(json_response['data_type']).to eq('boolean') + end + + it 'does converts string to boolean for default value for boolean data type with false (02)', db_strategy: :reset do + params = { + 'name': "customerdescription_#{rand(999_999_999)}", + 'object': 'Ticket', + 'display': "custom description #{rand(999_999_999)}", + 'active': true, + 'data_type': 'boolean', + 'data_option': { + 'options': { + 'true': '', + 'false': '', + }, + 'default': 'false', + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + } + }, + } + + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: params, as: :json + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + expect(response).to have_http_status(201) # created + + expect(json_response).to be_truthy + expect(json_response['data_option']['default']).to be_falsey + expect(json_response['data_option']['default']).to eq(false) + expect(json_response['data_type']).to eq('boolean') + end + + it 'does ticket attributes cannot be removed when it is referenced by an overview (03)', db_strategy: :reset do + + # 1. create a new ticket attribute and execute migration + migration = ObjectManager::Attribute.migration_execute + + params = { + 'name': 'test_attribute_referenced_by_an_overview', + 'object': 'Ticket', + 'display': 'Test Attribute', + 'active': true, + 'data_type': 'input', + 'data_option': { + 'default': '', + 'type': 'text', + 'maxlength': 120, + 'null': true, + 'options': {}, + 'relation': '' + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + }, + } + + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: params, as: :json + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + # 2. create an overview that uses the attribute + params = { + name: 'test_overview', + roles: Role.where(name: 'Agent').pluck(:name), + condition: { + 'ticket.state_id': { + 'operator': 'is', + 'value': Ticket::State.all.pluck(:id), + }, + 'ticket.test_attribute_referenced_by_an_overview': { + 'operator': 'contains', + 'value': 'DUMMY' + }, + }, + order: { + by: 'created_at', + direction: 'DESC', + }, + view: { + d: %w[title customer state created_at], + s: %w[number title customer state created_at], + m: %w[number title customer state created_at], + view_mode_default: 's', + }, + user_ids: [ '1' ], + } + + if Overview.where('name like ?', '%test%').empty? + post '/api/v1/overviews', params: params, as: :json + expect(response).to have_http_status(201) + expect(Hash).to eq(json_response.class) + expect('test_overview').to eq(json_response['name']) + end + + # 3. attempt to delete the ticket attribute + get '/api/v1/object_manager_attributes', as: :json + expect(response).to have_http_status(200) + target_attribute = json_response.select { |x| x['name'] == 'test_attribute_referenced_by_an_overview' && x['object'] == 'Ticket' } + expect(target_attribute.size).to eq(1) + target_id = target_attribute[0]['id'] + + delete "/api/v1/object_manager_attributes/#{target_id}", as: :json + expect(response).to have_http_status(422) + expect(response.body).to include('Overview') + expect(response.body).to include('test_overview') + expect(response.body).to include('cannot be deleted!') + end + + it 'does ticket attributes cannot be removed when it is referenced by a trigger (04)', db_strategy: :reset do + + # 1. create a new ticket attribute and execute migration + migration = ObjectManager::Attribute.migration_execute + + params = { + 'name': 'test_attribute_referenced_by_a_trigger', + 'object': 'Ticket', + 'display': 'Test Attribute', + 'active': true, + 'data_type': 'input', + 'data_option': { + 'default': '', + 'type': 'text', + 'maxlength': 120, + 'null': true, + 'options': {}, + 'relation': '' + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + }, + } + + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: params, as: :json + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + # 2. create an trigger that uses the attribute + params = { + name: 'test_trigger', + condition: { + 'ticket.test_attribute_referenced_by_a_trigger': { + 'operator': 'contains', + 'value': 'DUMMY' + } + }, + 'perform': { + 'ticket.state_id': { + 'value': '2' + } + }, + 'active': true, + 'id': 'c-3' + } + + if Trigger.where('name like ?', '%test%').empty? + post '/api/v1/triggers', params: params, as: :json + expect(response).to have_http_status(201) + expect(Hash).to eq(json_response.class) + expect('test_trigger').to eq(json_response['name']) + end + + # 3. attempt to delete the ticket attribute + get '/api/v1/object_manager_attributes', as: :json + expect(response).to have_http_status(200) + target_attribute = json_response.select { |x| x['name'] == 'test_attribute_referenced_by_a_trigger' && x['object'] == 'Ticket' } + expect(target_attribute.size).to eq(1) + target_id = target_attribute[0]['id'] + + delete "/api/v1/object_manager_attributes/#{target_id}", as: :json + expect(response).to have_http_status(422) + expect(response.body).to include('Trigger') + expect(response.body).to include('test_trigger') + expect(response.body).to include('cannot be deleted!') + end + + it 'does ticket attributes cannot be removed when it is referenced by a scheduler (05)', db_strategy: :reset do + + # 1. create a new ticket attribute and execute migration + migration = ObjectManager::Attribute.migration_execute + + params = { + 'name': 'test_attribute_referenced_by_a_scheduler', + 'object': 'Ticket', + 'display': 'Test Attribute', + 'active': true, + 'data_type': 'input', + 'data_option': { + 'default': '', + 'type': 'text', + 'maxlength': 120, + 'null': true, + 'options': {}, + 'relation': '' + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + }, + } + + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: params, as: :json + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + # 2. create a scheduler that uses the attribute + params = { + name: 'test_scheduler', + 'timeplan': { + 'days': { + 'Mon': true, + 'Tue': false, + 'Wed': false, + 'Thu': false, + 'Fri': false, + 'Sat': false, + 'Sun': false + }, + 'hours': { + '0': true, + '1': false, + '2': false, + '3': false, + '4': false, + '5': false, + '6': false, + '7': false, + '8': false, + '9': false, + '10': false, + '11': false, + '12': false, + '13': false, + '14': false, + '15': false, + '16': false, + '17': false, + '18': false, + '19': false, + '20': false, + '21': false, + '22': false, + '23': false + }, + 'minutes': { + '0': true, + '10': false, + '20': false, + '30': false, + '40': false, + '50': false + } + }, + 'condition': { + 'ticket.test_attribute_referenced_by_a_scheduler': { + 'operator': 'contains', + 'value': 'DUMMY' + } + }, + 'perform': { + 'ticket.state_id': { + 'value': '2' + } + }, + 'disable_notification': true, + 'note': '', + 'active': true, + 'id': 'c-0' + } + + if Job.where('name like ?', '%test%').empty? + post '/api/v1/jobs', params: params, as: :json + expect(response).to have_http_status(201) + expect(Hash).to eq(json_response.class) + expect('test_scheduler').to eq(json_response['name']) + end + + # 3. attempt to delete the ticket attribute + get '/api/v1/object_manager_attributes', as: :json + expect(response).to have_http_status(200) + target_attribute = json_response.select { |x| x['name'] == 'test_attribute_referenced_by_a_scheduler' && x['object'] == 'Ticket' } + expect(target_attribute.size).to eq(1) + target_id = target_attribute[0]['id'] + + delete "/api/v1/object_manager_attributes/#{target_id}", as: :json + expect(response).to have_http_status(422) + expect(response.body).to include('Job') + expect(response.body).to include('test_scheduler') + expect(response.body).to include('cannot be deleted!') + end + + it 'does ticket attributes can be removed when it is referenced by an overview but by user object (06)', db_strategy: :reset do + + # 1. create a new ticket attribute and execute migration + migration = ObjectManager::Attribute.migration_execute + + params = { + 'name': 'test_attribute_referenced_by_an_overview', + 'object': 'Ticket', + 'display': 'Test Attribute', + 'active': true, + 'data_type': 'input', + 'data_option': { + 'default': '', + 'type': 'text', + 'maxlength': 120, + 'null': true, + 'options': {}, + 'relation': '' + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + }, + } + + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: params, as: :json + + params = { + 'name': 'test_attribute_referenced_by_an_overview', + 'object': 'User', + 'display': 'Test Attribute', + 'active': true, + 'data_type': 'input', + 'data_option': { + 'default': '', + 'type': 'text', + 'maxlength': 120, + 'null': true, + 'options': {}, + 'relation': '' + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + }, + } + + post '/api/v1/object_manager_attributes', params: params, as: :json + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + # 2. create an overview that uses the attribute + params = { + name: 'test_overview', + roles: Role.where(name: 'Agent').pluck(:name), + condition: { + 'ticket.state_id': { + 'operator': 'is', + 'value': Ticket::State.all.pluck(:id), + }, + 'ticket.test_attribute_referenced_by_an_overview': { + 'operator': 'contains', + 'value': 'DUMMY' + }, + }, + order: { + by: 'created_at', + direction: 'DESC', + }, + view: { + d: %w[title customer state created_at], + s: %w[number title customer state created_at], + m: %w[number title customer state created_at], + view_mode_default: 's', + }, + user_ids: [ '1' ], + } + + if Overview.where('name like ?', '%test%').empty? + post '/api/v1/overviews', params: params, as: :json + expect(response).to have_http_status(201) + expect(Hash).to eq(json_response.class) + expect('test_overview').to eq(json_response['name']) + end + + # 3. attempt to delete the ticket attribute + get '/api/v1/object_manager_attributes', as: :json + expect(response).to have_http_status(200) + all_json_response = json_response + + target_attribute = all_json_response.select { |x| x['name'] == 'test_attribute_referenced_by_an_overview' && x['object'] == 'User' } + expect(target_attribute.size).to eq(1) + target_id = target_attribute[0]['id'] + + delete "/api/v1/object_manager_attributes/#{target_id}", as: :json + expect(response).to have_http_status(200) + + target_attribute = all_json_response.select { |x| x['name'] == 'test_attribute_referenced_by_an_overview' && x['object'] == 'Ticket' } + expect(target_attribute.size).to eq(1) + target_id = target_attribute[0]['id'] + + delete "/api/v1/object_manager_attributes/#{target_id}", as: :json + expect(response).to have_http_status(422) + expect(response.body).to include('Overview') + expect(response.body).to include('test_overview') + expect(response.body).to include('cannot be deleted!') + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + end + + it 'does verify if attribute type can not be changed (07)', db_strategy: :reset do + + params = { + 'name': "customerdescription_#{rand(999_999_999)}", + 'object': 'Ticket', + 'display': "custom description #{rand(999_999_999)}", + 'active': true, + 'data_type': 'boolean', + 'data_option': { + 'options': { + 'true': '', + 'false': '', + }, + 'default': 'false', + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + } + } + }, + } + + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: params, as: :json + + expect(response).to have_http_status(201) # created + + expect(json_response).to be_truthy + expect(json_response['data_option']['default']).to be_falsey + expect(json_response['data_option']['default']).to eq(false) + expect(json_response['data_type']).to eq('boolean') + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + params['data_type'] = 'input' + params['data_option'] = { + 'default': 'test', + 'type': 'text', + 'maxlength': 120 + } + + put "/api/v1/object_manager_attributes/#{json_response['id']}", params: params, as: :json + expect(response).to have_http_status(422) + expect(json_response).to be_truthy + expect(json_response['error']).to be_truthy + + end + + it 'does verify if attribute type can be changed (08)', db_strategy: :reset do + + params = { + 'name': "customerdescription_#{rand(999_999_999)}", + 'object': 'Ticket', + 'display': "custom description #{rand(999_999_999)}", + 'active': true, + 'data_type': 'input', + 'data_option': { + 'default': 'test', + 'type': 'text', + 'maxlength': 120, + }, + 'screens': { + 'create_middle': { + 'ticket.customer': { + 'shown': true, + 'item_class': 'column' + }, + 'ticket.agent': { + 'shown': true, + 'item_class': 'column' + } + }, + 'edit': { + 'ticket.customer': { + 'shown': true + }, + 'ticket.agent': { + 'shown': true + } + }, + }, + } + + authenticated_as(admin_user) + post '/api/v1/object_manager_attributes', params: params, as: :json + + expect(response).to have_http_status(201) # created + + expect(json_response).to be_truthy + expect(json_response['data_option']['default']).to eq('test') + expect(json_response['data_type']).to eq('input') + + migration = ObjectManager::Attribute.migration_execute + expect(migration).to eq(true) + + params['data_type'] = 'select' + params['data_option'] = { + 'default': 'fuu', + 'options': { + 'key1': 'foo', + 'key2': 'fuu', + } + } + + put "/api/v1/object_manager_attributes/#{json_response['id']}", params: params, as: :json + + expect(response).to have_http_status(200) + expect(json_response).to be_truthy + expect(json_response['data_option']['default']).to eq('test') + expect(json_response['data_option_new']['default']).to eq('fuu') + expect(json_response['data_type']).to eq('select') + end + end +end diff --git a/spec/requests/integration/telegram_spec.rb b/spec/requests/integration/telegram_spec.rb new file mode 100644 index 000000000..4a48f71d5 --- /dev/null +++ b/spec/requests/integration/telegram_spec.rb @@ -0,0 +1,367 @@ +require 'rails_helper' + +RSpec.describe 'Telegram', type: :request do + + describe 'request handling' do + + it 'does basic call' do + Ticket.destroy_all + + # configure telegram channel + token = 'valid_token' + bot_id = 123_456_789 + group_id = Group.find_by(name: 'Users').id + + UserInfo.current_user_id = 1 + Channel.where(area: 'Telegram::Bot').destroy_all + + # try with invalid token + stub_request(:post, 'https://api.telegram.org/botnot_existing/getMe') + .to_return(status: 404, body: '{"ok":false,"error_code":404,"description":"Not Found"}', headers: {}) + + expect do + Telegram.check_token('not_existing') + end.to raise_error(RuntimeError) + + # try valid token + stub_request(:post, "https://api.telegram.org/bot#{token}/getMe") + .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {}) + + bot = Telegram.check_token(token) + expect(bot['id']).to eq(bot_id) + + stub_request(:post, "https://api.telegram.org/bot#{token}/getMe") + .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {}) + + Setting.set('http_type', 'http') + expect do + Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!' }) + end.to raise_error(RuntimeError) + + # try invalid port + stub_request(:post, "https://api.telegram.org:443/bot#{token}/getMe") + .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {}) + stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook") + .with(body: { 'url' => "https://somehost.example.com:12345/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" }) + .to_return(status: 400, body: '{"ok":false,"error_code":400,"description":"Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 or 8443"}', headers: {}) + + Setting.set('http_type', 'https') + Setting.set('fqdn', 'somehost.example.com:12345') + expect do + Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!' }) + end.to raise_error(RuntimeError) + + # try invalid host + stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook") + .with(body: { 'url' => "https://somehost.example.com/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" }) + .to_return(status: 400, body: '{"ok":false,"error_code":400,"description":"Bad Request: bad webhook: getaddrinfo: Name or service not known"}', headers: {}) + + Setting.set('fqdn', 'somehost.example.com') + expect do + Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!' }) + end.to raise_error(RuntimeError) + + # valid token, host and port + stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook") + .with(body: { 'url' => "https://example.com/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" }) + .to_return(status: 200, body: '{"ok":true,"result":true,"description":"Webhook was set"}', headers: {}) + + Setting.set('fqdn', 'example.com') + channel = Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!' }) + UserInfo.current_user_id = nil + + # start communication #1 + post '/api/v1/channels/telegram_webhook', params: read_message('personal1_message_start'), as: :json + expect(response).to have_http_status(404) + + post '/api/v1/channels_telegram_webhook/not_existing', params: read_message('personal1_message_start'), as: :json + expect(response).to have_http_status(422) + expect(json_response['error']).to eq('bot param missing') + + callback_url = "/api/v1/channels_telegram_webhook/not_existing?bid=#{channel.options[:bot][:id]}" + post callback_url, params: read_message('personal1_message_start'), as: :json + expect(response).to have_http_status(422) + expect(json_response['error']).to eq('invalid callback token') + + callback_url = "/api/v1/channels_telegram_webhook/#{channel.options[:callback_token]}?bid=#{channel.options[:bot][:id]}" + post callback_url, params: read_message('personal1_message_start'), as: :json + expect(response).to have_http_status(200) + + # send message1 + post callback_url, params: read_message('personal1_message_content1'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(1) + ticket = Ticket.last + expect(ticket.title).to eq('Hello, I need your Help') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(1) + expect(ticket.articles.first.body).to eq('Hello, I need your Help') + expect(ticket.articles.first.content_type).to eq('text/plain') + + # send channel message1 + post callback_url, params: read_message('channel1_message_content1'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(1) + ticket = Ticket.last + expect(ticket.title).to eq('Hello, I need your Help') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(1) + expect(ticket.articles.first.body).to eq('Hello, I need your Help') + expect(ticket.articles.first.content_type).to eq('text/plain') + + # edit channel message1 + post callback_url, params: read_message('channel2_message_content1'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(1) + ticket = Ticket.last + expect(ticket.title).to eq('Hello, I need your Help') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(1) + expect(ticket.articles.first.body).to eq('Hello, I need your Help') + expect(ticket.articles.first.content_type).to eq('text/plain') + + # send same message again, ignore it + post callback_url, params: read_message('personal1_message_content1'), as: :json + expect(response).to have_http_status(200) + ticket = Ticket.last + expect(ticket.title).to eq('Hello, I need your Help') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(1) + expect(ticket.articles.first.body).to eq('Hello, I need your Help') + expect(ticket.articles.first.content_type).to eq('text/plain') + + # send message2 + post callback_url, params: read_message('personal1_message_content2'), as: :json + expect(response).to have_http_status(200) + ticket = Ticket.last + expect(ticket.title).to eq('Hello, I need your Help') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(2) + expect(ticket.articles.last.body).to eq('Hello, I need your Help 2') + expect(ticket.articles.last.content_type).to eq('text/plain') + + # send end message + post callback_url, params: read_message('personal1_message_end'), as: :json + expect(response).to have_http_status(200) + ticket = Ticket.last + expect(ticket.title).to eq('Hello, I need your Help') + expect(ticket.state.name).to eq('closed') + expect(ticket.articles.count).to eq(2) + expect(ticket.articles.last.body).to eq('Hello, I need your Help 2') + expect(ticket.articles.last.content_type).to eq('text/plain') + + # start communication #2 + post callback_url, params: read_message('personal2_message_start'), as: :json + expect(response).to have_http_status(200) + + # send message1 + post callback_url, params: read_message('personal2_message_content1'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(2) + ticket = Ticket.last + expect(ticket.title).to eq('Can you help me with my feature?') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(1) + expect(ticket.articles.first.body).to eq('Can you help me with my feature?') + expect(ticket.articles.first.content_type).to eq('text/plain') + + # send message2 + post callback_url, params: read_message('personal2_message_content2'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(2) + ticket = Ticket.last + expect(ticket.title).to eq('Can you help me with my feature?') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(2) + expect(ticket.articles.last.body).to eq('Yes of course! lalal') + expect(ticket.articles.last.content_type).to eq('text/plain') + + # start communication #3 + post callback_url, params: read_message('personal3_message_start'), as: :json + expect(response).to have_http_status(200) + + # send message1 + post callback_url, params: read_message('personal3_message_content1'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(3) + ticket = Ticket.last + expect(ticket.title).to eq('Can you help me with my feature?') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(1) + expect(ticket.articles.last.body).to eq('Can you help me with my feature?') + expect(ticket.articles.last.content_type).to eq('text/plain') + + # send message2 + stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") + .with(body: { 'file_id' => 'ABC-123VabcOcv123w0ABHywrcPqfrbAYIABC' }) + .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123VabcOcv123w0ABHywrcPqfrbAYIABC","file_path":"abc123"}}', headers: {}) + stub_request(:get, "https://api.telegram.org/file/bot#{token}/abc123") + .to_return(status: 200, body: 'ABC1', headers: {}) + + post callback_url, params: read_message('personal3_message_content2'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(3) + ticket = Ticket.last + expect(ticket.title).to eq('Can you help me with my feature?') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(2) + expect(ticket.articles.last.body).to match(/ 'AAQCABO0I4INAATATQAB5HWPq4XgxQACAg' }) + .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123AAQCABO0I4INAATATQAB5HWPq4XgxQACAg","file_path":"abc123"}}', headers: {}) + stub_request(:get, "https://api.telegram.org/file/bot#{token}/abc123") + .to_return(status: 200, body: 'ABC2', headers: {}) + stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") + .with(body: { 'file_id' => 'BQADAgADDgAD7x6ZSC_-1LMkOEmoAg' }) + .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123BQADAgADDgAD7x6ZSC_-1LMkOEmoAg","file_path":"abc123"}}', headers: {}) + + post callback_url, params: read_message('personal3_message_content3'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(3) + ticket = Ticket.last + expect(ticket.title).to eq('Can you help me with my feature?') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(3) + expect(ticket.articles.last.body).to match(/ 'AwADAgADVQADCEIYSZwyOmSZK9iZAg' }) + .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123AwADAgADVQADCEIYSZwyOmSZK9iZAg","file_path":"abc123"}}', headers: {}) + + post callback_url, params: read_message('personal3_message_content5'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(3) + ticket = Ticket.last + expect(ticket.title).to eq('Can you help me with my feature?') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(4) + expect(ticket.articles.last.content_type).to eq('text/html') + expect(ticket.articles.last.attachments.count).to eq(1) + + # send channel message 4 with voice + post callback_url, params: read_message('channel1_message_content4'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(3) + ticket = Ticket.last + expect(ticket.title).to eq('Can you help me with my feature?') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(4) + expect(ticket.articles.last.content_type).to eq('text/html') + expect(ticket.articles.last.attachments.count).to eq(1) + + # start communication #4 - with sticker + stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") + .with(body: { 'file_id' => 'AAQDABO3-e4qAASs6ZOjJUT7tQ4lAAIC' }) + .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123AAQDABO3-e4qAASs6ZOjJUT7tQ4lAAIC","file_path":"abc123"}}', headers: {}) + stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") + .with(body: { 'file_id' => 'BQADAwAD0QIAAqbJWAAB8OkQqgtDQe0C' }) + .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123BQADAwAD0QIAAqbJWAAB8OkQqgtDQe0C","file_path":"abc123"}}', headers: {}) + + post callback_url, params: read_message('personal4_message_content1'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(4) + ticket = Ticket.last + if Rails.application.config.db_4bytes_utf8 + expect(ticket.title).to eq('💻') + else + expect(ticket.title).to eq('') + end + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(1) + expect(ticket.articles.last.body).to match(/ 'AgADAgADwacxGxk5MUmim45lijOwsKk1Sw0ABNQoaI8BwR_z_2MFAAEC' }) + .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123AgADAgADwacxGxk5MUmim45lijOwsKk1Sw0ABNQoaI8BwR_z_2MFAAEC","file_path":"abc123"}}', headers: {}) + + post callback_url, params: read_message('personal5_message_content1'), as: :json + expect(response).to have_http_status(200) + expect(Ticket.count).to eq(5) + ticket = Ticket.last + expect(ticket.title).to eq('-') + expect(ticket.state.name).to eq('new') + expect(ticket.articles.count).to eq(1) + expect(ticket.articles.last.body).to match(/').to eq(json_response['error']) + + channel.group_id = Group.first.id + channel.save! + + post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_message('inbound_sms1'), as: :json + expect(response).to have_http_status(200) + xml_response = REXML::Document.new(response.body) + expect(1).to eq(xml_response.elements.count) + + ticket = Ticket.last + article = Ticket::Article.last + customer = User.last + expect(ticket.articles.count).to eq(1) + expect(ticket.title).to eq('Ldfhxhcuffufuf. Fifififig. Fifififiif F...') + expect(ticket.state.name).to eq('new') + expect(ticket.group_id).to eq(group_id) + expect(ticket.customer_id).to eq(customer.id) + expect(ticket.created_by_id).to eq(customer.id) + expect(article.from).to eq('+491710000000') + expect(article.to).to eq('+4915700000000') + expect(article.cc).to be_nil + expect(article.subject).to be_nil + expect(article.body).to eq('Ldfhxhcuffufuf. Fifififig. Fifififiif Fifififiif Fifififiif Fifififiif Fifififiif') + expect(article.created_by_id).to eq(customer.id) + expect(article.sender.name).to eq('Customer') + expect(article.type.name).to eq('sms') + + post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_message('inbound_sms2'), as: :json + expect(response).to have_http_status(200) + xml_response = REXML::Document.new(response.body) + expect(1).to eq(xml_response.elements.count) + + ticket.reload + expect(ticket.articles.count).to eq(2) + expect(ticket.state.name).to eq('new') + + article = Ticket::Article.last + expect(article.from).to eq('+491710000000') + expect(article.to).to eq('+4915700000000') + expect(article.cc).to be_nil + expect(article.subject).to be_nil + expect(article.body).to eq('Follow up') + expect(article.sender.name).to eq('Customer') + expect(article.type.name).to eq('sms') + expect(article.created_by_id).to eq(customer.id) + + # check duplicate callbacks + post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_message('inbound_sms2'), as: :json + expect(response).to have_http_status(200) + xml_response = REXML::Document.new(response.body) + expect(1).to eq(xml_response.elements.count) + + ticket.reload + expect(ticket.articles.count).to eq(2) + expect(ticket.state.name).to eq('new') + expect(article.id).to eq(Ticket::Article.last.id) + + # new ticket need to be create + ticket.state = Ticket::State.find_by(name: 'closed') + ticket.save! + + post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_message('inbound_sms3'), as: :json + expect(response).to have_http_status(200) + xml_response = REXML::Document.new(response.body) + expect(1).to eq(xml_response.elements.count) + + ticket.reload + expect(ticket.articles.count).to eq(2) + expect(ticket.id).to_not eq(Ticket.last.id) + expect(ticket.state.name).to eq('closed') + + ticket = Ticket.last + article = Ticket::Article.last + customer = User.last + expect(ticket.articles.count).to eq(1) + expect(ticket.title).to eq('new 2') + expect(ticket.group_id).to eq(group_id) + expect(ticket.customer_id).to eq(customer.id) + expect(ticket.created_by_id).to eq(customer.id) + expect(article.from).to eq('+491710000000') + expect(article.to).to eq('+4915700000000') + expect(article.cc).to be_nil + expect(article.subject).to be_nil + expect(article.body).to eq('new 2') + expect(article.created_by_id).to eq(customer.id) + expect(article.sender.name).to eq('Customer') + expect(article.type.name).to eq('sms') + + # reply by agent + params = { + ticket_id: ticket.id, + body: 'some test', + type: 'sms', + } + authenticated_as(agent_user) + post '/api/v1/ticket_articles', params: params, as: :json + expect(response).to have_http_status(201) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['subject']).to be_nil + expect(json_response['body']).to eq('some test') + expect(json_response['content_type']).to eq('text/plain') + expect(json_response['updated_by_id']).to eq(agent_user.id) + expect(json_response['created_by_id']).to eq(agent_user.id) + + stub_request(:post, 'https://api.twilio.com/2010-04-01/Accounts/111/Messages.json') + .with( + body: { + 'Body' => 'some test', + 'From' => '333', + 'To' => nil, + }, + headers: { + 'Accept' => 'application/json', + 'Accept-Charset' => 'utf-8', + 'Authorization' => 'Basic MTExOjIyMw==', + 'Content-Type' => 'application/x-www-form-urlencoded', + } + ).to_return(status: 200, body: '', headers: {}) + + expect(article.preferences[:delivery_retry]).to be_nil + expect(article.preferences[:delivery_status]).to be_nil + + Observer::Transaction.commit + Scheduler.worker(true) + + article = Ticket::Article.find(json_response['id']) + expect(article.preferences[:delivery_retry]).to eq(1) + expect(article.preferences[:delivery_status]).to eq('success') + + end + + it 'does customer based on already existing mobile attibute' do + + customer = create( + :customer_user, + email: 'me@example.com', + mobile: '01710000000', + ) + Observer::Transaction.commit + Scheduler.worker(true) + + # configure twilio channel + bot_id = 123_456_789 + + UserInfo.current_user_id = 1 + channel = create( + :channel, + area: 'Sms::Account', + options: { + adapter: 'sms/twilio', + webhook_token: 'f409460e50f76d331fdac8ba7b7963b6', + account_id: '111', + token: '223', + sender: '333', + }, + ) + + post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_message('inbound_sms1'), as: :json + expect(response).to have_http_status(200) + xml_response = REXML::Document.new(response.body) + expect(1).to eq(xml_response.elements.count) + + expect(customer.id).to eq(User.last.id) + end + + def read_message(file) + JSON.parse(File.read(Rails.root.join('test', 'data', 'twilio', "#{file}.json"))) + end + end +end diff --git a/spec/requests/integration/user_device_spec.rb b/spec/requests/integration/user_device_spec.rb new file mode 100644 index 000000000..7bed010ea --- /dev/null +++ b/spec/requests/integration/user_device_spec.rb @@ -0,0 +1,700 @@ +require 'rails_helper' + +RSpec.describe 'User Device', type: :request, sends_notification_emails: true do + + let!(:admin_user) do + create(:admin_user, login: 'user-device-admin', password: 'adminpw', groups: Group.all) + end + let!(:agent_user) do + create(:agent_user, login: 'user-device-agent', password: 'agentpw', groups: Group.all) + end + + before(:each) do + ENV['TEST_REMOTE_IP'] = '5.9.62.170' # de + ENV['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:46.0) Gecko/20100101 Firefox/46.0' + ENV['SWITCHED_FROM_USER_ID'] = nil + + UserDevice.destroy_all + end + + describe 'request handling' do + + it 'does index with nobody (01)' do + + get '/api/v1/signshow' + expect(response).to have_http_status(200) + expect(json_response).to be_a_kind_of(Hash) + expect('no valid session').to eq(json_response['error']) + expect(json_response['config']).to be_truthy + expect(controller.session[:user_device_fingerprint]).to be_falsey + + Scheduler.worker(true) + end + + it 'does login index with admin without fingerprint (02)' do + + params = { without_fingerprint: 'none', username: 'user-device-admin', password: 'adminpw' } + post '/api/v1/signin', params: params, as: :json + expect(response).to have_http_status(422) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to eq('Need fingerprint param!') + expect(json_response['config']).to be_falsey + expect(controller.session[:user_device_fingerprint]).to be_falsey + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(0) + end + + it 'does login index with admin with fingerprint - I (03)' do + params = { fingerprint: 'my_finger_print', username: 'user-device-admin', password: 'adminpw' } + post '/api/v1/signin', params: params, as: :json + expect(response).to have_http_status(201) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response['config']).to be_truthy + expect(controller.session[:user_device_fingerprint]).to eq('my_finger_print') + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + user_device_first = UserDevice.last + sleep 2 + + params = {} + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_a_kind_of(Array) + expect(controller.session[:user_device_fingerprint]).to eq('my_finger_print') + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + user_device_last = UserDevice.last + expect(user_device_first.updated_at.to_s).to eq(user_device_last.updated_at.to_s) + + params = { fingerprint: 'my_finger_print' } + get '/api/v1/signshow', params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['session']).to be_truthy + expect('user-device-admin').to eq(json_response['session']['login']) + expect(json_response['config']).to be_truthy + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + user_device_last = UserDevice.last + expect(user_device_first.updated_at.to_s).to eq(user_device_last.updated_at.to_s) + + ENV['USER_DEVICE_UPDATED_AT'] = (Time.zone.now - 4.hours).to_s + params = {} + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_a_kind_of(Array) + expect(controller.session[:user_device_fingerprint]).to eq('my_finger_print') + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + user_device_last = UserDevice.last + expect(user_device_last.updated_at.to_s).to_not eq(user_device_first.updated_at.to_s) + ENV['USER_DEVICE_UPDATED_AT'] = nil + + ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch + + #reset_notification_checks + + params = {} + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(2) + + # ip reset + ENV['TEST_REMOTE_IP'] = '5.9.62.170' # de + + end + + it 'does login index with admin with fingerprint - II (04)' do + + create( + :user_device, + user_id: admin_user.id, + fingerprint: 'fingerprintI', + ) + + params = { fingerprint: 'my_finger_print_II', username: 'user-device-admin', password: 'adminpw' } + post '/api/v1/signin', params: params, as: :json + expect(response).to have_http_status(201) + + check_notification do + + Scheduler.worker(true) + + sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(2) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response['config']).to be_truthy + expect(controller.session[:user_device_fingerprint]).to be_truthy + + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_a_kind_of(Array) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(2) + + params = { fingerprint: 'my_finger_print_II' } + get '/api/v1/signshow', params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['session']).to be_truthy + expect('user-device-admin').to eq(json_response['session']['login']) + expect(json_response['config']).to be_truthy + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(2) + + ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch + + params = {} + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(3) + + # ip reset + ENV['TEST_REMOTE_IP'] = '5.9.62.170' # de + end + + it 'does login index with admin with fingerprint - II (05)' do + + UserDevice.add( + ENV['HTTP_USER_AGENT'], + ENV['TEST_REMOTE_IP'], + admin_user.id, + 'my_finger_print_II', + 'session', # session|basic_auth|token_auth|sso + ) + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + + params = { fingerprint: 'my_finger_print_II', username: 'user-device-admin', password: 'adminpw' } + post '/api/v1/signin', params: params, as: :json + expect(response).to have_http_status(201) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response['config']).to be_truthy + expect(controller.session[:user_device_fingerprint]).to be_truthy + end + + it 'does login index with admin with basic auth (06)' do + + ENV['HTTP_USER_AGENT'] = 'curl 1.0.0' + UserDevice.add( + ENV['HTTP_USER_AGENT'], + '127.0.0.1', + admin_user.id, + '', + 'basic_auth', # session|basic_auth|token_auth|sso + ) + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + + ENV['HTTP_USER_AGENT'] = 'curl 1.2.3' + params = {} + authenticated_as(admin_user, password: 'adminpw') + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + + check_notification do + + Scheduler.worker(true) + + sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(2) + expect(json_response).to be_a_kind_of(Array) + user_device_first = UserDevice.last + sleep 2 + + params = {} + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(2) + expect(json_response).to be_a_kind_of(Array) + user_device_last = UserDevice.last + expect(user_device_first.id).to eq(user_device_last.id) + expect(user_device_first.updated_at.to_s).to eq(user_device_last.updated_at.to_s) + + user_device_last.updated_at = Time.zone.now - 4.hours + user_device_last.save! + + params = {} + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(2) + expect(json_response).to be_a_kind_of(Array) + user_device_last = UserDevice.last + expect(user_device_first.id).to eq(user_device_last.id) + expect(user_device_last.updated_at > user_device_first.updated_at).to be_truthy + end + + it 'does login index with admin with basic auth (07)' do + + ENV['HTTP_USER_AGENT'] = 'curl 1.2.3' + + UserDevice.add( + ENV['HTTP_USER_AGENT'], + ENV['TEST_REMOTE_IP'], + admin_user.id, + '', + 'basic_auth', # session|basic_auth|token_auth|sso + ) + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + + params = {} + authenticated_as(admin_user, password: 'adminpw') + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + expect(json_response).to be_a_kind_of(Array) + + end + + it 'does login index with agent with basic auth (08)' do + ENV['HTTP_USER_AGENT'] = 'curl 1.2.3' + + params = {} + authenticated_as(agent_user, password: 'agentpw') + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: agent_user, + ) + not_sent( + template: 'user_device_new_location', + user: agent_user, + ) + end + + expect(UserDevice.where(user_id: agent_user.id).count).to eq(1) + expect(json_response).to be_a_kind_of(Array) + end + + it 'does login index with agent with basic auth (09)' do + + ENV['HTTP_USER_AGENT'] = 'curl 1.2.3' + + UserDevice.add( + ENV['HTTP_USER_AGENT'], + ENV['TEST_REMOTE_IP'], + agent_user.id, + '', + 'basic_auth', # session|basic_auth|token_auth|sso + ) + + expect(UserDevice.where(user_id: agent_user.id).count).to eq(1) + + params = {} + authenticated_as(agent_user, password: 'agentpw') + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: agent_user, + ) + not_sent( + template: 'user_device_new_location', + user: agent_user, + ) + end + + expect(UserDevice.where(user_id: agent_user.id).count).to eq(1) + expect(json_response).to be_a_kind_of(Array) + + end + + it 'does login with switched_from_user_id (10)' do + expect(UserDevice.where(user_id: agent_user.id).count).to eq(0) + + ENV['SWITCHED_FROM_USER_ID'] = admin_user.id.to_s + + params = { fingerprint: 'my_finger_print_II', username: 'user-device-agent', password: 'agentpw' } + post '/api/v1/signin', params: params, as: :json + expect(response).to have_http_status(201) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: agent_user, + ) + not_sent( + template: 'user_device_new_location', + user: agent_user, + ) + end + + expect(UserDevice.where(user_id: agent_user.id).count).to eq(0) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response['config']).to be_truthy + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: agent_user, + ) + not_sent( + template: 'user_device_new_location', + user: agent_user, + ) + end + + expect(UserDevice.where(user_id: agent_user.id).count).to eq(0) + + ENV['USER_DEVICE_UPDATED_AT'] = (Time.zone.now - 4.hours).to_s + params = {} + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + expect(json_response).to be_a_kind_of(Array) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: agent_user, + ) + not_sent( + template: 'user_device_new_location', + user: agent_user, + ) + end + + expect(UserDevice.where(user_id: agent_user.id).count).to eq(0) + ENV['USER_DEVICE_UPDATED_AT'] = nil + + ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch + params = {} + get '/api/v1/users', params: params, as: :json + expect(response).to have_http_status(200) + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: agent_user, + ) + not_sent( + template: 'user_device_new_location', + user: agent_user, + ) + end + + # ip reset + ENV['TEST_REMOTE_IP'] = '5.9.62.170' # de + + expect(UserDevice.where(user_id: agent_user.id).count).to eq(0) + end + + it 'does login with invalid fingerprint (11)' do + params = { fingerprint: 'to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890', username: 'user-device-admin', password: 'adminpw' } + post '/api/v1/signin', params: params, as: :json + expect(response).to have_http_status(422) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to eq('fingerprint is 198 chars but can only be 160 chars!') + expect(json_response['config']).to be_falsey + expect(controller.session[:user_device_fingerprint]).to be_falsey + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(0) + end + + it 'does login with integer as fingerprint (12)' do + params = { fingerprint: 123_456_789, username: 'user-device-admin', password: 'adminpw' } + post '/api/v1/signin', params: params, as: :json + expect(response).to have_http_status(201) + expect(controller.session[:user_device_fingerprint]).to be_truthy + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(1) + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_nil + end + + it 'does login form controller - check no user device logging (13)' do + Setting.set('form_ticket_create', true) + + params = { + fingerprint: 'long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890' + } + authenticated_as(admin_user, password: 'adminpw') + post '/api/v1/form_config', params: params, as: :json + expect(response).to have_http_status(200) + + expect(json_response).to be_a_kind_of(Hash) + expect(json_response['error']).to be_falsey + expect(json_response['endpoint']).to be_truthy + expect(controller.session[:user_device_fingerprint]).to be_falsey + + check_notification do + + Scheduler.worker(true) + + not_sent( + template: 'user_device_new', + user: admin_user, + ) + not_sent( + template: 'user_device_new_location', + user: admin_user, + ) + end + + expect(UserDevice.where(user_id: admin_user.id).count).to eq(0) + end + end +end diff --git a/spec/requests/long_polling_spec.rb b/spec/requests/long_polling_spec.rb index d922aacb7..5b54a05b7 100644 --- a/spec/requests/long_polling_spec.rb +++ b/spec/requests/long_polling_spec.rb @@ -75,7 +75,9 @@ RSpec.describe 'LongPolling', type: :request do it 'send event spool and receive data' do - authenticated_as(agent_user) + # here we use a token for the authentication because the basic auth way with username and password + # will update the user by every request and return a different result for the test + authenticated_as(agent_user, token: create(:token, action: 'api', user_id: agent_user.id) ) get '/api/v1/message_send', params: { data: { event: 'login' } }, as: :json expect(response).to have_http_status(200) expect(json_response['client_id'].to_i).to be_between(1, 9_999_999_999) diff --git a/spec/requests/user/permission_spec.rb b/spec/requests/user/permission_spec.rb index 87c00c748..6248cee16 100644 --- a/spec/requests/user/permission_spec.rb +++ b/spec/requests/user/permission_spec.rb @@ -207,7 +207,16 @@ RSpec.describe 'User endpoint', type: :request do expect do put api_v1_update_user_path(requested), params: cleaned_params_for(requested).merge(firstname: 'Changed') end.to not_change { - requested.reload.attributes + requested.reload.attributes.tap do |attributes| + # take attributes as they are for different users + next if requester != requested + + # last_login and updated_at change every time + # even if the record itself should not change + attributes.delete_if do |key, _value| + %w[last_login updated_at].include?(key) + end + end } expect(response).to have_http_status(:unauthorized) diff --git a/spec/support/request.rb b/spec/support/request.rb index 1ef7548b6..39ae8943e 100644 --- a/spec/support/request.rb +++ b/spec/support/request.rb @@ -71,7 +71,7 @@ module ZammadSpecSupportRequest # mock authentication otherwise login won't # if user has no password (which is expensive to create) if password.nil? - allow(User).to receive(:authenticate).with(login, '').and_return(user) + allow(User).to receive(:authenticate).with(login, '') { user.update_last_login }.and_return(user) end # if we want to authenticate by token diff --git a/spec/support/sends_notification_emails.rb b/spec/support/sends_notification_emails.rb new file mode 100644 index 000000000..5cb48fcd9 --- /dev/null +++ b/spec/support/sends_notification_emails.rb @@ -0,0 +1,83 @@ +module SendsNotificationEmailsHelper + + # Provides a helper method to check notification email sending for a code block. + # + # @yield [] Description of block + # + # @example + # check_notification do + # + # SomeClass.do_things_and_send_notification + # + # sent( + # template: 'user_device_new', + # user: admin_user, + # ) + # end + # + # @return [nil] + def check_notification + @checking_notification = true + reset_notification_checks + yield + @checking_notification = false + end + + # Provides a helper method to check that a notification email wasn't sent. + # + # @param [Hash] args the arguments that get passed to "with hash_including" RSpec matchers + # @see NotificationFactory::Mailer.notification + # + # @example + # not_sent( + # template: 'user_device_new_location', + # user: admin_user, + # ) + # + # @return [nil] + def not_sent(args) + check_in_progress! + expect(NotificationFactory::Mailer).to_not have_received(:notification).with( + hash_including(args) + ) + end + + # Provides a helper method to check that a notification email was sent. + # + # @param [Hash] args the arguments that get passed to "with hash_including" RSpec matchers + # @see NotificationFactory::Mailer.notification + # + # @example + # sent( + # template: 'user_device_new_location', + # user: admin_user, + # ) + # + # @return [nil] + def sent(args) + check_in_progress! + expect(NotificationFactory::Mailer).to have_received(:notification).with( + hash_including(args) + ).once + end + + private + + def reset_notification_checks + check_in_progress! + RSpec::Mocks.space.proxy_for(NotificationFactory::Mailer).reset + # to be able to use `have_received` rspec expectations we need + # to stub the class and allow all calls which starts "recording" calls + allow(NotificationFactory::Mailer).to receive(:notification).and_call_original + end + + def check_in_progress! + return if @checking_notification + + raise "Don't check notification sending without `checking_notification` block around it." + end +end + +RSpec.configure do |config| + config.include SendsNotificationEmailsHelper, sends_notification_emails: true +end diff --git a/test/integration/idoit_controller_test.rb b/test/integration/idoit_controller_test.rb deleted file mode 100644 index 9fda87711..000000000 --- a/test/integration/idoit_controller_test.rb +++ /dev/null @@ -1,190 +0,0 @@ -require 'test_helper' -require 'webmock/minitest' - -class IdoitControllerTest < ActionDispatch::IntegrationTest - setup do - - stub_request(:any, 'https://images.zammad.com/api/v1/person/image') - .to_return(status: 404, body: '', headers: {}) - - @token = 'some_token' - @endpoint = 'https://idoit.example.com/i-doit/' - - @headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' } - - Setting.set('idoit_integration', true) - Setting.set('idoit_config', { - api_token: @token, - endpoint: @endpoint, - client_id: '', - }) - groups = Group.where(name: 'Users') - roles = Role.where(name: %w[Agent]) - agent = User.create_or_update( - login: 'idoit-agent@example.com', - firstname: 'E', - lastname: 'S', - email: 'idoit-agent@example.com', - password: 'agentpw', - active: true, - roles: roles, - groups: groups, - updated_by_id: 1, - created_by_id: 1, - ) - roles = Role.where(name: %w[Agent Admin]) - admin = User.create_or_update( - login: 'idoit-admin@example.com', - firstname: 'E', - lastname: 'S', - email: 'idoit-admin@example.com', - password: 'adminpw', - active: true, - roles: roles, - groups: groups, - updated_by_id: 1, - created_by_id: 1, - ) - - customer1 = User.create_or_update( - login: 'ticket-idoit-customer1@example.com', - firstname: 'CallerId', - lastname: 'Customer1', - email: 'ticket-idoit-customer1@example.com', - password: 'customerpw', - active: true, - updated_by_id: 1, - created_by_id: 1, - ) - - end - - test 'unclear urls' do - - agent_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-agent@example.com', 'agentpw') - params = { - api_token: @token, - endpoint: @endpoint, - client_id: '', - } - post '/api/v1/integration/idoit/verify', params: params.to_json, headers: @headers.merge('Authorization' => agent_credentials) - assert_response(401) - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result.blank?) - assert_equal('Not authorized (user)!', result['error']) - - stub_request(:post, "#{@endpoint}src/jsonrpc.php") - .with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{@token}\"},\"version\":\"2.0\"}") - .to_return(status: 200, body: read_messaage('object_types_response'), headers: {}) - - admin_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-admin@example.com', 'adminpw') - params = { - api_token: @token, - endpoint: @endpoint, - client_id: '', - } - post '/api/v1/integration/idoit/verify', params: params.to_json, headers: @headers.merge('Authorization' => admin_credentials) - assert_response(200) - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result.blank?) - assert_equal('ok', result['result']) - assert(result['response']) - assert_equal('2.0', result['response']['jsonrpc']) - assert(result['response']['result']) - - params = { - api_token: @token, - endpoint: " #{@endpoint}/", - client_id: '', - } - post '/api/v1/integration/idoit/verify', params: params.to_json, headers: @headers.merge('Authorization' => admin_credentials) - assert_response(200) - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result.blank?) - assert_equal('ok', result['result']) - assert(result['response']) - assert_equal('2.0', result['response']['jsonrpc']) - assert(result['response']['result']) - - end - - test 'list all object types' do - - stub_request(:post, "#{@endpoint}src/jsonrpc.php") - .with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{@token}\"},\"version\":\"2.0\"}") - .to_return(status: 200, body: read_messaage('object_types_response'), headers: {}) - - agent_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-agent@example.com', 'agentpw') - params = { - method: 'cmdb.object_types', - } - post '/api/v1/integration/idoit', params: params.to_json, headers: @headers.merge('Authorization' => agent_credentials) - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result.blank?) - assert_equal('ok', result['result']) - assert(result['response']) - assert_equal('2.0', result['response']['jsonrpc']) - assert(result['response']['result']) - assert_equal('1', result['response']['result'][0]['id']) - assert_equal('System service', result['response']['result'][0]['title']) - - admin_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-admin@example.com', 'adminpw') - params = { - method: 'cmdb.object_types', - } - post '/api/v1/integration/idoit', params: params.to_json, headers: @headers.merge('Authorization' => admin_credentials) - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result.blank?) - assert_equal('ok', result['result']) - assert(result['response']) - assert_equal('2.0', result['response']['jsonrpc']) - assert(result['response']['result']) - assert_equal('1', result['response']['result'][0]['id']) - assert_equal('System service', result['response']['result'][0]['title']) - - end - - test 'query objects' do - - stub_request(:post, "#{@endpoint}src/jsonrpc.php") - .with(body: "{\"method\":\"cmdb.objects\",\"params\":{\"apikey\":\"#{@token}\",\"filter\":{\"ids\":[\"33\"]}},\"version\":\"2.0\"}") - .to_return(status: 200, body: read_messaage('object_types_filter_response'), headers: {}) - - agent_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-agent@example.com', 'agentpw') - params = { - method: 'cmdb.objects', - filter: { - ids: ['33'] - }, - } - post '/api/v1/integration/idoit', params: params.to_json, headers: @headers.merge('Authorization' => agent_credentials) - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result.blank?) - assert_equal('ok', result['result']) - assert(result['response']) - assert_equal('2.0', result['response']['jsonrpc']) - assert(result['response']['result']) - assert_equal('26', result['response']['result'][0]['id']) - assert_equal('demo.example.com', result['response']['result'][0]['title']) - assert_equal('Virtual server', result['response']['result'][0]['type_title']) - assert_equal('in operation', result['response']['result'][0]['cmdb_status_title']) - - end - - def read_messaage(file) - File.read(Rails.root.join('test', 'data', 'idoit', "#{file}.json")) - end - -end diff --git a/test/integration/monitoring_controller_test.rb b/test/integration/monitoring_controller_test.rb deleted file mode 100644 index 1de1267a3..000000000 --- a/test/integration/monitoring_controller_test.rb +++ /dev/null @@ -1,816 +0,0 @@ -require 'integration_test_helper' - -class MonitoringControllerTest < ActionDispatch::IntegrationTest - - setup do - - # set accept header - @headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' } - - # set token - @token = SecureRandom.urlsafe_base64(64) - Setting.set('monitoring_token', @token) - - # create agent - roles = Role.where(name: %w[Admin Agent]) - groups = Group.all - - # channel cleanup - Channel.where.not(area: 'Email::Notification').destroy_all - Channel.all.each do |channel| - channel.status_in = 'ok' - channel.status_out = 'ok' - channel.last_log_in = nil - channel.last_log_out = nil - channel.save! - end - dir = Rails.root.join('tmp', 'unprocessable_mail') - Dir.glob("#{dir}/*.eml") do |entry| - File.delete(entry) - end - - Scheduler.where(active: true).each do |scheduler| - scheduler.last_run = Time.zone.now - scheduler.save! - end - - permission = Permission.find_by(name: 'admin.monitoring') - permission.active = true - permission.save! - - UserInfo.current_user_id = 1 - @admin = User.create_or_update( - login: 'monitoring-admin', - firstname: 'Monitoring', - lastname: 'Admin', - email: 'monitoring-admin@example.com', - password: 'adminpw', - active: true, - roles: roles, - groups: groups, - ) - - # create agent - roles = Role.where(name: 'Agent') - @agent = User.create_or_update( - login: 'monitoring-agent@example.com', - firstname: 'Monitoring', - lastname: 'Agent', - email: 'monitoring-agent@example.com', - password: 'agentpw', - active: true, - roles: roles, - groups: groups, - ) - - # create customer without org - roles = Role.where(name: 'Customer') - @customer_without_org = User.create_or_update( - login: 'monitoring-customer1@example.com', - firstname: 'Monitoring', - lastname: 'Customer1', - email: 'monitoring-customer1@example.com', - password: 'customer1pw', - active: true, - roles: roles, - ) - - end - - test '01 monitoring without token' do - - # health_check - get '/api/v1/monitoring/health_check', params: {}, headers: @headers - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['healthy']) - assert_equal('Not authorized', result['error']) - - # status - get '/api/v1/monitoring/status', params: {}, headers: @headers - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['agents']) - assert_not(result['last_login']) - assert_not(result['counts']) - assert_not(result['last_created_at']) - assert_equal('Not authorized', result['error']) - - # token - post '/api/v1/monitoring/token', params: {}, headers: @headers - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['token']) - assert_equal('authentication failed', result['error']) - - end - - test '02 monitoring with wrong token' do - - # health_check - get '/api/v1/monitoring/health_check?token=abc', params: {}, headers: @headers - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['healthy']) - assert_equal('Not authorized', result['error']) - - # status - get '/api/v1/monitoring/status?token=abc', params: {}, headers: @headers - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['agents']) - assert_not(result['last_login']) - assert_not(result['counts']) - assert_not(result['last_created_at']) - assert_equal('Not authorized', result['error']) - - # token - post '/api/v1/monitoring/token', params: { token: 'abc' }.to_json, headers: @headers - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['token']) - assert_equal('authentication failed', result['error']) - - end - - test '03 monitoring with correct token' do - - # test storage usage - string = '' - 10.times do - string += 'Some Text Some Text Some Text Some Text Some Text Some Text Some Text Some Text' - end - Store.add( - object: 'User', - o_id: 1, - data: string, - filename: 'filename.txt', - ) - - # health_check - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['error']) - assert_equal(true, result['healthy']) - assert_equal('success', result['message']) - - # status - get "/api/v1/monitoring/status?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['error']) - assert(result.key?('agents')) - assert(result.key?('last_login')) - assert(result.key?('counts')) - assert(result.key?('last_created_at')) - - if ActiveRecord::Base.connection_config[:adapter] == 'postgresql' - assert(result['storage']) - assert(result['storage'].key?('kB')) - assert(result['storage'].key?('MB')) - assert(result['storage'].key?('GB')) - else - assert_not(result['storage']) - end - - # token - post '/api/v1/monitoring/token', params: { token: @token }.to_json, headers: @headers - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['token']) - assert_equal('authentication failed', result['error']) - - end - - test '04 monitoring with admin user' do - - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('monitoring-admin@example.com', 'adminpw') - - # health_check - get '/api/v1/monitoring/health_check', params: {}, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['error']) - assert_equal(true, result['healthy']) - assert_equal('success', result['message']) - - # status - get '/api/v1/monitoring/status', params: {}, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['error']) - assert(result.key?('agents')) - assert(result.key?('last_login')) - assert(result.key?('counts')) - assert(result.key?('last_created_at')) - - # token - post '/api/v1/monitoring/token', params: { token: @token }.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['token']) - @token = result['token'] - assert_not(result['error']) - - end - - test '05 monitoring with agent user' do - - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('monitoring-agent@example.com', 'agentpw') - - # health_check - get '/api/v1/monitoring/health_check', params: {}, headers: @headers.merge('Authorization' => credentials) - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['healthy']) - assert_equal('Not authorized (user)!', result['error']) - - # status - get '/api/v1/monitoring/status', params: {}, headers: @headers.merge('Authorization' => credentials) - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['agents']) - assert_not(result['last_login']) - assert_not(result['counts']) - assert_not(result['last_created_at']) - assert_equal('Not authorized (user)!', result['error']) - - # token - post '/api/v1/monitoring/token', params: { token: @token }.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['token']) - assert_equal('Not authorized (user)!', result['error']) - - end - - test '06 monitoring with admin user and invalid permission' do - - permission = Permission.find_by(name: 'admin.monitoring') - permission.active = false - permission.save! - - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('monitoring-admin@example.com', 'adminpw') - - # health_check - get '/api/v1/monitoring/health_check', params: {}, headers: @headers.merge('Authorization' => credentials) - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['healthy']) - assert_equal('Not authorized (user)!', result['error']) - - # status - get '/api/v1/monitoring/status', params: {}, headers: @headers.merge('Authorization' => credentials) - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['agents']) - assert_not(result['last_login']) - assert_not(result['counts']) - assert_not(result['last_created_at']) - assert_equal('Not authorized (user)!', result['error']) - - # token - post '/api/v1/monitoring/token', params: { token: @token }.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['token']) - assert_equal('Not authorized (user)!', result['error']) - - permission.active = true - permission.save! - end - - test '07 monitoring with correct token and invalid permission' do - - permission = Permission.find_by(name: 'admin.monitoring') - permission.active = false - permission.save! - - # health_check - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['error']) - assert_equal(true, result['healthy']) - assert_equal('success', result['message']) - - # status - get "/api/v1/monitoring/status?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['error']) - assert(result.key?('agents')) - assert(result.key?('last_login')) - assert(result.key?('counts')) - assert(result.key?('last_created_at')) - - # token - post '/api/v1/monitoring/token', params: { token: @token }.to_json, headers: @headers - assert_response(401) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_not(result['token']) - assert_equal('authentication failed', result['error']) - - permission.active = true - permission.save! - - end - - test '08 check health false' do - - channel = Channel.find_by(active: true) - channel.status_in = 'ok' - channel.status_out = 'error' - channel.last_log_in = nil - channel.last_log_out = nil - channel.save! - - # health_check - channel - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal('Channel: Email::Notification out ', result['message']) - - # health_check - scheduler may not run - scheduler = Scheduler.where(active: true).last - scheduler.last_run = Time.zone.now - 20.minutes - scheduler.period = 600 - scheduler.save! - - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal("Channel: Email::Notification out ;scheduler may not run (last execution of #{scheduler.method} 10 minutes over) - please contact your system administrator", result['message']) - - # health_check - scheduler may not run - scheduler = Scheduler.where(active: true).last - scheduler.last_run = Time.zone.now - 1.day - scheduler.period = 600 - scheduler.save! - - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal("Channel: Email::Notification out ;scheduler may not run (last execution of #{scheduler.method} about 24 hours over) - please contact your system administrator", result['message']) - - # health_check - scheduler job count - travel 2.seconds - 8001.times do - Delayed::Job.enqueue( BackgroundJobSearchIndex.new('Ticket', 1)) - end - Scheduler.where(active: true).each do |local_scheduler| - local_scheduler.last_run = Time.zone.now - local_scheduler.save! - end - total_jobs = Delayed::Job.count - - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal('Channel: Email::Notification out ', result['message']) - - travel 20.minutes - Scheduler.where(active: true).each do |local_scheduler| - local_scheduler.last_run = Time.zone.now - local_scheduler.save! - end - - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal("Channel: Email::Notification out ;#{total_jobs} background jobs in queue", result['message']) - - Delayed::Job.delete_all - travel_back - - # health_check - unprocessable mail - dir = Rails.root.join('tmp', 'unprocessable_mail') - FileUtils.mkdir_p(dir) - FileUtils.touch("#{dir}/test.eml") - - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal('Channel: Email::Notification out ;unprocessable mails: 1', result['message']) - - # health_check - ldap - Setting.set('ldap_integration', true) - ImportJob.create( - name: 'Import::Ldap', - started_at: Time.zone.now, - finished_at: Time.zone.now, - result: { - error: 'Some bad error' - } - ) - - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal("Channel: Email::Notification out ;unprocessable mails: 1;Failed to run import backend 'Import::Ldap'. Cause: Some bad error", result['message']) - - stuck_updated_at_timestamp = 15.minutes.ago - ImportJob.create( - name: 'Import::Ldap', - started_at: Time.zone.now, - finished_at: nil, - updated_at: stuck_updated_at_timestamp, - ) - - # health_check - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal("Channel: Email::Notification out ;unprocessable mails: 1;Failed to run import backend 'Import::Ldap'. Cause: Some bad error;Stuck import backend 'Import::Ldap' detected. Last update: #{stuck_updated_at_timestamp}", result['message']) - - Setting.set('ldap_integration', false) - end - - test '09 check restart_failed_jobs' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('monitoring-admin@example.com', 'adminpw') - post '/api/v1/monitoring/restart_failed_jobs', params: {}, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - end - - test '10 check failed delayed job' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('monitoring-admin@example.com', 'adminpw') - - # disable elasticsearch - prev_es_config = Setting.get('es_url') - Setting.set('es_url', 'http://127.0.0.1:92001') - - # add a new object - object = ObjectManager::Attribute.add( - name: 'test3', - object: 'Ticket', - display: 'Test 3', - active: true, - data_type: 'input', - data_option: { - default: 'test', - type: 'text', - maxlength: 120, - null: true - }, - screens: { - create_middle: { - 'ticket.customer' => { - shown: true, - item_class: 'column' - }, - 'ticket.agent' => { - shown: true, - item_class: 'column' - } - }, - edit: { - 'ticket.customer' => { - shown: true - }, - 'ticket.agent' => { - shown: true - } - } - }, - position: 1550, - editable: true - ) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - post "/api/v1/object_manager_attributes/#{object.id}", params: {}, headers: @headers - token = @response.headers['CSRF-TOKEN'] - - # parameters for updating - params = { - 'name': 'test4', - 'object': 'Ticket', - 'display': 'Test 4', - 'active': true, - 'data_type': 'input', - 'data_option': { - 'default': 'test', - 'type': 'text', - 'maxlength': 120 - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - }, - 'id': 'c-196' - } - - # update the object - put "/api/v1/object_manager_attributes/#{object.id}", params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - assert_response(200) - result = JSON.parse(@response.body) - assert(result) - assert(result['data_option']['null']) - assert_equal(result['name'], 'test4') - assert_equal(result['display'], 'Test 4') - - jobs = Delayed::Job.all - - 4.times do - jobs.each do |job| - Delayed::Worker.new.run(job) - end - end - - # health_check - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal("Failed to run background job #1 'BackgroundJobSearchIndex' 1 time(s) with 4 attempt(s).", result['message']) - - # add another job - manual_added = Delayed::Job.enqueue( BackgroundJobSearchIndex.new('Ticket', 1)) - manual_added.update!(attempts: 10) - - # health_check - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal("Failed to run background job #1 'BackgroundJobSearchIndex' 2 time(s) with 14 attempt(s).", result['message']) - - # add another job - dummy_class = Class.new do - - def perform - puts 'work work' - end - end - - manual_added = Delayed::Job.enqueue( dummy_class.new ) - manual_added.update!(attempts: 5) - - # health_check - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal("Failed to run background job #1 'BackgroundJobSearchIndex' 2 time(s) with 14 attempt(s).;Failed to run background job #2 'Object' 1 time(s) with 5 attempt(s).", result['message']) - - # reset settings - Setting.set('es_url', prev_es_config) - - # add some more failing job - 10.times do - manual_added = Delayed::Job.enqueue( dummy_class.new ) - manual_added.update!(attempts: 5) - end - - # health_check - get "/api/v1/monitoring/health_check?token=#{@token}", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert(result['message']) - assert(result['issues']) - assert_equal(false, result['healthy']) - assert_equal("13 failing background jobs;Failed to run background job #1 'Object' 8 time(s) with 40 attempt(s).;Failed to run background job #2 'BackgroundJobSearchIndex' 2 time(s) with 14 attempt(s).", result['message']) - - # cleanup - Delayed::Job.delete_all - end - - test '11 check amount' do - Ticket.destroy_all - - # amount_check - ok - get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('ok', result['state']) - assert_equal('', result['message']) - assert_equal(0, result['count']) - - Ticket.destroy_all - (1..6).each do |i| - Ticket.create!( - title: "Ticket-#{i}", - group: Group.lookup(name: 'Users'), - customer_id: 1, - state: Ticket::State.lookup(name: 'new'), - priority: Ticket::Priority.lookup(name: '2 normal'), - updated_by_id: 1, - created_by_id: 1, - ) - travel 10.seconds - end - - get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&min_warning=10&min_critical=8", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('critical', result['state']) - assert_equal('The minimum of 8 was undercut by 6 in the last 1h', result['message']) - assert_equal(6, result['count']) - - get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&min_warning=7&min_critical=2", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('warning', result['state']) - assert_equal('The minimum of 7 was undercut by 6 in the last 1h', result['message']) - assert_equal(6, result['count']) - - get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&max_warning=10&max_critical=20", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('ok', result['state']) - assert_equal('', result['message']) - assert_equal(6, result['count']) - - (1..6).each do |i| - Ticket.create!( - title: "Ticket-#{i}", - group: Group.lookup(name: 'Users'), - customer_id: 1, - state: Ticket::State.lookup(name: 'new'), - priority: Ticket::Priority.lookup(name: '2 normal'), - updated_by_id: 1, - created_by_id: 1, - ) - travel 1.second - end - - get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&max_warning=10&max_critical=20", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('warning', result['state']) - assert_equal('The limit of 10 was exceeded with 12 in the last 1h', result['message']) - assert_equal(12, result['count']) - - (1..10).each do |i| - Ticket.create!( - title: "Ticket-#{i}", - group: Group.lookup(name: 'Users'), - customer_id: 1, - state: Ticket::State.lookup(name: 'new'), - priority: Ticket::Priority.lookup(name: '2 normal'), - updated_by_id: 1, - created_by_id: 1, - ) - travel 1.second - end - - get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h&max_warning=10&max_critical=20", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('critical', result['state']) - assert_equal('The limit of 20 was exceeded with 22 in the last 1h', result['message']) - assert_equal(22, result['count']) - - get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('ok', result['state']) - assert_equal('', result['message']) - assert_equal(22, result['count']) - - travel 2.hours - - get "/api/v1/monitoring/amount_check?token=#{@token}&periode=1h", params: {}, headers: @headers - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('ok', result['state']) - assert_equal('', result['message']) - assert_equal(0, result['count']) - - end - -end diff --git a/test/integration/object_manager_attributes_controller_test.rb b/test/integration/object_manager_attributes_controller_test.rb deleted file mode 100644 index 799b31ea8..000000000 --- a/test/integration/object_manager_attributes_controller_test.rb +++ /dev/null @@ -1,1151 +0,0 @@ -require 'integration_test_helper' -require 'rake' - -class ObjectManagerAttributesControllerTest < ActionDispatch::IntegrationTest - - setup do - - # set accept header - @headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' } - - roles = Role.where(name: %w[Admin Agent]) - groups = Group.all - - UserInfo.current_user_id = 1 - @admin = User.create_or_update( - login: 'tickets-admin', - firstname: 'Tickets', - lastname: 'Admin', - email: 'tickets-admin@example.com', - password: 'adminpw', - active: true, - roles: roles, - groups: groups, - ) - - end - - test 'add new ticket text object' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin', 'adminpw') - - post '/api/v1/object_manager_attributes', params: {}, headers: @headers - token = @response.headers['CSRF-TOKEN'] - - # token based on headers - params = { - 'name': 'test1', - 'object': 'Ticket', - 'display': 'Test 1', - 'active': true, - 'data_type': 'input', - 'data_option': { - 'default': 'test', - 'type': 'text', - 'maxlength': 120 - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - }, - 'id': 'c-196' - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - result = JSON.parse(@response.body) - assert(result) - assert(result['data_option']['null']) - assert_equal(result['data_option']['null'], true) - assert_equal(result['name'], 'test1') - end - - test 'add new ticket text object - no default' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin', 'adminpw') - - post '/api/v1/object_manager_attributes', params: {}, headers: @headers - token = @response.headers['CSRF-TOKEN'] - - # token based on headers - params = { - 'name': 'test2', - 'object': 'Ticket', - 'display': 'Test 2', - 'active': true, - 'data_type': 'input', - 'data_option': { - 'type': 'text', - 'maxlength': 120 - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - }, - 'id': 'c-196' - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - result = JSON.parse(@response.body) - assert(result) - assert(result['data_option']['null']) - assert_equal(result['data_option']['null'], true) - assert_equal(result['name'], 'test2') - end - - test 'update ticket text object' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin', 'adminpw') - - # add a new object - object = ObjectManager::Attribute.add( - name: 'test3', - object: 'Ticket', - display: 'Test 3', - active: true, - data_type: 'input', - data_option: { - default: 'test', - type: 'text', - maxlength: 120, - null: true - }, - screens: { - create_middle: { - 'ticket.customer' => { - shown: true, - item_class: 'column' - }, - 'ticket.agent' => { - shown: true, - item_class: 'column' - } - }, - edit: { - 'ticket.customer' => { - shown: true - }, - 'ticket.agent' => { - shown: true - } - } - }, - position: 1550, - editable: true - ) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - post "/api/v1/object_manager_attributes/#{object.id}", params: {}, headers: @headers - token = @response.headers['CSRF-TOKEN'] - - # parameters for updating - params = { - 'name': 'test4', - 'object': 'Ticket', - 'display': 'Test 4', - 'active': true, - 'data_type': 'input', - 'data_option': { - 'default': 'test', - 'type': 'text', - 'maxlength': 120 - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - }, - 'id': 'c-196' - } - - # update the object - put "/api/v1/object_manager_attributes/#{object.id}", params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - assert(result) - assert(result['data_option']['null']) - assert_equal(result['name'], 'test4') - assert_equal(result['display'], 'Test 4') - end - - test 'add new ticket boolean object' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin', 'adminpw') - - post '/api/v1/object_manager_attributes', params: {}, headers: @headers - token = @response.headers['CSRF-TOKEN'] - - # token based on headers - params = { - 'active': true, - 'data_option': { - 'options': { - 'false': 'no', - 'true': 'yes' - } - }, - 'data_type': 'boolean', - 'display': 'Boolean 2', - 'id': 'c-200', - 'name': 'bool2', - 'object': 'Ticket', - 'screens': { - 'create_middle': { - 'ticket.agent' => { - 'item_class': 'column', - 'shown': true - }, - 'ticket.customer' => { - 'item_class': 'column', - 'shown': true - } - }, - 'edit': { - 'ticket.agent' => { - 'shown': true - }, - 'ticket.customer' => { - 'shown': true - } - } - } - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - result = JSON.parse(@response.body) - assert(result) - assert(result['data_option']['null']) - assert_equal(result['data_option']['null'], true) - assert_equal(result['name'], 'bool2') - end - - test 'add new user select object' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin', 'adminpw') - - post '/api/v1/object_manager_attributes', params: {}, headers: @headers - token = @response.headers['CSRF-TOKEN'] - - # token based on headers - params = { - 'active': true, - 'data_option': { - 'options': { - 'key1': 'foo' - } - }, - 'data_type': 'select', - 'display': 'Test 5', - 'id': 'c-204', - 'name': 'test5', - 'object': 'User', - 'screens': { - 'create': { - 'admin.user' => { - 'shown': true - }, - 'ticket.agent' => { - 'shown': true - }, - 'ticket.customer' => { - 'shown': true - } - }, - 'edit': { - 'admin.user' => { - 'shown': true - }, - 'ticket.agent' => { - 'shown': true - } - }, - 'view': { - 'admin.user' => { - 'shown': true - }, - 'ticket.agent' => { - 'shown': true - }, - 'ticket.customer' => { - 'shown': true - } - } - } - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - result = JSON.parse(@response.body) - assert(result) - assert(result['data_option']['null']) - assert_equal(result['data_option']['null'], true) - assert_equal(result['name'], 'test5') - end - - test 'update user select object' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin', 'adminpw') - - # add a new object - object = ObjectManager::Attribute.add( - active: true, - data_option: { - options: { - key1: 'foo' - }, - null: true, - default: '', - }, - data_type: 'select', - display: 'Test 6', - id: 'c-204', - name: 'test6', - object: 'User', - screens: { - create: { - 'admin.user' => { - shown: true - }, - 'ticket.agent' => { - shown: true - }, - 'ticket.customer' => { - shown: true - } - }, - edit: { - 'admin.user' => { - shown: true - }, - 'ticket.agent' => { - shown: true - } - }, - view: { - 'admin.user' => { - shown: true - }, - 'ticket.agent' => { - shown: true - }, - 'ticket.customer' => { - shown: true - } - } - }, - position: 1550, - editable: true - ) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - post "/api/v1/object_manager_attributes/#{object.id}", params: {}, headers: @headers - token = @response.headers['CSRF-TOKEN'] - - # parameters for updating - params = { - active: true, - data_option: { - options: { - key1: 'foo', - key2: 'bar' - } - }, - data_type: 'select', - display: 'Test 7', - id: 'c-204', - name: 'test7', - object: 'User', - screens: { - create: { - 'admin.user' => { - shown: true - }, - 'ticket.agent' => { - shown: true - }, - 'ticket.customer' => { - shown: true - } - }, - edit: { - 'admin.user' => { - shown: true - }, - 'ticket.agent' => { - shown: true - } - }, - view: { - 'admin.user' => { - shown: true - }, - 'ticket.agent' => { - shown: true - }, - 'ticket.customer' => { - shown: true - } - } - } - } - - # update the object - put "/api/v1/object_manager_attributes/#{object.id}", params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - assert(result) - assert(result['data_option']['options']) - assert_equal(result['name'], 'test7') - assert_equal(result['display'], 'Test 7') - end - - test '01 converts string to boolean for default value for boolean data type with true' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw') - - params = { - 'name': "customerdescription#{rand(999_999_999)}", - 'object': 'Ticket', - 'display': "custom description#{rand(999_999_999)}", - 'active': true, - 'data_type': 'boolean', - 'data_option': { - 'options': { - 'true': '', - 'false': '', - }, - 'default': 'true', - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - } - }, - 'id': 'c-201' - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - assert_response(201) # created - result = JSON.parse(@response.body) - - assert(result) - assert(result['data_option']['default']) - assert_equal(result['data_option']['default'], true) - assert_equal(result['data_type'], 'boolean') - end - - test '02 converts string to boolean for default value for boolean data type with false' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw') - - params = { - 'name': "customerdescription_#{rand(999_999_999)}", - 'object': 'Ticket', - 'display': "custom description #{rand(999_999_999)}", - 'active': true, - 'data_type': 'boolean', - 'data_option': { - 'options': { - 'true': '', - 'false': '', - }, - 'default': 'false', - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - } - }, - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - assert_response(201) # created - result = JSON.parse(@response.body) - - assert(result) - assert_not(result['data_option']['default']) - assert_equal(result['data_option']['default'], false) - assert_equal(result['data_type'], 'boolean') - end - - test '03 ticket attributes cannot be removed when it is referenced by an overview' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw') - - # 1. create a new ticket attribute and execute migration - migration = ObjectManager::Attribute.migration_execute - - params = { - 'name': 'test_attribute_referenced_by_an_overview', - 'object': 'Ticket', - 'display': 'Test Attribute', - 'active': true, - 'data_type': 'input', - 'data_option': { - 'default': '', - 'type': 'text', - 'maxlength': 120, - 'null': true, - 'options': {}, - 'relation': '' - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - }, - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - # 2. create an overview that uses the attribute - params = { - name: 'test_overview', - roles: Role.where(name: 'Agent').pluck(:name), - condition: { - 'ticket.state_id': { - 'operator': 'is', - 'value': Ticket::State.all.pluck(:id), - }, - 'ticket.test_attribute_referenced_by_an_overview': { - 'operator': 'contains', - 'value': 'DUMMY' - }, - }, - order: { - by: 'created_at', - direction: 'DESC', - }, - view: { - d: %w[title customer state created_at], - s: %w[number title customer state created_at], - m: %w[number title customer state created_at], - view_mode_default: 's', - }, - user_ids: [ '1' ], - } - - if Overview.where('name like ?', '%test%').empty? - post '/api/v1/overviews', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('test_overview', result['name']) - end - - # 3. attempt to delete the ticket attribute - get '/api/v1/object_manager_attributes', headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - target_attribute = result.select { |x| x['name'] == 'test_attribute_referenced_by_an_overview' && x['object'] == 'Ticket' } - assert_equal target_attribute.size, 1 - target_id = target_attribute[0]['id'] - - delete "/api/v1/object_manager_attributes/#{target_id}", headers: @headers.merge('Authorization' => credentials) - assert_response(422) - assert @response.body.include?('Overview') - assert @response.body.include?('test_overview') - assert @response.body.include?('cannot be deleted!') - end - - test '04 ticket attributes cannot be removed when it is referenced by a trigger' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw') - - # 1. create a new ticket attribute and execute migration - migration = ObjectManager::Attribute.migration_execute - - params = { - 'name': 'test_attribute_referenced_by_a_trigger', - 'object': 'Ticket', - 'display': 'Test Attribute', - 'active': true, - 'data_type': 'input', - 'data_option': { - 'default': '', - 'type': 'text', - 'maxlength': 120, - 'null': true, - 'options': {}, - 'relation': '' - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - }, - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - # 2. create an trigger that uses the attribute - params = { - name: 'test_trigger', - condition: { - 'ticket.test_attribute_referenced_by_a_trigger': { - 'operator': 'contains', - 'value': 'DUMMY' - } - }, - 'perform': { - 'ticket.state_id': { - 'value': '2' - } - }, - 'active': true, - 'id': 'c-3' - } - - if Trigger.where('name like ?', '%test%').empty? - post '/api/v1/triggers', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('test_trigger', result['name']) - end - - # 3. attempt to delete the ticket attribute - get '/api/v1/object_manager_attributes', headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - target_attribute = result.select { |x| x['name'] == 'test_attribute_referenced_by_a_trigger' && x['object'] == 'Ticket' } - assert_equal target_attribute.size, 1 - target_id = target_attribute[0]['id'] - - delete "/api/v1/object_manager_attributes/#{target_id}", headers: @headers.merge('Authorization' => credentials) - assert_response(422) - assert @response.body.include?('Trigger') - assert @response.body.include?('test_trigger') - assert @response.body.include?('cannot be deleted!') - end - - test '05 ticket attributes cannot be removed when it is referenced by a scheduler' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw') - - # 1. create a new ticket attribute and execute migration - migration = ObjectManager::Attribute.migration_execute - - params = { - 'name': 'test_attribute_referenced_by_a_scheduler', - 'object': 'Ticket', - 'display': 'Test Attribute', - 'active': true, - 'data_type': 'input', - 'data_option': { - 'default': '', - 'type': 'text', - 'maxlength': 120, - 'null': true, - 'options': {}, - 'relation': '' - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - }, - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - # 2. create a scheduler that uses the attribute - params = { - name: 'test_scheduler', - 'timeplan': { - 'days': { - 'Mon': true, - 'Tue': false, - 'Wed': false, - 'Thu': false, - 'Fri': false, - 'Sat': false, - 'Sun': false - }, - 'hours': { - '0': true, - '1': false, - '2': false, - '3': false, - '4': false, - '5': false, - '6': false, - '7': false, - '8': false, - '9': false, - '10': false, - '11': false, - '12': false, - '13': false, - '14': false, - '15': false, - '16': false, - '17': false, - '18': false, - '19': false, - '20': false, - '21': false, - '22': false, - '23': false - }, - 'minutes': { - '0': true, - '10': false, - '20': false, - '30': false, - '40': false, - '50': false - } - }, - 'condition': { - 'ticket.test_attribute_referenced_by_a_scheduler': { - 'operator': 'contains', - 'value': 'DUMMY' - } - }, - 'perform': { - 'ticket.state_id': { - 'value': '2' - } - }, - 'disable_notification': true, - 'note': '', - 'active': true, - 'id': 'c-0' - } - - if Job.where('name like ?', '%test%').empty? - post '/api/v1/jobs', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('test_scheduler', result['name']) - end - - # 3. attempt to delete the ticket attribute - get '/api/v1/object_manager_attributes', headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - target_attribute = result.select { |x| x['name'] == 'test_attribute_referenced_by_a_scheduler' && x['object'] == 'Ticket' } - assert_equal target_attribute.size, 1 - target_id = target_attribute[0]['id'] - - delete "/api/v1/object_manager_attributes/#{target_id}", headers: @headers.merge('Authorization' => credentials) - assert_response(422) - assert @response.body.include?('Job') - assert @response.body.include?('test_scheduler') - assert @response.body.include?('cannot be deleted!') - end - - test '06 ticket attributes can be removed when it is referenced by an overview but by user object' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw') - - # 1. create a new ticket attribute and execute migration - migration = ObjectManager::Attribute.migration_execute - - params = { - 'name': 'test_attribute_referenced_by_an_overview', - 'object': 'Ticket', - 'display': 'Test Attribute', - 'active': true, - 'data_type': 'input', - 'data_option': { - 'default': '', - 'type': 'text', - 'maxlength': 120, - 'null': true, - 'options': {}, - 'relation': '' - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - }, - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - params = { - 'name': 'test_attribute_referenced_by_an_overview', - 'object': 'User', - 'display': 'Test Attribute', - 'active': true, - 'data_type': 'input', - 'data_option': { - 'default': '', - 'type': 'text', - 'maxlength': 120, - 'null': true, - 'options': {}, - 'relation': '' - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - }, - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - # 2. create an overview that uses the attribute - params = { - name: 'test_overview', - roles: Role.where(name: 'Agent').pluck(:name), - condition: { - 'ticket.state_id': { - 'operator': 'is', - 'value': Ticket::State.all.pluck(:id), - }, - 'ticket.test_attribute_referenced_by_an_overview': { - 'operator': 'contains', - 'value': 'DUMMY' - }, - }, - order: { - by: 'created_at', - direction: 'DESC', - }, - view: { - d: %w[title customer state created_at], - s: %w[number title customer state created_at], - m: %w[number title customer state created_at], - view_mode_default: 's', - }, - user_ids: [ '1' ], - } - - if Overview.where('name like ?', '%test%').empty? - post '/api/v1/overviews', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_equal('test_overview', result['name']) - end - - # 3. attempt to delete the ticket attribute - get '/api/v1/object_manager_attributes', headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - - target_attribute = result.select { |x| x['name'] == 'test_attribute_referenced_by_an_overview' && x['object'] == 'User' } - assert_equal target_attribute.size, 1 - target_id = target_attribute[0]['id'] - - delete "/api/v1/object_manager_attributes/#{target_id}", headers: @headers.merge('Authorization' => credentials) - assert_response(200) - - target_attribute = result.select { |x| x['name'] == 'test_attribute_referenced_by_an_overview' && x['object'] == 'Ticket' } - assert_equal target_attribute.size, 1 - target_id = target_attribute[0]['id'] - - delete "/api/v1/object_manager_attributes/#{target_id}", headers: @headers.merge('Authorization' => credentials) - assert_response(422) - assert @response.body.include?('Overview') - assert @response.body.include?('test_overview') - assert @response.body.include?('cannot be deleted!') - end - - test '07 verify if attribute type can not be changed' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw') - - params = { - 'name': "customerdescription_#{rand(999_999_999)}", - 'object': 'Ticket', - 'display': "custom description #{rand(999_999_999)}", - 'active': true, - 'data_type': 'boolean', - 'data_option': { - 'options': { - 'true': '', - 'false': '', - }, - 'default': 'false', - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - } - } - }, - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - assert_response(201) # created - result = JSON.parse(@response.body) - - assert(result) - assert_not(result['data_option']['default']) - assert_equal(result['data_option']['default'], false) - assert_equal(result['data_type'], 'boolean') - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - params['data_type'] = 'input' - params['data_option'] = { - 'default': 'test', - 'type': 'text', - 'maxlength': 120 - } - - put "/api/v1/object_manager_attributes/#{result['id']}", params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(422) - result = JSON.parse(@response.body) - assert(result) - assert(result['error']) - - end - - test '08 verify if attribute type can be changed' do - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw') - - params = { - 'name': "customerdescription_#{rand(999_999_999)}", - 'object': 'Ticket', - 'display': "custom description #{rand(999_999_999)}", - 'active': true, - 'data_type': 'input', - 'data_option': { - 'default': 'test', - 'type': 'text', - 'maxlength': 120, - }, - 'screens': { - 'create_middle': { - 'ticket.customer': { - 'shown': true, - 'item_class': 'column' - }, - 'ticket.agent': { - 'shown': true, - 'item_class': 'column' - } - }, - 'edit': { - 'ticket.customer': { - 'shown': true - }, - 'ticket.agent': { - 'shown': true - } - }, - }, - } - - post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - assert_response(201) # created - result = JSON.parse(@response.body) - - assert(result) - assert_equal(result['data_option']['default'], 'test') - assert_equal(result['data_type'], 'input') - - migration = ObjectManager::Attribute.migration_execute - assert_equal(migration, true) - - params['data_type'] = 'select' - params['data_option'] = { - 'default': 'fuu', - 'options': { - 'key1': 'foo', - 'key2': 'fuu', - } - } - - put "/api/v1/object_manager_attributes/#{result['id']}", params: params.to_json, headers: @headers.merge('Authorization' => credentials) - - assert_response(200) - result = JSON.parse(@response.body) - assert(result) - assert_equal(result['data_option']['default'], 'test') - assert_equal(result['data_option_new']['default'], 'fuu') - assert_equal(result['data_type'], 'select') - - end - -end diff --git a/test/integration/telegram_controller_test.rb b/test/integration/telegram_controller_test.rb deleted file mode 100644 index 10c4ab7cc..000000000 --- a/test/integration/telegram_controller_test.rb +++ /dev/null @@ -1,373 +0,0 @@ -require 'test_helper' -require 'rexml/document' -require 'webmock/minitest' - -class TelegramControllerTest < ActionDispatch::IntegrationTest - setup do - @headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' } - end - - test 'basic call' do - Ticket.destroy_all - - # configure telegram channel - token = 'valid_token' - bot_id = 123_456_789 - group_id = Group.find_by(name: 'Users').id - - UserInfo.current_user_id = 1 - Channel.where(area: 'Telegram::Bot').destroy_all - - # try with invalid token - stub_request(:post, 'https://api.telegram.org/botnot_existing/getMe') - .to_return(status: 404, body: '{"ok":false,"error_code":404,"description":"Not Found"}', headers: {}) - - assert_raises(RuntimeError) do - Telegram.check_token('not_existing') - end - - # try valid token - stub_request(:post, "https://api.telegram.org/bot#{token}/getMe") - .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {}) - - bot = Telegram.check_token(token) - assert_equal(bot_id, bot['id']) - - stub_request(:post, "https://api.telegram.org/bot#{token}/getMe") - .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {}) - - Setting.set('http_type', 'http') - assert_raises(RuntimeError) do - Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!' }) - end - - # try invalid port - stub_request(:post, "https://api.telegram.org:443/bot#{token}/getMe") - .to_return(status: 200, body: "{\"ok\":true,\"result\":{\"id\":#{bot_id},\"first_name\":\"Chrispresso Customer Service\",\"username\":\"ChrispressoBot\"}}", headers: {}) - stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook") - .with(body: { 'url' => "https://somehost.example.com:12345/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" }) - .to_return(status: 400, body: '{"ok":false,"error_code":400,"description":"Bad Request: bad webhook: Webhook can be set up only on ports 80, 88, 443 or 8443"}', headers: {}) - - Setting.set('http_type', 'https') - Setting.set('fqdn', 'somehost.example.com:12345') - assert_raises(RuntimeError) do - Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!' }) - end - - # try invalid host - stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook") - .with(body: { 'url' => "https://somehost.example.com/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" }) - .to_return(status: 400, body: '{"ok":false,"error_code":400,"description":"Bad Request: bad webhook: getaddrinfo: Name or service not known"}', headers: {}) - - Setting.set('fqdn', 'somehost.example.com') - assert_raises(RuntimeError) do - Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!' }) - end - - # valid token, host and port - stub_request(:post, "https://api.telegram.org:443/bot#{token}/setWebhook") - .with(body: { 'url' => "https://example.com/api/v1/channels_telegram_webhook/callback_token?bid=#{bot_id}" }) - .to_return(status: 200, body: '{"ok":true,"result":true,"description":"Webhook was set"}', headers: {}) - - Setting.set('fqdn', 'example.com') - channel = Telegram.create_or_update_channel(token, { group_id: group_id, welcome: 'hi!' }) - UserInfo.current_user_id = nil - - # start communication #1 - post '/api/v1/channels/telegram_webhook', params: read_messaage('personal1_message_start'), headers: @headers - assert_response(404) - result = JSON.parse(@response.body) - - post '/api/v1/channels_telegram_webhook/not_existing', params: read_messaage('personal1_message_start'), headers: @headers - assert_response(422) - result = JSON.parse(@response.body) - assert_equal('bot param missing', result['error']) - - callback_url = "/api/v1/channels_telegram_webhook/not_existing?bid=#{channel.options[:bot][:id]}" - post callback_url, params: read_messaage('personal1_message_start'), headers: @headers - assert_response(422) - result = JSON.parse(@response.body) - assert_equal('invalid callback token', result['error']) - - callback_url = "/api/v1/channels_telegram_webhook/#{channel.options[:callback_token]}?bid=#{channel.options[:bot][:id]}" - post callback_url, params: read_messaage('personal1_message_start'), headers: @headers - assert_response(200) - - # send message1 - post callback_url, params: read_messaage('personal1_message_content1'), headers: @headers - assert_response(200) - assert_equal(1, Ticket.count) - ticket = Ticket.last - assert_equal('Hello, I need your Help', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(1, ticket.articles.count) - assert_equal('Hello, I need your Help', ticket.articles.first.body) - assert_equal('text/plain', ticket.articles.first.content_type) - - # send channel message1 - post callback_url, params: read_messaage('channel1_message_content1'), headers: @headers - assert_response(200) - assert_equal(1, Ticket.count) - ticket = Ticket.last - assert_equal('Hello, I need your Help', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(1, ticket.articles.count) - assert_equal('Hello, I need your Help', ticket.articles.first.body) - assert_equal('text/plain', ticket.articles.first.content_type) - - # edit channel message1 - post callback_url, params: read_messaage('channel2_message_content1'), headers: @headers - assert_response(200) - assert_equal(1, Ticket.count) - ticket = Ticket.last - assert_equal('Hello, I need your Help', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(1, ticket.articles.count) - assert_equal('Hello, I need your Help', ticket.articles.first.body) - assert_equal('text/plain', ticket.articles.first.content_type) - - # send same message again, ignore it - post callback_url, params: read_messaage('personal1_message_content1'), headers: @headers - assert_response(200) - ticket = Ticket.last - assert_equal('Hello, I need your Help', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(1, ticket.articles.count) - assert_equal('Hello, I need your Help', ticket.articles.first.body) - assert_equal('text/plain', ticket.articles.first.content_type) - - # send message2 - post callback_url, params: read_messaage('personal1_message_content2'), headers: @headers - assert_response(200) - ticket = Ticket.last - assert_equal('Hello, I need your Help', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(2, ticket.articles.count) - assert_equal('Hello, I need your Help 2', ticket.articles.last.body) - assert_equal('text/plain', ticket.articles.last.content_type) - - # send end message - post callback_url, params: read_messaage('personal1_message_end'), headers: @headers - assert_response(200) - ticket = Ticket.last - assert_equal('Hello, I need your Help', ticket.title) - assert_equal('closed', ticket.state.name) - assert_equal(2, ticket.articles.count) - assert_equal('Hello, I need your Help 2', ticket.articles.last.body) - assert_equal('text/plain', ticket.articles.last.content_type) - - # start communication #2 - post callback_url, params: read_messaage('personal2_message_start'), headers: @headers - assert_response(200) - - # send message1 - post callback_url, params: read_messaage('personal2_message_content1'), headers: @headers - assert_response(200) - assert_equal(2, Ticket.count) - ticket = Ticket.last - assert_equal('Can you help me with my feature?', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(1, ticket.articles.count) - assert_equal('Can you help me with my feature?', ticket.articles.first.body) - assert_equal('text/plain', ticket.articles.first.content_type) - - # send message2 - post callback_url, params: read_messaage('personal2_message_content2'), headers: @headers - assert_response(200) - assert_equal(2, Ticket.count) - ticket = Ticket.last - assert_equal('Can you help me with my feature?', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(2, ticket.articles.count) - assert_equal('Yes of course! lalal', ticket.articles.last.body) - assert_equal('text/plain', ticket.articles.last.content_type) - - # start communication #3 - post callback_url, params: read_messaage('personal3_message_start'), headers: @headers - assert_response(200) - - # send message1 - post callback_url, params: read_messaage('personal3_message_content1'), headers: @headers - assert_response(200) - assert_equal(3, Ticket.count) - ticket = Ticket.last - assert_equal('Can you help me with my feature?', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(1, ticket.articles.count) - assert_equal('Can you help me with my feature?', ticket.articles.last.body) - assert_equal('text/plain', ticket.articles.last.content_type) - - # send message2 - stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") - .with(body: { 'file_id' => 'ABC-123VabcOcv123w0ABHywrcPqfrbAYIABC' }) - .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123VabcOcv123w0ABHywrcPqfrbAYIABC","file_path":"abc123"}}', headers: {}) - stub_request(:get, "https://api.telegram.org/file/bot#{token}/abc123") - .to_return(status: 200, body: 'ABC1', headers: {}) - - post callback_url, params: read_messaage('personal3_message_content2'), headers: @headers - assert_response(200) - assert_equal(3, Ticket.count) - ticket = Ticket.last - assert_equal('Can you help me with my feature?', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(2, ticket.articles.count) - assert_match(/ 'AAQCABO0I4INAATATQAB5HWPq4XgxQACAg' }) - .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123AAQCABO0I4INAATATQAB5HWPq4XgxQACAg","file_path":"abc123"}}', headers: {}) - stub_request(:get, "https://api.telegram.org/file/bot#{token}/abc123") - .to_return(status: 200, body: 'ABC2', headers: {}) - stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") - .with(body: { 'file_id' => 'BQADAgADDgAD7x6ZSC_-1LMkOEmoAg' }) - .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123BQADAgADDgAD7x6ZSC_-1LMkOEmoAg","file_path":"abc123"}}', headers: {}) - - post callback_url, params: read_messaage('personal3_message_content3'), headers: @headers - assert_response(200) - assert_equal(3, Ticket.count) - ticket = Ticket.last - assert_equal('Can you help me with my feature?', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(3, ticket.articles.count) - assert_match(/ 'AwADAgADVQADCEIYSZwyOmSZK9iZAg' }) - .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123AwADAgADVQADCEIYSZwyOmSZK9iZAg","file_path":"abc123"}}', headers: {}) - - post callback_url, params: read_messaage('personal3_message_content5'), headers: @headers - assert_response(200) - assert_equal(3, Ticket.count) - ticket = Ticket.last - assert_equal('Can you help me with my feature?', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(4, ticket.articles.count) - assert_equal('text/html', ticket.articles.last.content_type) - assert_equal(1, ticket.articles.last.attachments.count) - - # send channel message 4 with voice - post callback_url, params: read_messaage('channel1_message_content4'), headers: @headers - assert_response(200) - assert_equal(3, Ticket.count) - ticket = Ticket.last - assert_equal('Can you help me with my feature?', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(4, ticket.articles.count) - assert_equal('text/html', ticket.articles.last.content_type) - assert_equal(1, ticket.articles.last.attachments.count) - - # start communication #4 - with sticker - stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") - .with(body: { 'file_id' => 'AAQDABO3-e4qAASs6ZOjJUT7tQ4lAAIC' }) - .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123AAQDABO3-e4qAASs6ZOjJUT7tQ4lAAIC","file_path":"abc123"}}', headers: {}) - stub_request(:post, "https://api.telegram.org/bot#{token}/getFile") - .with(body: { 'file_id' => 'BQADAwAD0QIAAqbJWAAB8OkQqgtDQe0C' }) - .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123BQADAwAD0QIAAqbJWAAB8OkQqgtDQe0C","file_path":"abc123"}}', headers: {}) - - post callback_url, params: read_messaage('personal4_message_content1'), headers: @headers - assert_response(200) - assert_equal(4, Ticket.count) - ticket = Ticket.last - if Rails.application.config.db_4bytes_utf8 - assert_equal('💻', ticket.title) - else - assert_equal('', ticket.title) - end - assert_equal('new', ticket.state.name) - assert_equal(1, ticket.articles.count) - assert_match(/ 'AgADAgADwacxGxk5MUmim45lijOwsKk1Sw0ABNQoaI8BwR_z_2MFAAEC' }) - .to_return(status: 200, body: '{"result":{"file_size":123,"file_id":"ABC-123AgADAgADwacxGxk5MUmim45lijOwsKk1Sw0ABNQoaI8BwR_z_2MFAAEC","file_path":"abc123"}}', headers: {}) - - post callback_url, params: read_messaage('personal5_message_content1'), headers: @headers - assert_response(200) - assert_equal(5, Ticket.count) - ticket = Ticket.last - assert_equal('-', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(1, ticket.articles.count) - assert_match(/ 'application/json', 'CONTENT_TYPE' => 'application/json' } - end - - test 'basic call' do - - # configure twilio channel - bot_id = 123_456_789 - group_id = Group.find_by(name: 'Users').id - - UserInfo.current_user_id = 1 - channel = Channel.create!( - area: 'Sms::Account', - options: { - adapter: 'sms/twilio', - webhook_token: 'f409460e50f76d331fdac8ba7b7963b6', - account_id: '111', - token: '223', - sender: '333', - }, - group_id: nil, - active: true, - ) - - # create agent - agent = User.create!( - login: 'tickets-agent@example.com', - firstname: 'Tickets', - lastname: 'Agent', - email: 'tickets-agent@example.com', - password: 'agentpw', - active: true, - roles: Role.where(name: 'Agent'), - groups: Group.all, - ) - - # process inbound sms - post '/api/v1/sms_webhook', params: read_messaage('inbound_sms1'), headers: @headers - assert_response(404) - result = JSON.parse(@response.body) - - post '/api/v1/sms_webhook/not_existing', params: read_messaage('inbound_sms1'), headers: @headers - assert_response(404) - result = JSON.parse(@response.body) - - post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_messaage('inbound_sms1'), headers: @headers - assert_response(422) - result = JSON.parse(@response.body) - assert_equal(result['error'], 'Can\'t use Channel::Driver::Sms::Twilio: #') - - channel.group_id = Group.first.id - channel.save! - - post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_messaage('inbound_sms1'), headers: @headers - assert_response(200) - response = REXML::Document.new(@response.body) - assert_equal(response.elements.count, 1) - - ticket = Ticket.last - article = Ticket::Article.last - customer = User.last - assert_equal(1, ticket.articles.count) - assert_equal('Ldfhxhcuffufuf. Fifififig. Fifififiif F...', ticket.title) - assert_equal('new', ticket.state.name) - assert_equal(group_id, ticket.group_id) - assert_equal(customer.id, ticket.customer_id) - assert_equal(customer.id, ticket.created_by_id) - assert_equal('+491710000000', article.from) - assert_equal('+4915700000000', article.to) - assert_nil(article.cc) - assert_nil(article.subject) - assert_equal('Ldfhxhcuffufuf. Fifififig. Fifififiif Fifififiif Fifififiif Fifififiif Fifififiif', article.body) - assert_equal(customer.id, article.created_by_id) - assert_equal('Customer', article.sender.name) - assert_equal('sms', article.type.name) - - post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_messaage('inbound_sms2'), headers: @headers - assert_response(200) - response = REXML::Document.new(@response.body) - assert_equal(response.elements.count, 1) - - ticket.reload - assert_equal(2, ticket.articles.count) - assert_equal('new', ticket.state.name) - - article = Ticket::Article.last - assert_equal('+491710000000', article.from) - assert_equal('+4915700000000', article.to) - assert_nil(article.cc) - assert_nil(article.subject) - assert_equal('Follow up', article.body) - assert_equal('Customer', article.sender.name) - assert_equal('sms', article.type.name) - assert_equal(customer.id, article.created_by_id) - - # check duplicate callbacks - post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_messaage('inbound_sms2'), headers: @headers - assert_response(200) - response = REXML::Document.new(@response.body) - assert_equal(response.elements.count, 1) - - ticket.reload - assert_equal(2, ticket.articles.count) - assert_equal('new', ticket.state.name) - assert_equal(Ticket::Article.last.id, article.id) - - # new ticket need to be create - ticket.state = Ticket::State.find_by(name: 'closed') - ticket.save! - - post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_messaage('inbound_sms3'), headers: @headers - assert_response(200) - response = REXML::Document.new(@response.body) - assert_equal(response.elements.count, 1) - - ticket.reload - assert_equal(2, ticket.articles.count) - assert_not_equal(Ticket.last.id, ticket.id) - assert_equal('closed', ticket.state.name) - - ticket = Ticket.last - article = Ticket::Article.last - customer = User.last - assert_equal(1, ticket.articles.count) - assert_equal('new 2', ticket.title) - assert_equal(group_id, ticket.group_id) - assert_equal(customer.id, ticket.customer_id) - assert_equal(customer.id, ticket.created_by_id) - assert_equal('+491710000000', article.from) - assert_equal('+4915700000000', article.to) - assert_nil(article.cc) - assert_nil(article.subject) - assert_equal('new 2', article.body) - assert_equal(customer.id, article.created_by_id) - assert_equal('Customer', article.sender.name) - assert_equal('sms', article.type.name) - - # reply by agent - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent@example.com', 'agentpw') - params = { - ticket_id: ticket.id, - body: 'some test', - type: 'sms', - } - post '/api/v1/ticket_articles', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(201) - result = JSON.parse(@response.body) - assert_equal(Hash, result.class) - assert_nil(result['subject']) - assert_equal('some test', result['body']) - assert_equal('text/plain', result['content_type']) - assert_equal(agent.id, result['updated_by_id']) - assert_equal(agent.id, result['created_by_id']) - - stub_request(:post, 'https://api.twilio.com/2010-04-01/Accounts/111/Messages.json') - .with( - body: { - 'Body' => 'some test', - 'From' => '333', - 'To' => nil, - }, - headers: { - 'Accept' => 'application/json', - 'Accept-Charset' => 'utf-8', - 'Authorization' => 'Basic MTExOjIyMw==', - 'Content-Type' => 'application/x-www-form-urlencoded', - } - ).to_return(status: 200, body: '', headers: {}) - - assert_nil(article.preferences[:delivery_retry]) - assert_nil(article.preferences[:delivery_status]) - - Observer::Transaction.commit - Scheduler.worker(true) - - article = Ticket::Article.find(result['id']) - assert_equal(1, article.preferences[:delivery_retry]) - assert_equal('success', article.preferences[:delivery_status]) - - end - - test 'customer based on already existing mobile attibute' do - - customer = User.create!( - firstname: '', - lastname: '', - email: 'me@example.com', - mobile: '01710000000', - note: '', - updated_by_id: 1, - created_by_id: 1, - ) - Observer::Transaction.commit - Scheduler.worker(true) - - # configure twilio channel - bot_id = 123_456_789 - group_id = Group.find_by(name: 'Users').id - - UserInfo.current_user_id = 1 - channel = Channel.create!( - area: 'Sms::Account', - options: { - adapter: 'sms/twilio', - webhook_token: 'f409460e50f76d331fdac8ba7b7963b6', - account_id: '111', - token: '223', - sender: '333', - }, - group_id: group_id, - active: true, - ) - - post '/api/v1/sms_webhook/f409460e50f76d331fdac8ba7b7963b6', params: read_messaage('inbound_sms1'), headers: @headers - assert_response(200) - response = REXML::Document.new(@response.body) - assert_equal(response.elements.count, 1) - - assert_equal(User.last.id, customer.id) - end - - def read_messaage(file) - File.read(Rails.root.join('test', 'data', 'twilio', "#{file}.json")) - end -end diff --git a/test/integration/user_device_controller_test.rb b/test/integration/user_device_controller_test.rb deleted file mode 100644 index 790ceb08b..000000000 --- a/test/integration/user_device_controller_test.rb +++ /dev/null @@ -1,559 +0,0 @@ -require 'test_helper' - -class UserDeviceControllerTest < ActionDispatch::IntegrationTest - self.test_order = :sorted - self.use_transactional_tests = false - - setup do - - # set accept header - @headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' } - - # create agent - roles = Role.where(name: %w[Admin Agent]) - groups = Group.all - - UserInfo.current_user_id = 1 - @admin = User.create_or_update( - login: 'user-device-admin', - firstname: 'UserDevice', - lastname: 'Admin', - email: 'user-device-admin@example.com', - password: 'adminpw', - active: true, - roles: roles, - groups: groups, - ) - - # create agent - roles = Role.where(name: 'Agent') - @agent = User.create_or_update( - login: 'user-device-agent', - firstname: 'UserDevice', - lastname: 'Agent', - email: 'user-device-agent@example.com', - password: 'agentpw', - active: true, - roles: roles, - groups: groups, - ) - - ENV['TEST_REMOTE_IP'] = '5.9.62.170' # de - ENV['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:46.0) Gecko/20100101 Firefox/46.0' - ENV['SWITCHED_FROM_USER_ID'] = nil - - UserDevice.destroy_all - end - - test '01 - index with nobody' do - - get '/api/v1/signshow' - assert_response(200) - result = JSON.parse(@response.body) - assert_equal(result.class, Hash) - assert_equal(result['error'], 'no valid session') - assert(result['config']) - assert_not(controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - end - - test '02 - login index with admin without fingerprint' do - - assert_equal(0, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - params = { without_fingerprint: 'none', username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params: params.to_json, headers: @headers - assert_response(422) - result = JSON.parse(@response.body) - - assert_equal(result.class, Hash) - assert_equal('Need fingerprint param!', result['error']) - assert_not(result['config']) - assert_not(controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - assert_equal(0, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - end - - test '03 - login index with admin with fingerprint - I' do - - assert_equal(0, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - params = { fingerprint: 'my_finger_print', username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params: params.to_json, headers: @headers - assert_response(201) - result = JSON.parse(@response.body) - assert_equal(result.class, Hash) - assert_not(result['error']) - assert(result['config']) - assert('my_finger_print', controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - user_device_first = UserDevice.last - sleep 2 - - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers - assert_response(200) - result = JSON.parse(@response.body) - assert_equal(result.class, Array) - assert('my_finger_print', controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - user_device_last = UserDevice.last - assert_equal(user_device_last.updated_at.to_s, user_device_first.updated_at.to_s) - - params = { fingerprint: 'my_finger_print' } - get '/api/v1/signshow', params: params, headers: @headers - assert_response(200) - result = JSON.parse(@response.body) - assert_equal(result.class, Hash) - assert(result['session']) - assert_equal(result['session']['login'], 'user-device-admin') - assert(result['config']) - - Scheduler.worker(true) - - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - user_device_last = UserDevice.last - assert_equal(user_device_last.updated_at.to_s, user_device_first.updated_at.to_s) - - ENV['USER_DEVICE_UPDATED_AT'] = (Time.zone.now - 4.hours).to_s - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers - assert_response(200) - result = JSON.parse(@response.body) - assert_equal(result.class, Array) - assert('my_finger_print', controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - user_device_last = UserDevice.last - assert_not_equal(user_device_last.updated_at.to_s, user_device_first.updated_at.to_s) - ENV['USER_DEVICE_UPDATED_AT'] = nil - - ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch - - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers - assert_response(200) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(2, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(1, email_notification_count('user_device_new_location', @admin.email)) - - # ip reset - ENV['TEST_REMOTE_IP'] = '5.9.62.170' # de - - end - - test '04 - login index with admin with fingerprint - II' do - - UserDevice.create!( - user_id: @admin.id, - name: 'test 1', - location: 'some location', - user_agent: 'some user agent', - ip: '127.0.0.1', - fingerprint: 'fingerprintI', - ) - - params = { fingerprint: 'my_finger_print_II', username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params: params.to_json, headers: @headers - assert_response(201) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(2, UserDevice.where(user_id: @admin.id).count) - assert_equal(1, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - assert_equal(result.class, Hash) - assert_not(result['error']) - assert(result['config']) - assert('my_finger_print_III', controller.session[:user_device_fingerprint]) - - get '/api/v1/users', params: params.to_json, headers: @headers - assert_response(200) - result = JSON.parse(@response.body) - assert_equal(result.class, Array) - - Scheduler.worker(true) - - assert_equal(2, UserDevice.where(user_id: @admin.id).count) - assert_equal(1, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - params = { fingerprint: 'my_finger_print_II' } - get '/api/v1/signshow', params: params, headers: @headers - assert_response(200) - result = JSON.parse(@response.body) - assert_equal(result.class, Hash) - assert(result['session']) - assert_equal(result['session']['login'], 'user-device-admin') - assert(result['config']) - - Scheduler.worker(true) - - assert_equal(2, UserDevice.where(user_id: @admin.id).count) - assert_equal(1, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch - - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers - assert_response(200) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(3, UserDevice.where(user_id: @admin.id).count) - assert_equal(1, email_notification_count('user_device_new', @admin.email)) - assert_equal(1, email_notification_count('user_device_new_location', @admin.email)) - - # ip reset - ENV['TEST_REMOTE_IP'] = '5.9.62.170' # de - - end - - test '05 - login index with admin with fingerprint - II' do - - UserDevice.add( - ENV['HTTP_USER_AGENT'], - ENV['TEST_REMOTE_IP'], - @admin.id, - 'my_finger_print_II', - 'session', # session|basic_auth|token_auth|sso - ) - - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - - params = { fingerprint: 'my_finger_print_II', username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params: params.to_json, headers: @headers - assert_response(201) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - assert_equal(result.class, Hash) - assert_not(result['error']) - assert(result['config']) - assert('my_finger_print_II', controller.session[:user_device_fingerprint]) - end - - test '06 - login index with admin with basic auth' do - - ENV['HTTP_USER_AGENT'] = 'curl 1.0.0' - UserDevice.add( - ENV['HTTP_USER_AGENT'], - '127.0.0.1', - @admin.id, - '', - 'basic_auth', # session|basic_auth|token_auth|sso - ) - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-admin', 'adminpw') - - ENV['HTTP_USER_AGENT'] = 'curl 1.2.3' - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(2, UserDevice.where(user_id: @admin.id).count) - assert_equal(1, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - assert_equal(result.class, Array) - user_device_first = UserDevice.last - sleep 2 - - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(2, UserDevice.where(user_id: @admin.id).count) - assert_equal(1, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - assert_equal(result.class, Array) - user_device_last = UserDevice.last - assert_equal(user_device_last.id, user_device_first.id) - assert_equal(user_device_last.updated_at.to_s, user_device_first.updated_at.to_s) - - user_device_last.updated_at = Time.zone.now - 4.hours - user_device_last.save! - - params = {} - get '/api/v1/users', params: params, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(2, UserDevice.where(user_id: @admin.id).count) - assert_equal(1, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - assert_equal(result.class, Array) - user_device_last = UserDevice.last - assert_equal(user_device_last.id, user_device_first.id) - assert(user_device_last.updated_at > user_device_first.updated_at) - - end - - test '07 - login index with admin with basic auth' do - - ENV['HTTP_USER_AGENT'] = 'curl 1.2.3' - - UserDevice.add( - ENV['HTTP_USER_AGENT'], - ENV['TEST_REMOTE_IP'], - @admin.id, - '', - 'basic_auth', # session|basic_auth|token_auth|sso - ) - - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-admin', 'adminpw') - - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - assert_equal(result.class, Array) - - end - - test '08 - login index with agent with basic auth' do - - assert_equal(0, UserDevice.where(user_id: @agent.id).count) - assert_equal(0, email_notification_count('user_device_new', @agent.email)) - assert_equal(0, email_notification_count('user_device_new_location', @agent.email)) - - ENV['HTTP_USER_AGENT'] = 'curl 1.2.3' - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-agent', 'agentpw') - - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(1, UserDevice.where(user_id: @agent.id).count) - assert_equal(0, email_notification_count('user_device_new', @agent.email)) - assert_equal(0, email_notification_count('user_device_new_location', @agent.email)) - assert_equal(result.class, Array) - - end - - test '09 - login index with agent with basic auth' do - - ENV['HTTP_USER_AGENT'] = 'curl 1.2.3' - - UserDevice.add( - ENV['HTTP_USER_AGENT'], - ENV['TEST_REMOTE_IP'], - @agent.id, - '', - 'basic_auth', # session|basic_auth|token_auth|sso - ) - - assert_equal(1, UserDevice.where(user_id: @agent.id).count) - assert_equal(0, email_notification_count('user_device_new', @agent.email)) - assert_equal(0, email_notification_count('user_device_new_location', @agent.email)) - - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-agent', 'agentpw') - - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(1, UserDevice.where(user_id: @agent.id).count) - assert_equal(0, email_notification_count('user_device_new', @agent.email)) - assert_equal(0, email_notification_count('user_device_new_location', @agent.email)) - assert_equal(result.class, Array) - - end - - test '10 - login with switched_from_user_id' do - - assert_equal(0, UserDevice.where(user_id: @agent.id).count) - assert_equal(0, email_notification_count('user_device_new', @agent.email)) - assert_equal(0, email_notification_count('user_device_new_location', @agent.email)) - - ENV['SWITCHED_FROM_USER_ID'] = @admin.id.to_s - - params = { fingerprint: 'my_finger_print_II', username: 'user-device-agent', password: 'agentpw' } - post '/api/v1/signin', params: params.to_json, headers: @headers - assert_response(201) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - assert_equal(0, UserDevice.where(user_id: @agent.id).count) - assert_equal(0, email_notification_count('user_device_new', @agent.email)) - assert_equal(0, email_notification_count('user_device_new_location', @agent.email)) - assert_equal(result.class, Hash) - assert_not(result['error']) - assert(result['config']) - assert('my_finger_print_II', controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - assert_equal(0, UserDevice.where(user_id: @agent.id).count) - assert_equal(0, email_notification_count('user_device_new', @agent.email)) - assert_equal(0, email_notification_count('user_device_new_location', @agent.email)) - - ENV['USER_DEVICE_UPDATED_AT'] = (Time.zone.now - 4.hours).to_s - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers - assert_response(200) - result = JSON.parse(@response.body) - assert_equal(result.class, Array) - assert('my_finger_print_II', controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - assert_equal(0, UserDevice.where(user_id: @agent.id).count) - assert_equal(0, email_notification_count('user_device_new', @agent.email)) - assert_equal(0, email_notification_count('user_device_new_location', @agent.email)) - ENV['USER_DEVICE_UPDATED_AT'] = nil - - ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch - params = {} - get '/api/v1/users', params: params.to_json, headers: @headers - assert_response(200) - result = JSON.parse(@response.body) - - Scheduler.worker(true) - - # ip reset - ENV['TEST_REMOTE_IP'] = '5.9.62.170' # de - - assert_equal(0, UserDevice.where(user_id: @agent.id).count) - assert_equal(0, email_notification_count('user_device_new', @agent.email)) - assert_equal(0, email_notification_count('user_device_new_location', @agent.email)) - - end - - test '11 - login with invalid fingerprint' do - - assert_equal(0, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - params = { fingerprint: 'to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890to_long_1234567890', username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params: params.to_json, headers: @headers - assert_response(422) - result = JSON.parse(@response.body) - - assert_equal(result.class, Hash) - assert_equal('fingerprint is 198 chars but can only be 160 chars!', result['error']) - assert_not(result['config']) - assert_not(controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - assert_equal(0, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - end - - test '12 - login with integer as fingerprint' do - - assert_equal(0, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - params = { fingerprint: 123_456_789, username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params: params.to_json, headers: @headers - assert_response(201) - result = JSON.parse(@response.body) - assert(123_456_789, controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - assert_equal(1, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - assert_equal(result.class, Hash) - assert_nil(result['error']) - end - - test '13 - login form controller - check no user device logging' do - - Setting.set('form_ticket_create', true) - - assert_equal(0, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-admin', 'adminpw') - - params = { - fingerprint: 'long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890long_1234567890' - } - post '/api/v1/form_config', params: params.to_json, headers: @headers.merge('Authorization' => credentials) - assert_response(200) - - result = JSON.parse(@response.body) - assert_equal(result.class, Hash) - assert_not(result['error']) - assert(result['endpoint']) - assert_not(controller.session[:user_device_fingerprint]) - - Scheduler.worker(true) - - assert_equal(0, UserDevice.where(user_id: @admin.id).count) - assert_equal(0, email_notification_count('user_device_new', @admin.email)) - assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) - - end - -end