cannon 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.bundle/config +2 -0
 - data/.gitignore +4 -0
 - data/.rspec +2 -0
 - data/Gemfile +5 -0
 - data/README +3 -0
 - data/Rakefile +20 -0
 - data/bin/bundler +16 -0
 - data/bin/coderay +16 -0
 - data/bin/htmldiff +16 -0
 - data/bin/ldiff +16 -0
 - data/bin/mustache +16 -0
 - data/bin/pry +16 -0
 - data/bin/rspec +16 -0
 - data/cannon.gemspec +29 -0
 - data/lib/cannon.rb +16 -0
 - data/lib/cannon/app.rb +196 -0
 - data/lib/cannon/concerns/path_cache.rb +48 -0
 - data/lib/cannon/concerns/signature.rb +14 -0
 - data/lib/cannon/config.rb +58 -0
 - data/lib/cannon/cookie_jar.rb +99 -0
 - data/lib/cannon/handler.rb +25 -0
 - data/lib/cannon/middleware.rb +47 -0
 - data/lib/cannon/middleware/content_type.rb +15 -0
 - data/lib/cannon/middleware/cookies.rb +18 -0
 - data/lib/cannon/middleware/files.rb +33 -0
 - data/lib/cannon/middleware/flush_and_benchmark.rb +20 -0
 - data/lib/cannon/middleware/request_logger.rb +13 -0
 - data/lib/cannon/middleware/router.rb +19 -0
 - data/lib/cannon/request.rb +36 -0
 - data/lib/cannon/response.rb +165 -0
 - data/lib/cannon/route.rb +80 -0
 - data/lib/cannon/route_action.rb +92 -0
 - data/lib/cannon/version.rb +3 -0
 - data/lib/cannon/views.rb +28 -0
 - data/spec/app_spec.rb +20 -0
 - data/spec/config_spec.rb +41 -0
 - data/spec/environments_spec.rb +68 -0
 - data/spec/features/action_types_spec.rb +154 -0
 - data/spec/features/cookies_spec.rb +62 -0
 - data/spec/features/files_spec.rb +17 -0
 - data/spec/features/method_types_spec.rb +104 -0
 - data/spec/features/requests_spec.rb +59 -0
 - data/spec/features/views_spec.rb +31 -0
 - data/spec/fixtures/public/background.jpg +0 -0
 - data/spec/fixtures/views/render_test.html +1 -0
 - data/spec/fixtures/views/test.html +1 -0
 - data/spec/spec_helper.rb +98 -0
 - data/spec/support/cannon_test.rb +108 -0
 - metadata +219 -0
 
| 
         @@ -0,0 +1,62 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe 'Cookies', :cannon_app do
         
     | 
| 
      
 4 
     | 
    
         
            +
              before(:all) do
         
     | 
| 
      
 5 
     | 
    
         
            +
                cannon_app.get('/basic') do |request, response|
         
     | 
| 
      
 6 
     | 
    
         
            +
                  response.cookie(:simple, value: 'value')
         
     | 
| 
      
 7 
     | 
    
         
            +
                  response.send("cookie = #{request.cookies[:simple]}")
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                cannon_app.get('/cookies') do |request, response|
         
     | 
| 
      
 11 
     | 
    
         
            +
                  response.cookie(:remember_me, value: 'true')
         
     | 
| 
      
 12 
     | 
    
         
            +
                  response.cookie(:username, value: '"Luther;Martin"', expires: Time.new(2017, 10, 31, 10, 30, 05), httponly: true)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  response.cookie(:password, value: 'by=faith')
         
     | 
| 
      
 14 
     | 
    
         
            +
                  response.send("username = #{request.cookies[:username]}, password = #{request.cookies[:password]}, remember_me = #{request.cookies[:remember_me]}")
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                cannon_app.get('/signed') do |request, response|
         
     | 
| 
      
 18 
     | 
    
         
            +
                  response.cookie(:secure_value, value: 'SECURE', signed: true)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  response.send("secure value = #{request.cookies.signed[:secure_value]}")
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                cannon_app.listen(async: true)
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              it 'reads and writes cookies' do
         
     | 
| 
      
 26 
     | 
    
         
            +
                get '/basic'
         
     | 
| 
      
 27 
     | 
    
         
            +
                expect(response.body).to eq('cookie = ')
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                get '/basic'
         
     | 
| 
      
 30 
     | 
    
         
            +
                expect(response.body).to eq('cookie = value')
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              it 'handles cookie options' do
         
     | 
| 
      
 34 
     | 
    
         
            +
                get '/cookies'
         
     | 
| 
      
 35 
     | 
    
         
            +
                expect(response.body).to eq('username = , password = , remember_me = ')
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                expect(cookies[:username].httponly).to be true
         
     | 
| 
      
 38 
     | 
    
         
            +
                expect(cookies[:username].expires).to eq(Time.new(2017, 10, 31, 10, 30, 05))
         
     | 
| 
      
 39 
     | 
    
         
            +
                expect(cookies[:password].expires).to be nil
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                get '/cookies'
         
     | 
| 
      
 42 
     | 
    
         
            +
                expect(response.body).to eq('username = "Luther;Martin", password = by=faith, remember_me = true')
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              describe 'signed' do
         
     | 
| 
      
 46 
     | 
    
         
            +
                before(:each) do
         
     | 
| 
      
 47 
     | 
    
         
            +
                  get '/signed'
         
     | 
| 
      
 48 
     | 
    
         
            +
                  expect(response.body).to eq('secure value = ')
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                it 'will work if the cookie is not tampered' do
         
     | 
| 
      
 52 
     | 
    
         
            +
                  get '/signed'
         
     | 
| 
      
 53 
     | 
    
         
            +
                  expect(response.body).to eq('secure value = SECURE')
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                it 'will clear the cookie if the cookie is tampered' do
         
     | 
| 
      
 57 
     | 
    
         
            +
                  cookies[:secure_value].value.gsub!('SECURE', 'SeCURE')
         
     | 
| 
      
 58 
     | 
    
         
            +
                  get '/signed'
         
     | 
| 
      
 59 
     | 
    
         
            +
                  expect(response.body).to eq('secure value = ')
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe 'Files', :cannon_app do
         
     | 
| 
      
 4 
     | 
    
         
            +
              before(:all) do
         
     | 
| 
      
 5 
     | 
    
         
            +
                cannon_app.config.public_path = '../fixtures/public'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                cannon_app.listen(async: true)
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              it 'serves files' do
         
     | 
| 
      
 11 
     | 
    
         
            +
                get '/background.jpg'
         
     | 
| 
      
 12 
     | 
    
         
            +
                expect(response.body.size).to_not eq('')
         
     | 
| 
      
 13 
     | 
    
         
            +
                expect(response.code).to be(200)
         
     | 
| 
      
 14 
     | 
    
         
            +
                expect(response['Content-Type']).to eq('image/jpeg')
         
     | 
| 
      
 15 
     | 
    
         
            +
                expect(response['Content-Length']).to eq('55697')
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,104 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe 'Method types', :cannon_app do
         
     | 
| 
      
 4 
     | 
    
         
            +
              before(:all) do
         
     | 
| 
      
 5 
     | 
    
         
            +
                cannon_app.get('/hi') do |request, response|
         
     | 
| 
      
 6 
     | 
    
         
            +
                  response.send('hi')
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                cannon_app.get('/value') do |request, response|
         
     | 
| 
      
 10 
     | 
    
         
            +
                  response.send("key = #{request.params[:key]}, place = #{request.params[:place]}")
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                cannon_app.post('/hi') do |request, response|
         
     | 
| 
      
 14 
     | 
    
         
            +
                  response.send('created!', status: :created)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                cannon_app.post('/submit') do |request, response|
         
     | 
| 
      
 18 
     | 
    
         
            +
                  response.send("name=#{request.params[:name]}, age=#{request.params[:age]}")
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                cannon_app.patch('/update') do |request, response|
         
     | 
| 
      
 22 
     | 
    
         
            +
                  response.send("updated object #{request.params[:name]}")
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                cannon_app.put('/modify') do |request, response|
         
     | 
| 
      
 26 
     | 
    
         
            +
                  response.send("modified object #{request.params[:name]}")
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                cannon_app.delete('/object/:id') do |request, response|
         
     | 
| 
      
 30 
     | 
    
         
            +
                  response.send("deleted #{request.params[:id]}")
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                cannon_app.head('/object/:id') do |request, response|
         
     | 
| 
      
 34 
     | 
    
         
            +
                  response.header('ETag', "object_#{request.params[:id]}")
         
     | 
| 
      
 35 
     | 
    
         
            +
                  response.send('head body should be ignored')
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                cannon_app.all('/any') do |request, response|
         
     | 
| 
      
 39 
     | 
    
         
            +
                  response.send("request method = #{request.method}")
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                cannon_app.listen(async: true)
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              it 'handles get requests' do
         
     | 
| 
      
 46 
     | 
    
         
            +
                get '/hi'
         
     | 
| 
      
 47 
     | 
    
         
            +
                expect(response.code).to be(200)
         
     | 
| 
      
 48 
     | 
    
         
            +
                expect(response.body).to eq('hi')
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              it 'handles query params' do
         
     | 
| 
      
 52 
     | 
    
         
            +
                get '/value', key: 'a value', place: '12 ave st'
         
     | 
| 
      
 53 
     | 
    
         
            +
                expect(response.body).to eq('key = a value, place = 12 ave st')
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              it 'handles post requests' do
         
     | 
| 
      
 57 
     | 
    
         
            +
                post '/hi'
         
     | 
| 
      
 58 
     | 
    
         
            +
                expect(response.body).to eq('created!')
         
     | 
| 
      
 59 
     | 
    
         
            +
                expect(response.code).to eq(201)
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              it 'handles post params' do
         
     | 
| 
      
 63 
     | 
    
         
            +
                post('/submit', name: 'John', age: 21)
         
     | 
| 
      
 64 
     | 
    
         
            +
                expect(response.body).to eq('name=John, age=21')
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              it 'handles put requests' do
         
     | 
| 
      
 68 
     | 
    
         
            +
                put '/modify', name: 'zebra'
         
     | 
| 
      
 69 
     | 
    
         
            +
                expect(response.body).to eq('modified object zebra')
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              it 'handles patch requests' do
         
     | 
| 
      
 73 
     | 
    
         
            +
                patch '/update', name: 'lion'
         
     | 
| 
      
 74 
     | 
    
         
            +
                expect(response.body).to eq('updated object lion')
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
              it 'handles delete requests' do
         
     | 
| 
      
 78 
     | 
    
         
            +
                delete '/object/34'
         
     | 
| 
      
 79 
     | 
    
         
            +
                expect(response.body).to eq('deleted 34')
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
              describe 'head requests' do
         
     | 
| 
      
 83 
     | 
    
         
            +
                it 'handles head request headers' do
         
     | 
| 
      
 84 
     | 
    
         
            +
                  head '/object/45'
         
     | 
| 
      
 85 
     | 
    
         
            +
                  expect(response.headers['etag']).to eq('object_45')
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                it 'does not return a body' do
         
     | 
| 
      
 89 
     | 
    
         
            +
                  head '/object/45'
         
     | 
| 
      
 90 
     | 
    
         
            +
                  expect(response.body).to be_nil
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
              end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
              it 'can be configured to handle all methods for routes' do
         
     | 
| 
      
 95 
     | 
    
         
            +
                get '/any'
         
     | 
| 
      
 96 
     | 
    
         
            +
                expect(response.body).to eq('request method = GET')
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                post '/any'
         
     | 
| 
      
 99 
     | 
    
         
            +
                expect(response.body).to eq('request method = POST')
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                put '/any'
         
     | 
| 
      
 102 
     | 
    
         
            +
                expect(response.body).to eq('request method = PUT')
         
     | 
| 
      
 103 
     | 
    
         
            +
              end
         
     | 
| 
      
 104 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,59 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe 'Requests', :cannon_app do
         
     | 
| 
      
 4 
     | 
    
         
            +
              before(:all) do
         
     | 
| 
      
 5 
     | 
    
         
            +
                cannon_app.get('/basic') do |request, response|
         
     | 
| 
      
 6 
     | 
    
         
            +
                  response.send('hi')
         
     | 
| 
      
 7 
     | 
    
         
            +
                end.handle do |request, response|
         
     | 
| 
      
 8 
     | 
    
         
            +
                  response.send(' how are you?')
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                cannon_app.get('/bad') do |response, request|
         
     | 
| 
      
 12 
     | 
    
         
            +
                  bad_fail_code
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                cannon_app.get('/resource/:id') do |request, response|
         
     | 
| 
      
 16 
     | 
    
         
            +
                  response.send("id = #{request.params[:id]}")
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                cannon_app.get('/:type/by-grouping/:grouping') do |request, response|
         
     | 
| 
      
 20 
     | 
    
         
            +
                  response.send("type=#{request.params[:type]}, grouping=#{request.params[:grouping]}, sort=#{request.params[:sort]}")
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                cannon_app.get('/object/:id') do |request, response|
         
     | 
| 
      
 24 
     | 
    
         
            +
                  response.send("view #{request.params[:id]}")
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                cannon_app.listen(async: true)
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              it 'sets the Content-Type' do
         
     | 
| 
      
 31 
     | 
    
         
            +
                get '/basic'
         
     | 
| 
      
 32 
     | 
    
         
            +
                expect(response['Content-Type']).to eq('text/plain; charset=us-ascii')
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              it 'sets the Content-Length' do
         
     | 
| 
      
 36 
     | 
    
         
            +
                get '/basic'
         
     | 
| 
      
 37 
     | 
    
         
            +
                expect(response['Content-Length']).to eq('15')
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              it 'handles params in routes' do
         
     | 
| 
      
 41 
     | 
    
         
            +
                get '/resource/12'
         
     | 
| 
      
 42 
     | 
    
         
            +
                expect(response.body).to eq('id = 12')
         
     | 
| 
      
 43 
     | 
    
         
            +
                get '/messages/by-grouping/author', sort: 'name'
         
     | 
| 
      
 44 
     | 
    
         
            +
                expect(response.body).to eq('type=messages, grouping=author, sort=name')
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              it 'returns 404 for not found routes' do
         
     | 
| 
      
 48 
     | 
    
         
            +
                get '/badroute'
         
     | 
| 
      
 49 
     | 
    
         
            +
                expect(response.code).to be(404)
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              it 'returns 500 for errors' do
         
     | 
| 
      
 53 
     | 
    
         
            +
                old_log_level = Cannon.config.log_level
         
     | 
| 
      
 54 
     | 
    
         
            +
                Cannon.config.log_level = :fatal
         
     | 
| 
      
 55 
     | 
    
         
            +
                get '/bad'
         
     | 
| 
      
 56 
     | 
    
         
            +
                expect(response.code).to be(500)
         
     | 
| 
      
 57 
     | 
    
         
            +
                Cannon.config.log_level = old_log_level
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe 'Views', :cannon_app do
         
     | 
| 
      
 4 
     | 
    
         
            +
              before(:all) do
         
     | 
| 
      
 5 
     | 
    
         
            +
                cannon_app.config.view_path = '../fixtures/views'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                cannon_app.get('/view') do |request, response|
         
     | 
| 
      
 8 
     | 
    
         
            +
                  response.view('test.html')
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                cannon_app.get('/render') do |request, response|
         
     | 
| 
      
 12 
     | 
    
         
            +
                  response.view('render_test.html', name: 'John Calvin')
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                cannon_app.listen(async: true)
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              describe 'rendering' do
         
     | 
| 
      
 19 
     | 
    
         
            +
                it 'handles plain text' do
         
     | 
| 
      
 20 
     | 
    
         
            +
                  get '/view'
         
     | 
| 
      
 21 
     | 
    
         
            +
                  expect(response.body).to eq('Test view content')
         
     | 
| 
      
 22 
     | 
    
         
            +
                  expect(response.code).to be(200)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  expect(response['Content-Type']).to eq('text/html')
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                it 'handles mustache templates' do
         
     | 
| 
      
 27 
     | 
    
         
            +
                  get '/render'
         
     | 
| 
      
 28 
     | 
    
         
            +
                  expect(response.body).to eq('Hello John Calvin')
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         Binary file 
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Hello {{name}}
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Test view content
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,98 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'cannon'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            # This file was generated by the `rspec --init` command. Conventionally, all
         
     | 
| 
      
 4 
     | 
    
         
            +
            # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
         
     | 
| 
      
 5 
     | 
    
         
            +
            # The generated `.rspec` file contains `--require spec_helper` which will cause
         
     | 
| 
      
 6 
     | 
    
         
            +
            # this file to always be loaded, without a need to explicitly require it in any
         
     | 
| 
      
 7 
     | 
    
         
            +
            # files.
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            # Given that it is always loaded, you are encouraged to keep this file as
         
     | 
| 
      
 10 
     | 
    
         
            +
            # light-weight as possible. Requiring heavyweight dependencies from this file
         
     | 
| 
      
 11 
     | 
    
         
            +
            # will add to the boot time of your test suite on EVERY test run, even for an
         
     | 
| 
      
 12 
     | 
    
         
            +
            # individual file that may not need all of that loaded. Instead, consider making
         
     | 
| 
      
 13 
     | 
    
         
            +
            # a separate helper file that requires the additional dependencies and performs
         
     | 
| 
      
 14 
     | 
    
         
            +
            # the additional setup, and require it from the spec files that actually need
         
     | 
| 
      
 15 
     | 
    
         
            +
            # it.
         
     | 
| 
      
 16 
     | 
    
         
            +
            #
         
     | 
| 
      
 17 
     | 
    
         
            +
            # The `.rspec` file also contains a few flags that are not defaults but that
         
     | 
| 
      
 18 
     | 
    
         
            +
            # users commonly want.
         
     | 
| 
      
 19 
     | 
    
         
            +
            #
         
     | 
| 
      
 20 
     | 
    
         
            +
            # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            # Require support files
         
     | 
| 
      
 23 
     | 
    
         
            +
            Dir[Dir.getwd + '/spec/support/**/*.rb'].each { |f| require f }
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            RSpec.configure do |config|
         
     | 
| 
      
 26 
     | 
    
         
            +
              # rspec-expectations config goes here. You can use an alternate
         
     | 
| 
      
 27 
     | 
    
         
            +
              # assertion/expectation library such as wrong or the stdlib/minitest
         
     | 
| 
      
 28 
     | 
    
         
            +
              # assertions if you prefer.
         
     | 
| 
      
 29 
     | 
    
         
            +
              config.expect_with :rspec do |expectations|
         
     | 
| 
      
 30 
     | 
    
         
            +
                # This option will default to `true` in RSpec 4. It makes the `description`
         
     | 
| 
      
 31 
     | 
    
         
            +
                # and `failure_message` of custom matchers include text for helper methods
         
     | 
| 
      
 32 
     | 
    
         
            +
                # defined using `chain`, e.g.:
         
     | 
| 
      
 33 
     | 
    
         
            +
                #     be_bigger_than(2).and_smaller_than(4).description
         
     | 
| 
      
 34 
     | 
    
         
            +
                #     # => "be bigger than 2 and smaller than 4"
         
     | 
| 
      
 35 
     | 
    
         
            +
                # ...rather than:
         
     | 
| 
      
 36 
     | 
    
         
            +
                #     # => "be bigger than 2"
         
     | 
| 
      
 37 
     | 
    
         
            +
                expectations.include_chain_clauses_in_custom_matcher_descriptions = true
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              # rspec-mocks config goes here. You can use an alternate test double
         
     | 
| 
      
 41 
     | 
    
         
            +
              # library (such as bogus or mocha) by changing the `mock_with` option here.
         
     | 
| 
      
 42 
     | 
    
         
            +
              config.mock_with :rspec do |mocks|
         
     | 
| 
      
 43 
     | 
    
         
            +
                # Prevents you from mocking or stubbing a method that does not exist on
         
     | 
| 
      
 44 
     | 
    
         
            +
                # a real object. This is generally recommended, and will default to
         
     | 
| 
      
 45 
     | 
    
         
            +
                # `true` in RSpec 4.
         
     | 
| 
      
 46 
     | 
    
         
            +
                mocks.verify_partial_doubles = true
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              # These two settings work together to allow you to limit a spec run
         
     | 
| 
      
 50 
     | 
    
         
            +
              # to individual examples or groups you care about by tagging them with
         
     | 
| 
      
 51 
     | 
    
         
            +
              # `:focus` metadata. When nothing is tagged with `:focus`, all examples
         
     | 
| 
      
 52 
     | 
    
         
            +
              # get run.
         
     | 
| 
      
 53 
     | 
    
         
            +
              config.filter_run :focus
         
     | 
| 
      
 54 
     | 
    
         
            +
              config.run_all_when_everything_filtered = true
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              # Allows RSpec to persist some state between runs in order to support
         
     | 
| 
      
 57 
     | 
    
         
            +
              # the `--only-failures` and `--next-failure` CLI options. We recommend
         
     | 
| 
      
 58 
     | 
    
         
            +
              # you configure your source control system to ignore this file.
         
     | 
| 
      
 59 
     | 
    
         
            +
              config.example_status_persistence_file_path = "spec/examples.txt"
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              # Limits the available syntax to the non-monkey patched syntax that is
         
     | 
| 
      
 62 
     | 
    
         
            +
              # recommended. For more details, see:
         
     | 
| 
      
 63 
     | 
    
         
            +
              #   - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
         
     | 
| 
      
 64 
     | 
    
         
            +
              #   - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
         
     | 
| 
      
 65 
     | 
    
         
            +
              #   - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
         
     | 
| 
      
 66 
     | 
    
         
            +
              config.disable_monkey_patching!
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              # This setting enables warnings. It's recommended, but in some cases may
         
     | 
| 
      
 69 
     | 
    
         
            +
              # be too noisy due to issues in dependencies.
         
     | 
| 
      
 70 
     | 
    
         
            +
              # config.warnings = true
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              # Many RSpec users commonly either run the entire suite or an individual
         
     | 
| 
      
 73 
     | 
    
         
            +
              # file, and it's useful to allow more verbose output when running an
         
     | 
| 
      
 74 
     | 
    
         
            +
              # individual spec file.
         
     | 
| 
      
 75 
     | 
    
         
            +
              if config.files_to_run.one?
         
     | 
| 
      
 76 
     | 
    
         
            +
                # Use the documentation formatter for detailed output,
         
     | 
| 
      
 77 
     | 
    
         
            +
                # unless a formatter has already been configured
         
     | 
| 
      
 78 
     | 
    
         
            +
                # (e.g. via a command-line flag).
         
     | 
| 
      
 79 
     | 
    
         
            +
                config.default_formatter = 'doc'
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
              # Print the 10 slowest examples and example groups at the
         
     | 
| 
      
 83 
     | 
    
         
            +
              # end of the spec run, to help surface which specs are running
         
     | 
| 
      
 84 
     | 
    
         
            +
              # particularly slow.
         
     | 
| 
      
 85 
     | 
    
         
            +
              # config.profile_examples = 10
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
              # Run specs in random order to surface order dependencies. If you find an
         
     | 
| 
      
 88 
     | 
    
         
            +
              # order dependency and want to debug it, you can fix the order by providing
         
     | 
| 
      
 89 
     | 
    
         
            +
              # the seed, which is printed after each run.
         
     | 
| 
      
 90 
     | 
    
         
            +
              #     --seed 1234
         
     | 
| 
      
 91 
     | 
    
         
            +
              config.order = :random
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
              # Seed global randomization in this process using the `--seed` CLI option.
         
     | 
| 
      
 94 
     | 
    
         
            +
              # Setting this allows you to use `--seed` to deterministically reproduce
         
     | 
| 
      
 95 
     | 
    
         
            +
              # test failures related to randomization by passing the same `--seed` value
         
     | 
| 
      
 96 
     | 
    
         
            +
              # as the one that triggered the failure.
         
     | 
| 
      
 97 
     | 
    
         
            +
              Kernel.srand config.seed
         
     | 
| 
      
 98 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,108 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'http-cookie'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class MockResponse
         
     | 
| 
      
 4 
     | 
    
         
            +
              def initialize(response)
         
     | 
| 
      
 5 
     | 
    
         
            +
                @response = response
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              def code
         
     | 
| 
      
 9 
     | 
    
         
            +
                @response.code.to_i
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              def headers
         
     | 
| 
      
 13 
     | 
    
         
            +
                @headers ||= build_headers
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              def method_missing(sym, *args, &block)
         
     | 
| 
      
 17 
     | 
    
         
            +
                @response.send(sym, *args, &block)
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            private
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              def build_headers
         
     | 
| 
      
 23 
     | 
    
         
            +
                headers = {}
         
     | 
| 
      
 24 
     | 
    
         
            +
                each_header { |k, v| headers[k] = v }
         
     | 
| 
      
 25 
     | 
    
         
            +
                headers
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            module Cannon::Test
         
     | 
| 
      
 30 
     | 
    
         
            +
              PORT = 5031
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              def cannon_app
         
     | 
| 
      
 33 
     | 
    
         
            +
                @cannon_app ||= create_cannon_app
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              def get(path, params = {})
         
     | 
| 
      
 37 
     | 
    
         
            +
                http_request(path, Net::HTTP::Get, query_params: params)
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              def post(path, params = {})
         
     | 
| 
      
 41 
     | 
    
         
            +
                http_request(path, Net::HTTP::Post, post_params: params)
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              def put(path, params = {})
         
     | 
| 
      
 45 
     | 
    
         
            +
                http_request(path, Net::HTTP::Put, post_params: params)
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
              def patch(path, params = {})
         
     | 
| 
      
 49 
     | 
    
         
            +
                http_request(path, Net::HTTP::Patch, post_params: params)
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              def delete(path, params = {})
         
     | 
| 
      
 53 
     | 
    
         
            +
                http_request(path, Net::HTTP::Delete, post_params: params)
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              def head(path, params = {})
         
     | 
| 
      
 57 
     | 
    
         
            +
                http_request(path, Net::HTTP::Head, query_params: params)
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              def response
         
     | 
| 
      
 61 
     | 
    
         
            +
                @response
         
     | 
| 
      
 62 
     | 
    
         
            +
              end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
              def cookies
         
     | 
| 
      
 65 
     | 
    
         
            +
                jar.inject({}) { |cookies, cookie| cookies[cookie.name.to_sym] = cookie; cookies }
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              def jar
         
     | 
| 
      
 69 
     | 
    
         
            +
                @jar ||= HTTP::CookieJar.new
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            private
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              def http_request(path, request_class, post_params: nil, query_params: nil)
         
     | 
| 
      
 75 
     | 
    
         
            +
                uri = URI("http://127.0.0.1:#{PORT}#{path}")
         
     | 
| 
      
 76 
     | 
    
         
            +
                uri.query = URI.encode_www_form(query_params) unless query_params.nil?
         
     | 
| 
      
 77 
     | 
    
         
            +
                req = request_class.new(uri)
         
     | 
| 
      
 78 
     | 
    
         
            +
                req.set_form_data(post_params) unless post_params.nil?
         
     | 
| 
      
 79 
     | 
    
         
            +
                req['Cookie'] = HTTP::Cookie.cookie_value(jar.cookies(uri)) unless jar.empty?
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                @response = MockResponse.new(Net::HTTP.start(uri.hostname, uri.port) do |http|
         
     | 
| 
      
 82 
     | 
    
         
            +
                  http.request(req)
         
     | 
| 
      
 83 
     | 
    
         
            +
                end)
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                if @response['Set-Cookie']
         
     | 
| 
      
 86 
     | 
    
         
            +
                  @response.get_fields('Set-Cookie').each do |cookie|
         
     | 
| 
      
 87 
     | 
    
         
            +
                    jar.parse(cookie, uri)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              def create_cannon_app
         
     | 
| 
      
 93 
     | 
    
         
            +
                app = Cannon::App.new(binding, port: PORT, ip_address: '127.0.0.1')
         
     | 
| 
      
 94 
     | 
    
         
            +
                app.config.log_level = :error
         
     | 
| 
      
 95 
     | 
    
         
            +
                app.config.cookies.secret = 'test'
         
     | 
| 
      
 96 
     | 
    
         
            +
                app
         
     | 
| 
      
 97 
     | 
    
         
            +
              end
         
     | 
| 
      
 98 
     | 
    
         
            +
            end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
            RSpec.configure do |config|
         
     | 
| 
      
 101 
     | 
    
         
            +
              config.include Cannon::Test
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
              config.append_after(:context, cannon_app: true) do
         
     | 
| 
      
 104 
     | 
    
         
            +
                cannon_app.stop
         
     | 
| 
      
 105 
     | 
    
         
            +
                @cannon_app = nil
         
     | 
| 
      
 106 
     | 
    
         
            +
                jar.clear
         
     | 
| 
      
 107 
     | 
    
         
            +
              end
         
     | 
| 
      
 108 
     | 
    
         
            +
            end
         
     |