test: add cli and end-to-end integration tests
This commit is contained in:
1 parent
9adaad8728
commit
28e6bc3cf2
3 files changed
+236
No files matched your search
@@ -0,0 +1,95 @@
|
||||
require 'minitest/autorun'
|
||||
require 'prism'
|
||||
require 'tmpdir'
|
||||
require 'fileutils'
|
||||
|
||||
class CliTest < Minitest::Test
|
||||
def setup
|
||||
@workdir = Dir.mktmpdir('prism-cli')
|
||||
@cli = Prism::Cli.new(@workdir)
|
||||
end
|
||||
|
||||
def teardown
|
||||
FileUtils.remove_entry(@workdir)
|
||||
end
|
||||
|
||||
def test_new_app_scaffolds_expected_files
|
||||
app_dir = @cli.new_app('blog')
|
||||
assert File.directory?(File.join(app_dir, 'app', 'controllers'))
|
||||
assert File.directory?(File.join(app_dir, 'app', 'models'))
|
||||
assert File.directory?(File.join(app_dir, 'db', 'migrate'))
|
||||
assert File.file?(File.join(app_dir, 'app.rb'))
|
||||
assert File.file?(File.join(app_dir, 'config.ru'))
|
||||
assert File.file?(File.join(app_dir, 'app', 'views', 'layouts', 'application.erb'))
|
||||
assert File.executable?(File.join(app_dir, 'bin', 'server'))
|
||||
end
|
||||
|
||||
def test_new_app_boot_file_references_app_class
|
||||
app_dir = @cli.new_app('blog')
|
||||
content = File.read(File.join(app_dir, 'app.rb'))
|
||||
assert_includes content, 'class Blog < Prism::Application'
|
||||
end
|
||||
|
||||
def test_new_app_refuses_to_overwrite_existing_directory
|
||||
@cli.new_app('blog')
|
||||
assert_raises(Prism::Cli::UsageError) { @cli.new_app('blog') }
|
||||
end
|
||||
|
||||
def test_generate_migration_for_create_table
|
||||
path = @cli.generate_migration('create_posts', ['title:string', 'body:text'])
|
||||
content = File.read(path)
|
||||
assert_includes content, 'class CreatePosts < Prism::Orm::Migration'
|
||||
assert_includes content, 'create_table :posts do |t|'
|
||||
assert_includes content, 't.string :title'
|
||||
assert_includes content, 't.text :body'
|
||||
assert_includes content, 't.timestamps'
|
||||
assert_includes content, 'drop_table :posts'
|
||||
end
|
||||
|
||||
def test_generate_migration_filename_has_version_prefix
|
||||
path = @cli.generate_migration('create_posts', [])
|
||||
assert_match(/\A\d{14}_create_posts\.rb\z/, File.basename(path))
|
||||
end
|
||||
|
||||
def test_generate_migration_avoids_version_collisions_within_the_same_second
|
||||
first = @cli.generate_migration('create_posts', [])
|
||||
second = @cli.generate_migration('create_comments', [])
|
||||
first_version = File.basename(first).split('_', 2).first
|
||||
second_version = File.basename(second).split('_', 2).first
|
||||
refute_equal first_version, second_version
|
||||
end
|
||||
|
||||
def test_generated_migration_actually_runs
|
||||
path = @cli.generate_migration('create_widgets', ['name:string'])
|
||||
store = Prism::Orm::Store.new(File.join(@workdir, 'test.pstore'))
|
||||
Prism::Orm::Migrator.new(store, File.dirname(path)).migrate!
|
||||
assert store.table_exists?(:widgets)
|
||||
assert_includes store.columns(:widgets), 'name'
|
||||
end
|
||||
|
||||
def test_generate_model_creates_model_and_migration
|
||||
model_path, migration_path = @cli.generate_model('post', ['title:string'])
|
||||
assert_includes File.read(model_path), 'class Post < Prism::Orm::Model'
|
||||
assert_includes File.read(migration_path), 'create_table :posts do |t|'
|
||||
end
|
||||
|
||||
def test_bin_prism_new_via_subprocess
|
||||
lib_dir = File.expand_path('../lib', __dir__)
|
||||
bin_path = File.expand_path('../bin/prism', __dir__)
|
||||
ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
|
||||
output = IO.popen([ruby, "-I#{lib_dir}", bin_path, 'new', 'shop'], chdir: @workdir, err: [:child, :out], &:read)
|
||||
status = $?.exitstatus
|
||||
assert_equal 0, status, output
|
||||
assert File.file?(File.join(@workdir, 'shop', 'app.rb'))
|
||||
end
|
||||
|
||||
def test_bin_prism_reports_usage_error_and_nonzero_exit
|
||||
lib_dir = File.expand_path('../lib', __dir__)
|
||||
bin_path = File.expand_path('../bin/prism', __dir__)
|
||||
ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
|
||||
output = IO.popen([ruby, "-I#{lib_dir}", bin_path, 'bogus'], chdir: @workdir, err: [:child, :out], &:read)
|
||||
status = $?.exitstatus
|
||||
refute_equal 0, status
|
||||
assert_includes output, 'unknown command'
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,53 @@
|
||||
require 'minitest/autorun'
|
||||
require 'prism'
|
||||
require 'net/http'
|
||||
|
||||
class IntegrationApp < Prism::Application
|
||||
get '/ping' do
|
||||
json(pong: true)
|
||||
end
|
||||
|
||||
get '/hello/:name' do
|
||||
json(hello: params['name'])
|
||||
end
|
||||
|
||||
post '/sum' do
|
||||
numbers = JSON.parse(request.body)
|
||||
json(sum: numbers['a'] + numbers['b'])
|
||||
end
|
||||
end
|
||||
|
||||
class IntegrationTest < Minitest::Test
|
||||
def setup
|
||||
@server = Prism::Server.new(IntegrationApp, port: 0).start
|
||||
@port = @server.port
|
||||
end
|
||||
|
||||
def teardown
|
||||
@server.stop
|
||||
end
|
||||
|
||||
def test_port_is_ephemeral
|
||||
assert @port.positive?
|
||||
end
|
||||
|
||||
def test_get_with_param
|
||||
response = Net::HTTP.get_response(URI("http://127.0.0.1:#{@port}/hello/Ruby"))
|
||||
assert_equal '200', response.code
|
||||
assert_equal({ 'hello' => 'Ruby' }, JSON.parse(response.body))
|
||||
end
|
||||
|
||||
def test_post_with_body
|
||||
uri = URI("http://127.0.0.1:#{@port}/sum")
|
||||
response = Net::HTTP.start(uri.host, uri.port) do |http|
|
||||
http.post(uri.path, JSON.generate(a: 2, b: 40), 'Content-Type' => 'application/json')
|
||||
end
|
||||
assert_equal '200', response.code
|
||||
assert_equal 42, JSON.parse(response.body)['sum']
|
||||
end
|
||||
|
||||
def test_not_found_over_http
|
||||
response = Net::HTTP.get_response(URI("http://127.0.0.1:#{@port}/nope"))
|
||||
assert_equal '404', response.code
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,88 @@
|
||||
require 'minitest/autorun'
|
||||
require 'prism'
|
||||
require 'net/http'
|
||||
require 'tmpdir'
|
||||
require 'fileutils'
|
||||
|
||||
class IntegrationOrmTest < Minitest::Test
|
||||
def setup
|
||||
@dir = Dir.mktmpdir('prism-e2e-orm')
|
||||
@db_path = File.join(@dir, 'blog.pstore')
|
||||
@views_dir = File.join(@dir, 'views', 'e2e_posts')
|
||||
FileUtils.mkdir_p(@views_dir)
|
||||
File.write(File.join(@views_dir, 'index.erb'), <<~ERB)
|
||||
<ul class="posts">
|
||||
<% posts.each do |post| %>
|
||||
<li><%= post.title %>: <%= post.body %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
ERB
|
||||
|
||||
Prism::Orm.connect(@db_path)
|
||||
Prism::Orm.store.create_table(:e2e_posts, %w[id title body created_at updated_at])
|
||||
|
||||
views_dir = File.dirname(@views_dir)
|
||||
post_class = Class.new(Prism::Orm::Model) do
|
||||
table_name :e2e_posts
|
||||
validates :title, presence: true
|
||||
end
|
||||
Object.const_set(:E2ePost, post_class)
|
||||
|
||||
controller_class = Class.new(Prism::Controller) do
|
||||
views_root views_dir
|
||||
|
||||
define_method(:index) { render(:index, locals: { posts: E2ePost.order(:id) }) }
|
||||
define_method(:create) do
|
||||
post = E2ePost.create(title: params['title'], body: params['body'])
|
||||
json({ id: post.id }, 201)
|
||||
end
|
||||
end
|
||||
Object.const_set(:E2ePostsController, controller_class)
|
||||
|
||||
app_class = Class.new(Prism::Application) do
|
||||
get '/posts', to: 'e2e_posts#index'
|
||||
post '/posts', to: 'e2e_posts#create'
|
||||
end
|
||||
Object.const_set(:E2eBlogApp, app_class)
|
||||
end
|
||||
|
||||
def teardown
|
||||
@server&.stop
|
||||
%i[E2ePost E2ePostsController E2eBlogApp].each { |name| Object.send(:remove_const, name) if Object.const_defined?(name) }
|
||||
FileUtils.remove_entry(@dir)
|
||||
end
|
||||
|
||||
def test_post_then_get_round_trip_and_survives_a_process_restart
|
||||
@server = Prism::Server.new(E2eBlogApp, port: 0).start
|
||||
port = @server.port
|
||||
|
||||
create_response = Net::HTTP.start('127.0.0.1', port) do |http|
|
||||
http.post('/posts', URI.encode_www_form(title: 'Hello Prism', body: 'first real post'),
|
||||
'Content-Type' => 'application/x-www-form-urlencoded')
|
||||
end
|
||||
assert_equal '201', create_response.code
|
||||
created_id = JSON.parse(create_response.body)['id']
|
||||
refute_nil created_id
|
||||
|
||||
listing_response = Net::HTTP.get_response(URI("http://127.0.0.1:#{port}/posts"))
|
||||
assert_equal '200', listing_response.code
|
||||
assert_includes listing_response.body, 'Hello Prism: first real post'
|
||||
|
||||
@server.stop
|
||||
@server = nil
|
||||
|
||||
# Simulate a process restart: reconnect to the same file with a brand new
|
||||
# Store instance (no shared in-memory state with the writer above) and
|
||||
# boot a second, independent server against it.
|
||||
Prism::Orm.connect(@db_path)
|
||||
restarted_server = Prism::Server.new(E2eBlogApp, port: 0).start
|
||||
begin
|
||||
restarted_response = Net::HTTP.get_response(URI("http://127.0.0.1:#{restarted_server.port}/posts"))
|
||||
assert_equal '200', restarted_response.code
|
||||
assert_includes restarted_response.body, 'Hello Prism: first real post',
|
||||
'data inserted before the restart must still render after reconnecting to the store file'
|
||||
ensure
|
||||
restarted_server.stop
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user