Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions web/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ GEM
language_server-protocol (3.17.0.6)
lint_roller (1.1.0)
logger (1.7.0)
loofah (2.25.2)
loofah (2.25.3)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
nokogiri (>= 1.19.5)
mail (2.9.1)
logger
mini_mime (>= 0.1.1)
Expand Down Expand Up @@ -235,21 +235,21 @@ GEM
net-smtp (0.5.2)
net-protocol
nio4r (2.7.5)
nokogiri (1.19.4-aarch64-linux-gnu)
nokogiri (1.19.7-aarch64-linux-gnu)
racc (~> 1.4)
nokogiri (1.19.4-aarch64-linux-musl)
nokogiri (1.19.7-aarch64-linux-musl)
racc (~> 1.4)
nokogiri (1.19.4-arm-linux-gnu)
nokogiri (1.19.7-arm-linux-gnu)
racc (~> 1.4)
nokogiri (1.19.4-arm-linux-musl)
nokogiri (1.19.7-arm-linux-musl)
racc (~> 1.4)
nokogiri (1.19.4-arm64-darwin)
nokogiri (1.19.7-arm64-darwin)
racc (~> 1.4)
nokogiri (1.19.4-x86_64-darwin)
nokogiri (1.19.7-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.19.4-x86_64-linux-gnu)
nokogiri (1.19.7-x86_64-linux-gnu)
racc (~> 1.4)
nokogiri (1.19.4-x86_64-linux-musl)
nokogiri (1.19.7-x86_64-linux-musl)
racc (~> 1.4)
nostr (0.7.0)
bech32 (~> 1.4)
Expand Down Expand Up @@ -319,8 +319,8 @@ GEM
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
rails-html-sanitizer (1.7.1)
loofah (~> 2.25, >= 2.25.2)
rails-html-sanitizer (1.7.2)
loofah (~> 2.25, >= 2.25.3)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
railties (8.1.4)
actionpack (= 8.1.4)
Expand Down Expand Up @@ -635,7 +635,7 @@ CHECKSUMS
language_server-protocol (3.17.0.6) sha256=5ef2c0c138f8267e1bc631d3328347d354f96724b0af22f2c79516120443b7f0
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
loofah (2.25.2) sha256=2007f746959ac65552456e04b433e83deb22759ab38c838b4445c70e43425918
loofah (2.25.3) sha256=545f14eef0cc2a7de80df560530d593232b7c07e515c5c4e37532d9cb5b0185c
mail (2.9.1) sha256=06574eca475253d6c18145dd70af80d0eb970182d55053497c5f4d797ea160e8
marcel (1.2.1) sha256=1678e9360e32f9eafa917c80029e2f6d10b2715c66a4b87b6d0da9b9cd1f859f
matrix (0.4.3) sha256=a0d5ab7ddcc1973ff690ab361b67f359acbb16958d1dc072b8b956a286564c5b
Expand All @@ -653,14 +653,14 @@ CHECKSUMS
net-protocol (0.4.0) sha256=f9f90c8c6f64794a45160bf422177a336db12809de3beeeaa26b88fcd2e8c853
net-smtp (0.5.2) sha256=35103cc04d6b2d94632f9928ede07483c24b70b9c0db1f231fea43909b678f3c
nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
nokogiri (1.19.4-aarch64-linux-gnu) sha256=1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f
nokogiri (1.19.4-aarch64-linux-musl) sha256=35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af
nokogiri (1.19.4-arm-linux-gnu) sha256=a301313e38bb065d68239e79734bcd6f56fb6efaacebde29e9abf2a4735340ca
nokogiri (1.19.4-arm-linux-musl) sha256=588923c101bcfa78869734d247d25b598674323e7f22474fc468f6e5647311eb
nokogiri (1.19.4-arm64-darwin) sha256=a46db9853286e6597b36ebc6953817d15acf3a299583eb3f89fdc6f91dd63527
nokogiri (1.19.4-x86_64-darwin) sha256=7fd17057d3e1f00e9954a74b3cd76595d3d4a5ef233b7ed9599047c204f70551
nokogiri (1.19.4-x86_64-linux-gnu) sha256=379fae440b28915e3f19d752ce2dcf8465ed2b2fbefd2a7ca0dd497bc981a06a
nokogiri (1.19.4-x86_64-linux-musl) sha256=17dfb7c1fa194ae02fbf7c51a7afc8d278045ab3fdacfd86f91d02d7b274470b
nokogiri (1.19.7-aarch64-linux-gnu) sha256=8f5e15d299602456406e1f03a9f3456cceb33a0722811e818d2ee2214eb4c84a
nokogiri (1.19.7-aarch64-linux-musl) sha256=efe0c3602e6e54521bc21c681930ce5568e2d11203de17400710b2b3ca2e4cb4
nokogiri (1.19.7-arm-linux-gnu) sha256=7fd1907125691aa89e838cc91161761c758b4e17bb32f0dd9b5515a82cc759af
nokogiri (1.19.7-arm-linux-musl) sha256=28d0ff0c87b6bb2e56580323a6fb049d5d4a02b94f0958fdd47e9ac146991c77
nokogiri (1.19.7-arm64-darwin) sha256=f27d7f25f4873fbc3aa35a2cc2fb680c98555fec1925348da439d0869d541142
nokogiri (1.19.7-x86_64-darwin) sha256=508e81e8c5f84aaa240dce981bf1c43faae60808726f0ce7024ee92effc5cafe
nokogiri (1.19.7-x86_64-linux-gnu) sha256=25865ccb462f714e712fdf8906fde07849cb6704a808e3d629d75baa5af5dd3b
nokogiri (1.19.7-x86_64-linux-musl) sha256=464d1f3dfb0d53cf54c0c6a7e23e8e91cf68ec3cafc2b27dc4a7682f2d9bf546
nostr (0.7.0) sha256=2971efb01821857203d5e32569b3ab1bfa0f4904da4b9c1a7822112e904ccd90
oj (3.17.7) sha256=7a21d3ac8e544a850f1cdaf711b0c8144ba587d14d3e4917c0855fd7b0483db7
openssl (4.0.2) sha256=1037ad2868ae58df9ad917891c0c0f9815a1172f6846d4bcdd508e4c2ee747c2
Expand Down Expand Up @@ -688,7 +688,7 @@ CHECKSUMS
rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868
rails (8.1.4) sha256=5f3ecdf9a2a3b79b2e31b8fee3b64a00f7284d76e5631f87d0e58e665911a33b
rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
rails-html-sanitizer (1.7.1) sha256=e797a7c9b01e567307e317c576b49ab4168017e63eea4dba9ce3cb587e2f22c2
rails-html-sanitizer (1.7.2) sha256=a21ef45b7a6639fc8e2282473c547514cb86ae271616162a946bf89148fa2424
railties (8.1.4) sha256=b5e7a8e8984e33114d68af62227971960aae1e6c02bd7c9d826ffad97fff583c
rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
Expand Down
9 changes: 6 additions & 3 deletions web/app/jobs/pos_payment_reconciliation_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ def perform
# SQLite deployments share one filesystem. An advisory process lock keeps
# a slow gateway request from overlapping a later scheduled sweep; it is
# released automatically if the worker exits.
directory = Rails.root.join('tmp/locks')
FileUtils.mkdir_p(directory)
File.open(directory.join('pos-payment-reconciliation.lock'), File::RDWR | File::CREAT | File::NOFOLLOW, 0o600) do |lock|
FileUtils.mkdir_p(lock_path.dirname)
File.open(lock_path, File::RDWR | File::CREAT | File::NOFOLLOW, 0o600) do |lock|
return unless lock.flock(File::LOCK_EX | File::LOCK_NB)

reconcile_batch
Expand All @@ -20,6 +19,10 @@ def perform

private

def lock_path
Rails.root.join('tmp/locks/pos-payment-reconciliation.lock')
end

def reconcile_batch
PosPaymentAttempt.unscoped.joins(:tenant).where(tenants: { status: 'active' })
.where(status: %w[submitting unknown]).where('submitted_at < ?', 1.minute.ago)
Expand Down
9 changes: 7 additions & 2 deletions web/app/services/host_vitals.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ def cgroup_cpu_usec

# Without a cgroup (a laptop, say): the one-minute load average as a share of the cores.
def load_percent
load1 = File.read('/proc/loadavg').split.first.to_f
load1 = read_host_file('/proc/loadavg').split.first.to_f
[(load1 / Etc.nprocessors * 100).round, 100].min
rescue SystemCallError, ZeroDivisionError
nil
end

def memory_percent
info = File.read('/proc/meminfo').lines.to_h do |line|
info = read_host_file('/proc/meminfo').lines.to_h do |line|
key, value = line.split(':')
[key, value.to_i]
end
Expand All @@ -86,6 +86,11 @@ def memory_percent
nil
end

# Linux-only /proc files; tests stub this so the parsing is checked on any host.
def read_host_file(path)
File.read(path)
end

# Use of the filesystem holding the database, as df reports it.
def disk_percent
output = IO.popen(['df', '-Pk', database_path.dirname.to_s], err: File::NULL, &:read)
Expand Down
6 changes: 5 additions & 1 deletion web/app/services/instance_overview.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@ def instance
end

def deployment_label
value = ENV['RUPERT_INSTANCE_LABEL'].to_s.strip
# Read as UTF-8 whatever the server's locale; under a C/POSIX locale ENV values arrive as binary.
value = ENV['RUPERT_INSTANCE_LABEL'].to_s.dup.force_encoding(Encoding::UTF_8)
return 'Not configured' unless value.valid_encoding?

value = value.strip
value.present? && value.length <= 80 && !value.match?(/[\x00-\x1f\x7f]/) ? value : 'Not configured'
end

Expand Down
2 changes: 2 additions & 0 deletions web/test/integration/platform_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,8 @@ class PlatformTest < ActionDispatch::IntegrationTest
%w[PRIVATE_SYNC_DETAILS PRIVATE_BACKUP_FILENAME PRIVATE_BACKUP_LINK].each { |value| refute_includes response.body, value }
ENV['RUPERT_INSTANCE_LABEL'] = "Invalid\nlabel"
assert_equal 'Not configured', InstanceOverview.call(actor: @owner)[:instance][:label]
ENV['RUPERT_INSTANCE_LABEL'] = "Not UTF-8 \xFF".b
assert_equal 'Not configured', InstanceOverview.call(actor: @owner)[:instance][:label]
ensure
ENV['RUPERT_INSTANCE_LABEL'] = old_label
end
Expand Down
35 changes: 32 additions & 3 deletions web/test/services/host_vitals_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,41 @@
require 'test_helper'

class HostVitalsTest < ActiveSupport::TestCase
test 'reads load, memory, disk and database size from this host' do
# /proc is Linux-only, so these readings are stubbed and the parsing is checked on any host (CI or a Mac).
PROC_FILES = {
'/proc/loadavg' => "1.50 0.80 0.40 2/345 6789\n",
'/proc/meminfo' => "MemTotal: 16000000 kB\nMemFree: 2000000 kB\nMemAvailable: 4000000 kB\n"
}.freeze

test 'reads load, memory, disk and database size' do
HostVitals.stub(:cgroup_cpu_usec, nil) do
HostVitals.stub(:read_host_file, ->(path) { PROC_FILES.fetch(path) }) do
Etc.stub(:nprocessors, 4) do
reading = HostVitals.read
assert_equal 38, reading.cpu, 'one-minute load 1.5 on 4 cores'
assert_equal 75, reading.memory, '12 of 16 GB in use'
assert reading.disk.between?(0, 100)
assert reading.db_bytes.positive?
end
end
end
end

test 'a reading this host cannot take is nil, never 0' do
HostVitals.stub(:cgroup_cpu_usec, nil) do
HostVitals.stub(:read_host_file, ->(path) { raise Errno::ENOENT, path }) do
reading = HostVitals.read
assert_nil reading.cpu
assert_nil reading.memory
end
end
end

test 'reads CPU and memory from a real Linux host' do
skip 'needs Linux /proc' unless File.readable?('/proc/meminfo')
reading = HostVitals.read
assert_kind_of Integer, reading.cpu
assert reading.memory.between?(0, 100)
assert reading.disk.between?(0, 100)
assert reading.db_bytes.positive?
end

test 'CPU is this container\'s own CPU time, not the host load average' do
Expand Down
8 changes: 7 additions & 1 deletion web/test/services/pos_card_payment_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
require 'test_helper'
class PosCardPaymentTest < ActiveSupport::TestCase
setup do
# Parallel test workers would otherwise share the job's one lock file, and a job that finds it held skips its sweep.
@lock_dir = Dir.mktmpdir('pos-reconciliation-lock')
PosPaymentReconciliationJob.any_instance.stubs(:lock_path).returns(Pathname(@lock_dir).join('reconciliation.lock'))
Current.tenant = tenants(:default_tenant)
@location = Location.create!(source: 'ctrax', externalId: 'card-fixture/1', name: 'Card fixture')
@user = users(:regular_user)
Expand Down Expand Up @@ -40,7 +43,10 @@ class PosCardPaymentTest < ActiveSupport::TestCase
{ status: 200, headers: { 'Content-Type' => 'application/json' }, body: data.merge(messages: { resultCode: 'Ok' }).to_json }
end
end
teardown { Current.reset }
teardown do
Current.reset
FileUtils.rm_rf(@lock_dir)
end

test 'reconciliation rotates past unresolved attempts without sending charges' do
51.times do |i|
Expand Down
Loading