debshots/test/controllers/packages_controller_test.rb
Christoph Haas 4d07f43a2e Show related packages based on description embeddings
Package pages get a "Related packages" section: a nearest neighbor
query against the package's own stored embedding (no external service
call), excluding the package itself. Packages without an embedding
render no section.
2026-08-22 23:47:42 +02:00

176 lines
6.4 KiB
Ruby

# frozen_string_literal: true
require 'test_helper'
class PackagesControllerTest < ActionController::TestCase
test 'should get index and contain dummy package-4' do
get :grid
assert_response :success
assert_select 'div', 'package-4'
end
test 'should get list view with_screenshots and find Firefox' do
# package = Package.create!(name: 'firefox', description: 'A web browser.')
# Screenshot.create!(package: package, approved: true, hidden: false)
# get :list, params: { show: 'with' }
# assert_response :success
# assert_select 'div', 'A web browser.'
get :list, params: { show: 'with' }
assert_response :success
assert_select 'div', 'A program to browse web sites.'
end
test 'exact package name search wins without calling the vector service' do
with_stubbed_method(Package, :nearest_to_text,
->(_text) { flunk 'should not call vector search' }) do
get :grid, params: { search: 'vim' }
assert_response :success
assert_select 'div', 'vim'
end
end
test 'gibberish search shows no results and never calls the vector service' do
with_stubbed_method(Package, :nearest_to_text,
->(_text) { flunk 'should not call vector search' }) do
get :grid, params: { search: 'asdfgh zzzz' }
assert_response :success
# the grid renders every package in the database when no search
# filter applies - so an empty result must not fall back to that
assert_select 'div', text: /package-\d+/, count: 0
end
end
test 'name prefix matches rank above semantic results' do
with_stubbed_method(Package, :nearest_to_text,
->(_text, **_opts) { Package.where(name: packages(:vim).name) }) do
get :grid, params: { search: 'package' }
assert_response :success
# fixtures create package-0..package-99 - prefix hits must render
assert_select 'div', 'package-0'
# ...and before any semantically found package
assert response.body.index('package-0') < response.body.index('vim')
end
end
test 'prefix matches and semantic results are deduplicated' do
with_stubbed_method(Package, :nearest_to_text,
->(_text, **_opts) { Package.where(name: packages(:firefox).name) }) do
get :grid, params: { search: 'fire' }
assert_response :success
assert_select 'div', text: 'firefox', count: 1
end
end
test 'compound words in search match packages with joined names' do
# "fire fox" should find "firefox" via name substring matching
with_stubbed_method(Package, :nearest_to_text,
->(_text, **_opts) { Package.none }) do
get :grid, params: { search: 'fire fox' }
assert_response :success
assert_select 'div', text: 'firefox', count: 1
end
end
test 'details shows semantically related packages' do
packages(:vim).update_column(:embedding, Array.new(384, 0.25))
packages(:firefox).update_column(:embedding, Array.new(384, 0.75))
get :details, params: { name: 'vim' }
assert_response :success
assert_select '#related .pkgname', text: 'firefox'
end
test 'details without embedding renders no related section' do
get :details, params: { name: 'vim' }
assert_response :success
assert_select '#related', count: 0
end
test 'search uses semantic (vector) results' do
relation = Package.where(name: packages(:vim).name)
with_stubbed_method(Package, :nearest_to_text, ->(_text, **_opts) { relation }) do
get :grid, params: { search: 'editor' }
assert_response :success
assert_select 'div', 'vim'
end
end
# There is deliberately no fallback for an empty vector search
# result: KNN always returns something as long as packages have
# embeddings. Full-text search is only used when the vector service
# cannot be reached.
test 'search falls back to full-text search when vector service fails' do
with_stubbed_method(Vectorizer, :embed,
->(_text) { raise Vectorizer::Error, 'service down' }) do
get :grid, params: { search: 'editor' }
assert_response :success
assert_select 'div', 'vim'
assert flash[:error].present?
end
end
# test 'should get thumbnail for a package and a desired version' do
# # get '/thumbnail-with-version/package-5/0.1'
# get thumbnail_with_version_url('package-5', '0.1')
# end
# test 'should get without_screenshots' do
# get :without_screenshots
# assert_response :success
# end
# test "should get moderate" do
# get :moderate
# assert_response :success
# end
# test "upload screenshot anonymously then login and get screenshots assigned" do
# newest_screenshot1 = Package.find_by_name(:firefox).screenshots.order(id: :desc).first
# # Load the upload page
# get :upload, params: { name: 'firefox' }
# assert_response :success
# # Upload a screenshot and expect to be redirected afterwards
# post :upload_receive, params: { name: 'firefox', file: [ fixture_file_upload('test/fixtures/files/large1.png','image/png') ] }
# assert_redirected_to package_path(name: 'firefox')
# # Check that the newest screenshot is not yet approved
# newest_screenshot2 = Package.find_by_name(:firefox).screenshots.order(id: :desc).first
# assert_not_equal newest_screenshot1, newest_screenshot2
# assert_equal newest_screenshot2.approved, false
# # Login
# sign_in users(:normal)
# # Get the information about the newest screenshot again
# newest_screenshot2 = Package.find_by_name(:firefox).screenshots.order(id: :desc).first
# # Expect the uploaded screenshot to be assigned to this user
# byebug
# assert_equal newest_screenshot2.user, users(:normal)
# # (name: 'firefox')
# # img_count_before = page.find_all('img').count
# # attach_file 'file[]', Rails.root.join('test/fixtures/files/large1.png')
# # click_on 'Start upload'
# # # The cookie session must remember this anonymous upload
# # newest_screenshot = Package.find_by_name(:firefox).screenshots.order(id: :desc).first
# # assert_equal session[:uploaded_screenshots].length, [newest_screenshot]
# # #
# # # sign_in users(:debian)
# # # # Screenshot is instantly public
# # # newest_screenshot = Package.find_by_name(:firefox).screenshots.order(id: :desc).first
# # # assert_equal newest_screenshot.approved, true
# # # # Clean up
# # newest_screenshot.destroy
# # sign_out users(:normal)
# end
end