Skip to content

Commit

Permalink
Add CLI support to the project
Browse files Browse the repository at this point in the history
A nice feature to add (plus it gave us some exposure to a couple of new cool tools) was to allow users of the demo app to change the port used by Sinatra. It defaults to 4567, and it's unlikely someone would already be running something on that already.

But just in case we've added the ability to specify a custom port in the app. We've done this by adding [Thor](https://github.com/erikhuda/thor) as a dependency. Thor is a toolkit for building powerful command-line interfaces. In our case it allowed us to

- add a default command
- add a description for that command
- add help on how to use the command
- add support for a custom argument (`--port`)
- add an alias for the custom argument (`-p`)
- add help on how to the custom argument

This meant some refactoring in the project, mainly dropping the `Run` class in favour of a `CLI` class that inherits from Thor.

The second cool tool we added was [Aruba](https://github.com/cucumber/aruba). Aruba allows you to test command-line applications with Cucumber-Ruby, RSpec or Minitest. It essentially runs your app in a separate process but still allows you to make assertions against the behaviour of it.

The one issue we faced was that because it runs things in a separate process, [Simplecov](https://github.com/colszowka/simplecov) was not seeing that certain lines did have test coverage. So a final change was to resolve this based a stackoverflow post we found (https://stackoverflow.com/a/20505441).

So TL;DR

- the app has a proper CLI
- the app has tests for its CLI
  • Loading branch information
Cruikshanks committed Sep 8, 2019
1 parent 1cd35c2 commit a0f9f60
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 9 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A Sinatra web app packaged as a gem that is used to demonstrate https://github/DEFRA/quke

## Installation
## Installating the app

Add this line to your application's Gemfile

Expand All @@ -22,6 +22,20 @@ Or install it yourself as:
gem install quke-demo-app
```

## Running the app

Run the app with its default port of **4567** using

```bash
quke_demo_app
```

You can change the port used if there is an issue with the default

```bash
quke_demo_app --port 9876
```

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
Expand Down
38 changes: 37 additions & 1 deletion exe/quke_demo_app
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
#!/usr/bin/env ruby

# When testing with Aruba we are actually running the gem under a separate
# process. This means though we are running a test that is exercising our code
# simplecov doesn't see it.
#
# So I managed to come across a way to do this, but essentially it means
# inserting test code into our normal production app code. Essentially if the
# env var `COVERAGE` is set we require and let Simplecov know of the details of
# our process, so it can then record which lines were covered and merge the
# results with our standard RSpec tests.
#
# The issue of working with Aruba and Simplecov in this way is covered here
# https://github.com/colszowka/simplecov/issues/234
# The solution details were mainly taken from here
# https://stackoverflow.com/a/20505441
if ENV["COVERAGE"]
require "simplecov"

# Each time this process is started we're telling Simplecov about it, and
# giving it a unique name so the results don't get overidden. We've tweaked
# how we name the process based on https://stackoverflow.com/a/22018887/6117745
# We also found that each time RSpec was run Simeplcov was both recording
# new results, and merging them in with the results of previous runs. The
# tweak we made was to mix the name of our app with the args passed in to give
# us something that would still allow for the different tests to be recorded
# separately, but also could be matched and overidden on subsequent RSpec
# runs.
SimpleCov.command_name "quke_demo_app #{ARGV.join(' ')}"

# Comments taken from original post. It certainly doesnt work without it!
# > When running with aruba simplecov was using /tmp/aruba as the root folder.
# > This is to force using the project folder
SimpleCov.root(File.dirname(__dir__))

SimpleCov.start
end

require_relative "../lib/quke/demo_app"

Quke::DemoApp::Runner.run(ARGV)
Quke::DemoApp::Cli.start
7 changes: 1 addition & 6 deletions lib/quke/demo_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,10 @@

require_relative "demo_app/concerns/can_have_search_results"
require_relative "demo_app/app"
require_relative "demo_app/cli"

module Quke
module DemoApp
# The DemoApp namespace
class Runner
def self.run(_args = [])
puts "Hello, you're running your web app from a gem!"
Quke::DemoApp::App.run!
end
end
end
end
19 changes: 19 additions & 0 deletions lib/quke/demo_app/cli.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

require "thor"

module Quke
module DemoApp
class Cli < Thor
desc("execute", "Start the demo app running")
option(:port, aliases: "-p", desc: "Port to run the app on", default: "4567")
def execute
puts "Warming up the Quke Demo App. Hold on!"
Quke::DemoApp::App.set(port: options[:port])
Quke::DemoApp::App.run!
end

default_task :execute
end
end
end
8 changes: 7 additions & 1 deletion quke_demo_app.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,20 @@ Gem::Specification.new do |spec|
end

spec.bindir = "exe"
# spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.executables = ["quke_demo_app"]
spec.default_executable = "quke_demo_app"

# Sinatra is a DSL for quickly creating web applications in Ruby with minimal
# effort. We've used it for creating our demo website
spec.add_dependency "sinatra"
# Thor is a toolkit for building powerful command-line interfaces.
spec.add_dependency "thor"

# Test command-line applications with Cucumber-Ruby or RSpec
spec.add_development_dependency "aruba"
# Cucumber is a tool for running automated tests written in plain language.
# It works with Aruba in our case to allow us to run tests through the CLI
spec.add_development_dependency "cucumber"
spec.add_development_dependency "defra_ruby_style"
# Allows us to automatically generate the change log from the tags, issues,
# labels and pull requests on GitHub. Added as a dependency so all dev's have
Expand Down
35 changes: 35 additions & 0 deletions spec/quke/demo_app/cli_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

require "spec_helper"

module Quke
module DemoApp
# We make use of https://github.com/cucumber/aruba here to allow us to test
# the CLI for our demo app. Because we are kicking off a long lived process
# (Sinatra web server) we need someway to kill the process but still
# capture a result. That's what the `exit_timeout` arg does for us.
RSpec.describe Cli, type: :aruba, exit_timeout: 2 do
context "Start the demo app" do
let(:port_args) { "" }
before(:each) do
# We have to set the env var to invoke the simplecov section of our
# quke_demo_app exe file in order to capture test coverage accurately.
# set_environment_variable() is a method provided by Aruba, as is
# run_command
set_environment_variable("COVERAGE", "true")
run_command("exe/quke_demo_app #{port_args}")
end

it { expect(last_command_started).to be_successfully_executed }
it { expect(last_command_started).to have_output(/has taken the stage on 4567/) }

context "and set a custom port" do
let(:port_args) { "--port 9876" }

it { expect(last_command_started).to be_successfully_executed }
it { expect(last_command_started).to have_output(/has taken the stage on 9876/) }
end
end
end
end
end
3 changes: 3 additions & 0 deletions spec/support/aruba.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

require "aruba/rspec"

0 comments on commit a0f9f60

Please sign in to comment.