-
Notifications
You must be signed in to change notification settings - Fork 0
Enable TACOS integration #228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| class TacosController < ApplicationController | ||
| layout false | ||
|
|
||
| def analyze | ||
| return unless ApplicationHelper.tacos_enabled? | ||
|
|
||
| Tacos.call(params[:q]) | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| class Tacos | ||
| # The tacos_client argument here is unused in production - it is provided for | ||
| # our test suite so that we can mock various error conditions to ensure that | ||
| # error handling happens as we intend. | ||
| def self.call(term, tacos_client = nil) | ||
|
||
| tacos_http = setup(tacos_client) | ||
| query = '{ "query": "{ logSearchEvent(searchTerm: \"' + clean_term(term) + '\", sourceSystem: \"' + tacos_source + '\" ) { phrase source detectors { suggestedResources { title url } } } }" }' | ||
| begin | ||
| raw_response = tacos_http.timeout(http_timeout).post(tacos_url, body: query) | ||
| JSON.parse(raw_response.to_s) | ||
| rescue HTTP::Error | ||
| {"error" => "A connection error has occurred"} | ||
| rescue JSON::ParserError | ||
| {"error" => "A parsing error has occurred"} | ||
| end | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def self.clean_term(term) | ||
| term.gsub('"', '\'') | ||
| end | ||
|
|
||
| def self.http_timeout | ||
| ENV.fetch('TIMDEX_TIMEOUT', 6).to_f | ||
| end | ||
|
|
||
| def self.origins | ||
| ENV.fetch('ORIGINS', nil) | ||
| end | ||
|
|
||
| # We define the HTTP connection this way so that it can be overridden during | ||
| # testing, to make sure that the .call method can handle specific error | ||
| # conditions. | ||
| def self.setup(tacos_client) | ||
| tacos_client || HTTP.persistent(tacos_url) | ||
| .headers(accept: 'application/json', | ||
| 'Content-Type': 'application/json', | ||
| origin: origins) | ||
| end | ||
|
|
||
| def self.tacos_source | ||
| ENV.fetch('TACOS_SOURCE', 'unset') | ||
|
||
| end | ||
|
|
||
| def self.tacos_url | ||
| ENV.fetch('TACOS_URL', nil) | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| <% return unless (tacos_enabled? and @enhanced_query[:q].present?) %> | ||
|
|
||
| <% data_url = "/analyze?q=#{URI.encode_www_form_component(@enhanced_query[:q])}" %> | ||
|
|
||
| <div class="tacos-container" | ||
| data-controller="content-loader" | ||
| data-content-loader-url-value=<%= data_url %>> | ||
| </div> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| <!-- Result of TACOS analysis would go here --> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| require 'test_helper' | ||
|
|
||
| class TacosControllerTest < ActionDispatch::IntegrationTest | ||
| test 'analyze route exists but returns an HTML comment for now' do | ||
| VCR.use_cassette('tacos direct') do | ||
| get '/analyze?q=direct' | ||
|
|
||
| assert_response :success | ||
| assert_equal "<!-- Result of TACOS analysis would go here -->\n", response.body | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| require 'test_helper' | ||
|
|
||
| class TacosConnectionError | ||
| def timeout(_) | ||
| self | ||
| end | ||
|
|
||
| def post(_url, body:) | ||
| raise HTTP::ConnectionError, "forced connection failure" | ||
| end | ||
| end | ||
|
|
||
| class TacosParsingError | ||
| def timeout(_) | ||
| self | ||
| end | ||
|
|
||
| def post(_url, body:) | ||
| 'This is not valid json' | ||
| end | ||
| end | ||
|
|
||
| class TacosTest < ActiveSupport::TestCase | ||
| test 'TACOS model has a call method that reflects a search term back' do | ||
| VCR.use_cassette('tacos popcorn') do | ||
| searchterm = 'popcorn' | ||
|
|
||
| result = Tacos.call(searchterm) | ||
|
|
||
| assert_instance_of Hash, result | ||
| assert_equal searchterm, result['data']['logSearchEvent']['phrase'] | ||
| end | ||
| end | ||
|
|
||
| test 'TACOS model will use ENV to populate the sourceSystem value' do | ||
| VCR.use_cassette('tacos fake system') do | ||
| ClimateControl.modify(TACOS_SOURCE: 'faked') do | ||
| result = Tacos.call('popcorn') | ||
|
|
||
| assert_equal 'faked', result['data']['logSearchEvent']['source'] | ||
| end | ||
| end | ||
| end | ||
|
|
||
| test 'TACOS model catches connection errors' do | ||
| tacos_client = TacosConnectionError.new | ||
|
|
||
| result = Tacos.call('popcorn', tacos_client) | ||
|
|
||
| assert_instance_of Hash, result | ||
| assert_equal 'A connection error has occurred', result['error'] | ||
| end | ||
|
|
||
| test 'TACOS model catches parsing errors' do | ||
| tacos_client = TacosParsingError.new | ||
|
|
||
| result = Tacos.call('popcorn', tacos_client) | ||
|
|
||
| assert_instance_of Hash, result | ||
| assert_equal 'A parsing error has occurred', result['error'] | ||
| end | ||
| end |
Large diffs are not rendered by default.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ENV.fetch('TACOS_URL', '').present?is more idiomatic in our codebase. (A blank string is not present, yeah it's sort of weird but also kind of makes sense)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm generally happy to go with the idiomatic approach, unless it doesn't work