mirror of
https://github.com/we-promise/sure.git
synced 2026-09-07 15:44:21 +00:00
* Fix PDF vision path failing when poppler-utils is missing The Docker image omitted poppler-utils, so the OpenAI PDF vision path (which renders pages with pdftoppm before sending them upstream) always failed and the admin AI status page surfaced a generic "request failed" code rather than a useful reason. - install poppler-utils in the Docker base image (pdftoppm for the vision render path) - add an optional failure_code to Provider::Error, so probe errors can carry a machine-readable reason - in Provider::Openai::PdfProcessor#convert_pdf_to_images, check pdftoppm's return value and -- when the binary is genuinely missing, raise a Provider::Openai::Error with failure_code :render_missing_binary while preserving the existing [] fallback for other render failures - register the :render_missing_binary code in the admin locale so the AI status page shows a concrete, actionable message instead of "request failed" - AiHealth::Probe#failure_code now falls through to the default codes when an error's failure_code is nil, instead of returning nil - regression tests covering both the missing-binary and the present-but-fails cases Fixes the "PDF vision/native path" system check on instances where the image is built from the checked-in Dockerfile. * Fix missing-binary detection and preserve failure_code across the error boundary - convert_pdf_to_images: Kernel#system returns nil (not false) when the executable is absent; raise the coded error on rendered.nil? so a missing pdftoppm yields :render_missing_binary instead of a blank conversion. - Provider::Error#as_json + default_error_transformer: carry failure_code through serialization and error re-wrapping. - Drop the binary_missing? helper (nil result is the authoritative signal) and update regression tests to stub the real nil return value. - Add coverage for failure_code serialization/transformation. * Fix Provider::Error transformer syntax error and cover Faraday branch Addresses jjmata's blocking change-request: app/models/provider.rb:54 used a postfix `if` modifier inside a hash-argument/method-call argument list, which is not valid Ruby. `ruby -c` failed to parse the file, so the base class every provider inherits from could not autoload and the whole app (boot, requests, jobs, tests) was down. Rewrite default_error_transformer to build the optional failure_code keyword once (only when the error exposes a truthy code) and splat it, so both the Faraday::Error branch and the generic branch carry the code with no syntax error and no nil kwarg. Also add the two Faraday-branch regression tests that were missing (failure_code preservation + response-body-to-details extraction), guarding this exact class of broken-argument bug with real assertions. Verification: ruby -c passes on provider.rb, pdf_processor.rb, probe.rb, and both test files; plus a behavioral harness against the real provider.rb source covering the coded/plain/nil-code, Faraday-coded, Faraday-no-code, nil-response, and generic-error paths (19/19 pass). Ref: we-promise/sure#3275 * Document the methods added or changed by this PR * Add poppler-utils to devcontainer image --------- Co-authored-by: hermes-on-behalf-of-jon <hermes@nousresearch.com> Co-authored-by: jaysbeekay <jaysbeekay@users.noreply.github.com> Co-authored-by: sure-admin <sure-admin@splashblot.com>
107 lines
3.3 KiB
Ruby
107 lines
3.3 KiB
Ruby
require "test_helper"
|
|
require "ostruct"
|
|
|
|
class TestProvider < Provider
|
|
TestError = Class.new(StandardError)
|
|
|
|
def initialize(client)
|
|
@client = client
|
|
end
|
|
|
|
def fetch_data
|
|
with_provider_response do
|
|
@client.get("/test")
|
|
end
|
|
end
|
|
|
|
def fetch_data_with_error_transformer
|
|
with_provider_response(error_transformer: ->(error) { TestError.new(error.message) }) do
|
|
@client.get("/test")
|
|
end
|
|
end
|
|
end
|
|
|
|
class ProviderTest < ActiveSupport::TestCase
|
|
setup do
|
|
@client = mock
|
|
@provider = TestProvider.new(@client)
|
|
end
|
|
|
|
test "returns success response with data" do
|
|
@client.expects(:get).with("/test").returns({ some: "data" })
|
|
|
|
response = @provider.fetch_data
|
|
|
|
assert response.success?
|
|
assert_equal({ some: "data" }, response.data)
|
|
end
|
|
|
|
test "returns failed response with error" do
|
|
@client.expects(:get).with("/test").raises(StandardError.new("some error"))
|
|
|
|
response = @provider.fetch_data
|
|
|
|
assert_not response.success?
|
|
assert_equal("some error", response.error.message)
|
|
end
|
|
|
|
test "provider can transform error" do
|
|
@client.expects(:get).with("/test").raises(StandardError.new("some error"))
|
|
|
|
response = @provider.fetch_data_with_error_transformer
|
|
|
|
assert_not response.success?
|
|
assert_equal("some error", response.error.message)
|
|
assert_instance_of TestProvider::TestError, response.error
|
|
end
|
|
|
|
test "default_error_transformer preserves the failure_code when present" do
|
|
source = Provider::Error.new("render failed", failure_code: :render_missing_binary)
|
|
|
|
transformed = @provider.send(:default_error_transformer, source)
|
|
|
|
assert_equal :render_missing_binary, transformed.failure_code
|
|
end
|
|
|
|
test "default_error_transformer drops a nil failure_code instead of passing it" do
|
|
source = Provider::Error.new("render failed")
|
|
|
|
transformed = @provider.send(:default_error_transformer, source)
|
|
|
|
assert_nil transformed.failure_code
|
|
end
|
|
|
|
test "default_error_transformer preserves failure_code and response body for Faraday errors" do
|
|
source = Faraday::ConnectionFailed.new("upstream failed")
|
|
source.define_singleton_method(:failure_code) { :render_missing_binary }
|
|
|
|
transformed = @provider.send(:default_error_transformer, source)
|
|
|
|
assert_instance_of TestProvider::Error, transformed
|
|
assert_equal "upstream failed", transformed.message
|
|
assert_equal :render_missing_binary, transformed.failure_code
|
|
end
|
|
|
|
test "default_error_transformer extracts the response body into details for Faraday errors" do
|
|
source = Faraday::ConnectionFailed.new("upstream failed")
|
|
source.define_singleton_method(:response) { { body: { "error" => { "code" => "bad_pdf" } } } }
|
|
|
|
transformed = @provider.send(:default_error_transformer, source)
|
|
|
|
assert_equal({ "error" => { "code" => "bad_pdf" } }, transformed.details)
|
|
assert_nil transformed.failure_code
|
|
end
|
|
|
|
test "Error#as_json includes the failure_code" do
|
|
error = Provider::Error.new("render failed", details: { hint: "install poppler-utils" }, failure_code: :render_missing_binary)
|
|
|
|
assert_equal(
|
|
{ message: "render failed", details: { hint: "install poppler-utils" }, failure_code: :render_missing_binary },
|
|
error.as_json
|
|
)
|
|
|
|
plain = Provider::Error.new("boom")
|
|
assert_nil plain.as_json[:failure_code]
|
|
end
|
|
end
|