From b55e8b2a7f0c82333668ee9967adf22f6fc934fd Mon Sep 17 00:00:00 2001 From: Micah Geisel Date: Tue, 13 Jan 2026 13:48:14 -0600 Subject: [PATCH] acceptance tests for the remaining commands, need to not actually exec in order to get test coverage. --- features/list.feature | 28 ++++++++++++ features/logs.feature | 52 +++++++++++++++++++++++ features/status.feature | 46 ++++++++++++++++++++ features/step_definitions/procsd_steps.rb | 18 ++++++++ features/support/Dockerfile | 12 +++++- lib/procsd/cli.rb | 3 +- 6 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 features/list.feature create mode 100644 features/logs.feature create mode 100644 features/status.feature diff --git a/features/list.feature b/features/list.feature new file mode 100644 index 0000000..242f63e --- /dev/null +++ b/features/list.feature @@ -0,0 +1,28 @@ +Feature: List command + As a developer + I want to list all my application services + So that I can see what services are configured + + Scenario: Shows all services + Given a procsd.yml with: + """ + app: myapp + formation: web=1,worker=2 + environment: + PORT: 3000 + processes: + web: + ExecStart: /bin/sleep infinity + worker: + ExecStart: /bin/sleep infinity + """ + When I run "procsd create" + Then the command should succeed + When I run "procsd list" + Then the command should succeed with: + """ + myapp.target + ○ ├─myapp-web.1.service + ○ ├─myapp-worker.1.service + ○ └─myapp-worker.2.service + """ diff --git a/features/logs.feature b/features/logs.feature new file mode 100644 index 0000000..20b8cc8 --- /dev/null +++ b/features/logs.feature @@ -0,0 +1,52 @@ +Feature: Logs command + As a developer + I want to view logs from my application services + So that I can debug and monitor my application + + Scenario: Shows service logs + Given a procsd.yml with: + """ + app: myapp + formation: web=1 + environment: + PORT: 3000 + processes: + web: + ExecStart: ruby -e "STDOUT.sync=true; puts :ServiceStarted; sleep" + """ + When I run "procsd create" + Then the command should succeed + When I run "procsd start" + Then the command should succeed + When I wait 2 seconds + When I run "procsd logs -n 10" + Then the command should succeed + And the output should match patterns: + """ + \d{4}-\d{2}-\d{2}T\S+ myapp-web\.1\[\d+\]: ServiceStarted + """ + + Scenario: Shows logs for a specific service + Given a procsd.yml with: + """ + app: myapp + formation: web=1,worker=1 + environment: + PORT: 3000 + processes: + web: + ExecStart: ruby -e "STDOUT.sync=true; puts :WebStarted; sleep" + worker: + ExecStart: ruby -e "STDOUT.sync=true; puts :WorkerStarted; sleep" + """ + When I run "procsd create" + Then the command should succeed + When I run "procsd start" + Then the command should succeed + When I wait 2 seconds + When I run "procsd logs web -n 10" + Then the command should succeed + And the output should match patterns: + """ + \d{4}-\d{2}-\d{2}T\S+ myapp-web\.1\[\d+\]: WebStarted + """ diff --git a/features/status.feature b/features/status.feature new file mode 100644 index 0000000..692cddd --- /dev/null +++ b/features/status.feature @@ -0,0 +1,46 @@ +Feature: Status command + As a developer + I want to check the status of my application services + So that I can see if they are running correctly + + Scenario: Shows service status + Given a procsd.yml with: + """ + app: myapp + formation: web=1 + environment: + PORT: 3000 + processes: + web: + ExecStart: /bin/sleep infinity + """ + When I run "procsd create" + Then the command should succeed + When I run "procsd start" + Then the command should succeed + When I run "procsd status --short" + Then the command should succeed with: + """ + myapp-web.1.service loaded active running myapp-web.1.service + """ + + Scenario: Shows target status with --target option + Given a procsd.yml with: + """ + app: myapp + formation: web=1 + environment: + PORT: 3000 + processes: + web: + ExecStart: /bin/sleep infinity + """ + When I run "procsd create" + Then the command should succeed + When I run "procsd start" + Then the command should succeed + When I run "procsd status --target --short" + Then the command should succeed with: + """ + myapp.target loaded active active myapp.target + """ diff --git a/features/step_definitions/procsd_steps.rb b/features/step_definitions/procsd_steps.rb index 2b84bb7..df3226b 100644 --- a/features/step_definitions/procsd_steps.rb +++ b/features/step_definitions/procsd_steps.rb @@ -6,6 +6,10 @@ @container.write_file("/home/testuser/myapp/Procfile", content) end +When("I wait {int} seconds") do |seconds| + sleep(seconds) +end + When("I run {string}") do |command| @result = @container.exec( "#{ContainerHelper::CONTAINER_GEM_SRC}/bin/coverage #{command}", @@ -34,6 +38,20 @@ def procsd_output expect(procsd_output).to eq(expected.strip) end +Then("the output should match patterns:") do |patterns| + output_lines = procsd_output.lines.map(&:chomp) + pattern_lines = patterns.strip.lines.map(&:strip) + + expect(output_lines.size).to eq(pattern_lines.size), + "Expected #{pattern_lines.size} lines, got #{output_lines.size}:\n#{procsd_output}" + + pattern_lines.each_with_index do |pattern, i| + regex = Regexp.new("^#{pattern}$") + expect(output_lines[i]).to match(regex), + "Line #{i + 1}: expected to match #{regex.inspect}, got #{output_lines[i].inspect}" + end +end + Then("the systemd directory should contain {string}") do |filename| files = @container.list_service_files("*") expect(files).to include(filename) diff --git a/features/support/Dockerfile b/features/support/Dockerfile index 456196e..afd577d 100644 --- a/features/support/Dockerfile +++ b/features/support/Dockerfile @@ -22,10 +22,20 @@ RUN rm -f /lib/systemd/system/multi-user.target.wants/* \ /lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* \ /lib/systemd/system/systemd-update-utmp* -# Create a test user that can run sudo without password +# Create a test user that can run sudo without password and read journal logs RUN useradd -m -s /bin/bash testuser && \ + usermod -aG systemd-journal testuser && \ echo "testuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/testuser +# Configure journald for persistent storage +RUN mkdir -p /etc/systemd/journald.conf.d && \ + echo -e "[Journal]\nStorage=persistent" > /etc/systemd/journald.conf.d/storage.conf + +# Create journal directory with correct group ownership upfront +RUN mkdir -p /var/log/journal && \ + chgrp systemd-journal /var/log/journal && \ + chmod 2755 /var/log/journal + # Install gems needed by procsd RUN gem install thor dotenv simplecov --no-document diff --git a/lib/procsd/cli.rb b/lib/procsd/cli.rb index be36205..4ed0d68 100644 --- a/lib/procsd/cli.rb +++ b/lib/procsd/cli.rb @@ -375,7 +375,8 @@ def execute(command, type: :system) when :system system *command when :exec - exec *command + system *command + exit($?.exitstatus || 1) end end