diff --git a/app/controllers/api/v3/notices_controller.rb b/app/controllers/api/v3/notices_controller.rb index 96437d8..750d0dd 100644 --- a/app/controllers/api/v3/notices_controller.rb +++ b/app/controllers/api/v3/notices_controller.rb @@ -23,12 +23,12 @@ class Api::V3::NoticesController < ApplicationController render text: 'Notice for old app version ignored' end else - render text: 'Your API key is unknown', :status => 422 + render text: 'Your API key is unknown', status: 422 end else render nothing: true end rescue AirbrakeApi::ParamsError - render text: 'Invalid request' + render text: 'Invalid request', status: 400 end end diff --git a/config/routes.rb b/config/routes.rb index c52e06b..fcf1e3d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -58,10 +58,10 @@ Rails.application.routes.draw do end end end - - match '/v3/projects/:project_id/notices' => 'v3/notices#create', via: [:post, :options] end + match '/api/v3/projects/:project_id/notices' => 'api/v3/notices#create', via: [:post, :options] + root :to => 'apps#index' end diff --git a/lib/airbrake_api/v3/notice_parser.rb b/lib/airbrake_api/v3/notice_parser.rb index 96c80d4..a91e62f 100644 --- a/lib/airbrake_api/v3/notice_parser.rb +++ b/lib/airbrake_api/v3/notice_parser.rb @@ -27,7 +27,7 @@ module AirbrakeApi private def error - raise ParamsError unless params.has_key?('errors') && params['errors'].any? + raise AirbrakeApi::ParamsError unless params.has_key?('errors') && params['errors'].any? @error ||= params['errors'].first end diff --git a/spec/controllers/api/v3/notices_controller_spec.rb b/spec/controllers/api/v3/notices_controller_spec.rb new file mode 100644 index 0000000..2f52787 --- /dev/null +++ b/spec/controllers/api/v3/notices_controller_spec.rb @@ -0,0 +1,54 @@ +describe Api::V3::NoticesController, type: :controller do + let(:app) { Fabricate(:app) } + + it 'responds to OPTIONS request and sets CORS headers' do + process :create, 'OPTIONS', project_id: app.api_key + expect(response).to be_success + expect(response.headers['Access-Control-Allow-Origin']).to eq('*') + expect(response.headers['Access-Control-Allow-Headers']).to eq('origin, content-type, accept') + end + + it 'sets CORS headers on POST request' do + post :create, project_id: 'invalid id' + expect(response.headers['Access-Control-Allow-Origin']).to eq('*') + expect(response.headers['Access-Control-Allow-Headers']).to eq('origin, content-type, accept') + end + + it 'returns created notice id in json format' do + json = Rails.root.join('spec', 'fixtures', 'api_v3_request.json').read + data = JSON.parse(json) + data['project_id'] = app.api_key + data['key'] = app.api_key + post :create, data + notice = Notice.last + expect(response.body).to eq({ notice: { id: notice.id } }.to_json) + end + + it 'responds with 400 when request attributes are not valid' do + allow_any_instance_of(AirbrakeApi::V3::NoticeParser).to receive(:report).and_raise(AirbrakeApi::ParamsError) + post :create, project_id: 'ID' + expect(response.status).to eq(400) + expect(response.body).to eq('Invalid request') + end + + it 'responds with 422 when api_key or project_id is invalid' do + json = Rails.root.join('spec', 'fixtures', 'api_v3_request.json').read + data = JSON.parse(json) + data['project_id'] = 'invalid' + data.delete('key') + post :create, data + expect(response.status).to eq(422) + expect(response.body).to eq('Your API key is unknown') + end + + it 'ignores notices for older api' do + upgraded_app = Fabricate(:app, current_app_version: '2.0') + json = Rails.root.join('spec', 'fixtures', 'api_v3_request.json').read + data = JSON.parse(json) + data['project_id'] = upgraded_app.api_key + data['key'] = upgraded_app.api_key + post :create, data + expect(response.body).to eq('Notice for old app version ignored') + expect(Notice.count).to eq(0) + end +end \ No newline at end of file diff --git a/spec/fixtures/api_v3_request.json b/spec/fixtures/api_v3_request.json new file mode 100644 index 0000000..dccf38c --- /dev/null +++ b/spec/fixtures/api_v3_request.json @@ -0,0 +1,38 @@ +{ + "notifier":{"name":"airbrake-js-v8","version":"0.3.10","url":"https://github.com/airbrake/airbrake-js"}, + "errors":[ + { + "type":"Error", + "message":"Error: TestError", + "backtrace":[ + {"function":"d","file":"http://localhost:3000/assets/application.js","line":11234,"column":24}, + {"function":"c","file":"http://localhost:3000/assets/application.js","line":11233,"column":18}, + {"function":"b","file":"http://localhost:3000/assets/application.js","line":11232,"column":18}, + {"function":"a","file":"http://localhost:3000/assets/application.js","line":11231,"column":18}, + {"function":"HTMLDocument.","file":"http://localhost:3000/assets/application.js","line":11236,"column":3}, + {"function":"fire","file":"http://localhost:3000/assets/application.js","line":1018,"column":34}, + {"function":"Object.self.fireWith [as resolveWith]","file":"http://localhost:3000/assets/application.js","line":1128,"column":13}, + {"function":"Function.jQuery.extend.ready","file":"http://localhost:3000/assets/application.js","line":417,"column":15}, + {"function":"HTMLDocument.DOMContentLoaded","file":"http://localhost:3000/assets/application.js","line":93,"column":14} + ] + } + ], + "context":{ + "language":"JavaScript", + "sourceMapEnabled":true, + "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36", + "url":"http://localhost:3000/kontakt", + "userId":1,"userUsername":"john", + "userName":"John Doe", + "userUsername": "john", + "userEmail":"john.doe@example.org", + "version":"1.0", + "component":"ContactsController", + "action":"show" + }, + "params":{"returnTo":"dashboard"}, + "environment":{"navigator_vendor":"Google Inc."}, + "session":{"isAdmin":true}, + "key":"a3969bfbf65f073921e", + "project_id":"a3969bfbf65f073921e" +} \ No newline at end of file diff --git a/spec/lib/airbrake_api/v3/notice_parser_spec.rb b/spec/lib/airbrake_api/v3/notice_parser_spec.rb index d414cf7..97bc60f 100644 --- a/spec/lib/airbrake_api/v3/notice_parser_spec.rb +++ b/spec/lib/airbrake_api/v3/notice_parser_spec.rb @@ -4,15 +4,15 @@ describe AirbrakeApi::V3::NoticeParser do it 'raises error when errors attribute is missing' do expect { AirbrakeApi::V3::NoticeParser.new({}).report - }.to raise_error(AirbrakeApi::V3::NoticeParser::ParamsError) + }.to raise_error(AirbrakeApi::ParamsError) expect { AirbrakeApi::V3::NoticeParser.new({'errors' => []}).report - }.to raise_error(AirbrakeApi::V3::NoticeParser::ParamsError) + }.to raise_error(AirbrakeApi::ParamsError) end it 'parses JSON payload and returns ErrorReport' do - params = build_params(api_key: app.api_key) + params = build_params(key: app.api_key) report = AirbrakeApi::V3::NoticeParser.new(params).report notice = report.generate_notice! @@ -30,52 +30,19 @@ describe AirbrakeApi::V3::NoticeParser do end it 'parses JSON payload when api_key is missing but project_id is present' do - params = build_params(api_key: nil, project_id: app.api_key) + params = build_params(key: nil, project_id: app.api_key) report = AirbrakeApi::V3::NoticeParser.new(params).report expect(report).to be_valid end def build_params(options = {}) - JSON.parse(<<-EOL) - { - "notifier":{"name":"airbrake-js-v8","version":"0.3.10","url":"https://github.com/airbrake/airbrake-js"}, - "errors":[ - { - "type":"Error", - "message":"Error: TestError", - "backtrace":[ - {"function":"d","file":"http://localhost:3000/assets/application.js","line":11234,"column":24}, - {"function":"c","file":"http://localhost:3000/assets/application.js","line":11233,"column":18}, - {"function":"b","file":"http://localhost:3000/assets/application.js","line":11232,"column":18}, - {"function":"a","file":"http://localhost:3000/assets/application.js","line":11231,"column":18}, - {"function":"HTMLDocument.","file":"http://localhost:3000/assets/application.js","line":11236,"column":3}, - {"function":"fire","file":"http://localhost:3000/assets/application.js","line":1018,"column":34}, - {"function":"Object.self.fireWith [as resolveWith]","file":"http://localhost:3000/assets/application.js","line":1128,"column":13}, - {"function":"Function.jQuery.extend.ready","file":"http://localhost:3000/assets/application.js","line":417,"column":15}, - {"function":"HTMLDocument.DOMContentLoaded","file":"http://localhost:3000/assets/application.js","line":93,"column":14} - ] - } - ], - "context":{ - "language":"JavaScript", - "sourceMapEnabled":true, - "userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36", - "url":"http://localhost:3000/kontakt", - "userId":1,"userUsername":"john", - "userName":"John Doe", - "userUsername": "john", - "userEmail":"john.doe@example.org", - "version":"1.0", - "component":"ContactsController", - "action":"show" - }, - "params":{"returnTo":"dashboard"}, - "environment":{"navigator_vendor":"Google Inc."}, - "session":{"isAdmin":true}, - "key":"#{options[:api_key]}", - "project_id":"#{options[:project_id]}" - } - EOL + json = Rails.root.join('spec', 'fixtures', 'api_v3_request.json').read + data = JSON.parse(json) + + data['key'] = options[:key] if options.has_key?(:key) + data['project_id'] = options[:project_id] if options.has_key?(:project_id) + + data end end \ No newline at end of file -- libgit2 0.21.2