contracto 0.4.2 → 0.4.3
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 +4 -4
- data/README.md +2 -4
- data/lib/contracto/command/init.rb +1 -1
- data/lib/contracto/command/start.rb +1 -0
- data/lib/contracto/command/stop.rb +1 -0
- data/lib/contracto/config.rb +5 -6
- data/lib/contracto/contract.rb +4 -17
- data/lib/contracto/contract/request.rb +61 -0
- data/lib/contracto/contract/response.rb +1 -12
- data/lib/contracto/errors.rb +3 -0
- data/lib/contracto/server.rb +31 -0
- data/lib/contracto/server/contract_routes.rb +22 -0
- data/lib/contracto/server/controller.rb +75 -0
- data/lib/contracto/stats.rb +34 -1
- data/lib/contracto/system_action.rb +10 -38
- data/lib/contracto/version.rb +1 -1
- data/spec/fixtures/{get_users_by_id.con.json → get_user_by_id.contract.json} +6 -4
- data/spec/fixtures/{get_users.con.json → get_users.contract.json} +6 -4
- data/spec/fixtures/{post_users.con.json → post_users.contract.json} +6 -4
- metadata +12 -12
- data/lib/contracto/server/ruby/config.ru +0 -5
- data/lib/contracto/server/ruby/server.rb +0 -66
- data/spec/fixtures/my_data.con.json +0 -23
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 893f39a06bea5e901e247bab7d2de6c37a3a0825
         | 
| 4 | 
            +
              data.tar.gz: 1b8741717d48f6fa368529bfdd0c1c5815d67ba1
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 18efae1e83e4e38f7746080e0626c18207775f0edd47e5a6b359b66e9266ed57f85b405c38cb977aa22eab1b2b1dfc831f46af2868d76b6a668ab85c7b9385dd
         | 
| 7 | 
            +
              data.tar.gz: 975b7ee12c51b0e6d77ea83d1c6510beae86243e872801d3c83b961e3b8d7da17c038234af37bbb72e380dac0644a384c3a4a056b3810e2a1c5afc38f3e1e924
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            # IN DEVELOPMENT
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            # Contracto
         | 
| 4 2 |  | 
| 5 3 | 
             
            Creates HTTP server based on your contract.
         | 
| @@ -12,11 +10,11 @@ Creates HTTP server based on your contract. | |
| 12 10 |  | 
| 13 11 | 
             
            Start server:
         | 
| 14 12 |  | 
| 15 | 
            -
                $ contracto start  | 
| 13 | 
            +
                $ contracto start https://github.com/contracto-lab/contracto-format.git
         | 
| 16 14 |  | 
| 17 15 | 
             
            Test server (default port is __54321__):
         | 
| 18 16 |  | 
| 19 | 
            -
                $ curl  | 
| 17 | 
            +
                $ curl localhost:54321/users; curl localhost:54321/users/1; curl localhost:54321/users/2
         | 
| 20 18 |  | 
| 21 19 | 
             
            Stop server: 
         | 
| 22 20 |  | 
| @@ -6,7 +6,7 @@ class Contracto::Command::Init | |
| 6 6 | 
             
                initialized = Contracto::SystemActionChain.new(*actions).execute
         | 
| 7 7 |  | 
| 8 8 | 
             
                if initialized
         | 
| 9 | 
            -
                  puts 'contract initialized, enter  | 
| 9 | 
            +
                  puts 'contract initialized, enter "contracto start" to start server'
         | 
| 10 10 | 
             
                else
         | 
| 11 11 | 
             
                  puts 'initializing contract failed'
         | 
| 12 12 | 
             
                end
         | 
    
        data/lib/contracto/config.rb
    CHANGED
    
    | @@ -4,18 +4,17 @@ class Contracto::Config | |
| 4 4 | 
             
              class << self
         | 
| 5 5 |  | 
| 6 6 | 
             
                attr_accessor :repo_url
         | 
| 7 | 
            -
                attr_accessor :root_dir
         | 
| 8 7 |  | 
| 9 8 | 
             
                def configure
         | 
| 10 9 | 
             
                  yield self if block_given?
         | 
| 11 10 | 
             
                end
         | 
| 12 11 |  | 
| 12 | 
            +
                def root_dir=(root_dir)
         | 
| 13 | 
            +
                  @root_dir = "#{current_dir}/#{root_dir}"
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 13 16 | 
             
                def root_dir
         | 
| 14 | 
            -
                  @ | 
| 15 | 
            -
                    "#{current_dir}/#{@root_dir}"
         | 
| 16 | 
            -
                  else
         | 
| 17 | 
            -
                    default_root_dir
         | 
| 18 | 
            -
                  end
         | 
| 17 | 
            +
                  @root_dir || default_root_dir
         | 
| 19 18 | 
             
                end
         | 
| 20 19 |  | 
| 21 20 | 
             
              end
         | 
    
        data/lib/contracto/contract.rb
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            class Contracto::Contract
         | 
| 2 | 
            +
              require_relative 'contract/request'
         | 
| 2 3 | 
             
              require_relative 'contract/response'
         | 
| 3 4 | 
             
              require_relative 'stats'
         | 
| 4 5 |  | 
| @@ -6,8 +7,8 @@ class Contracto::Contract | |
| 6 7 |  | 
| 7 8 | 
             
              def initialize(hash)
         | 
| 8 9 | 
             
                @hash = hash
         | 
| 9 | 
            -
                @request   = Contracto::Contract::Request.new(@hash.fetch('request'))
         | 
| 10 | 
            -
                @responses = Contracto::Contract::Responses.new(@hash.fetch(' | 
| 10 | 
            +
                @request   = Contracto::Contract::Request.new(@hash.fetch('schema').fetch('request'))
         | 
| 11 | 
            +
                @responses = Contracto::Contract::Responses.new(@hash.fetch('examples'))
         | 
| 11 12 | 
             
              end
         | 
| 12 13 |  | 
| 13 14 | 
             
              def http_method
         | 
| @@ -45,18 +46,4 @@ class Contracto::Contract | |
| 45 46 | 
             
                  @responses.count
         | 
| 46 47 | 
             
                end
         | 
| 47 48 | 
             
              end
         | 
| 48 | 
            -
             | 
| 49 | 
            -
              class Contracto::Contract::Request
         | 
| 50 | 
            -
                def initialize(hash)
         | 
| 51 | 
            -
                  @hash = hash
         | 
| 52 | 
            -
                end
         | 
| 53 | 
            -
             | 
| 54 | 
            -
                def http_method
         | 
| 55 | 
            -
                  @hash.fetch('http_method')
         | 
| 56 | 
            -
                end
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                def url_pattern
         | 
| 59 | 
            -
                  @hash.fetch('path')
         | 
| 60 | 
            -
                end
         | 
| 61 | 
            -
              end
         | 
| 62 | 
            -
            end
         | 
| 49 | 
            +
            end
         | 
| @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            class Contracto::Contract::Request
         | 
| 2 | 
            +
              def initialize(hash)
         | 
| 3 | 
            +
                @hash = hash
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def http_method
         | 
| 7 | 
            +
                @hash.fetch('method')
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def url_pattern
         | 
| 11 | 
            +
                PathToSinatraPathAdapter.new(@hash.fetch('path')).sinatra_path
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              class PathToSinatraPathAdapter
         | 
| 15 | 
            +
                def initialize(path)
         | 
| 16 | 
            +
                  @path = path
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def sinatra_path
         | 
| 20 | 
            +
                  parse_brackets! if path_with_brackets?
         | 
| 21 | 
            +
                  @path
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                private
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def parse_brackets!
         | 
| 27 | 
            +
                  if fully_dynamic_route?
         | 
| 28 | 
            +
                    path_to_regexp!
         | 
| 29 | 
            +
                  else
         | 
| 30 | 
            +
                    brackets_to_colons!
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def brackets_to_colons!
         | 
| 35 | 
            +
                  @path.gsub!('{', ':')
         | 
| 36 | 
            +
                  @path.gsub!('}', '')
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def path_to_regexp!
         | 
| 40 | 
            +
                  brackets_to_named_captures!
         | 
| 41 | 
            +
                  @path = Regexp.new(@path)
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def brackets_to_named_captures!
         | 
| 45 | 
            +
                  matches = @path.scan(/(\{([^\/])*\})/).map(&:first)
         | 
| 46 | 
            +
                  matches.each do |match|
         | 
| 47 | 
            +
                    @path.gsub! match, "(?<#{match}>\\w*)"
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                  @path.gsub!('{', '')
         | 
| 50 | 
            +
                  @path.gsub!('}', '')
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def fully_dynamic_route?
         | 
| 54 | 
            +
                  !@path.scan(/\}[^\/]/).empty? || !@path.scan(/[^\/]\{/).empty?
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                def path_with_brackets?
         | 
| 58 | 
            +
                  !!@path.match('{')
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
            end
         | 
| @@ -50,10 +50,7 @@ class Contracto::Contract::Response | |
| 50 50 | 
             
              end
         | 
| 51 51 |  | 
| 52 52 | 
             
              def body
         | 
| 53 | 
            -
                 | 
| 54 | 
            -
                @body.tap do
         | 
| 55 | 
            -
                  replace_params_placeholders_with_params_value
         | 
| 56 | 
            -
                end
         | 
| 53 | 
            +
                File.read(Contracto::Config.root_dir + body_path)
         | 
| 57 54 | 
             
              end
         | 
| 58 55 |  | 
| 59 56 | 
             
              private
         | 
| @@ -66,18 +63,10 @@ class Contracto::Contract::Response | |
| 66 63 | 
             
                end
         | 
| 67 64 | 
             
              end
         | 
| 68 65 |  | 
| 69 | 
            -
              def set_body
         | 
| 70 | 
            -
                @body = File.read(Contracto::Config.root_dir + body_path)
         | 
| 71 | 
            -
              end
         | 
| 72 | 
            -
             | 
| 73 66 | 
             
              def human_header_key_to_http_header_key(key)
         | 
| 74 67 | 
             
                key = key.upcase
         | 
| 75 68 | 
             
                key = key.gsub('-', '_')
         | 
| 76 69 | 
             
                key = 'HTTP_' + key
         | 
| 77 70 | 
             
                key
         | 
| 78 71 | 
             
              end
         | 
| 79 | 
            -
             | 
| 80 | 
            -
              def replace_params_placeholders_with_params_value
         | 
| 81 | 
            -
                # TODO
         | 
| 82 | 
            -
              end
         | 
| 83 72 | 
             
            end
         | 
    
        data/lib/contracto/errors.rb
    CHANGED
    
    | @@ -4,6 +4,9 @@ class Contracto::CouldNotDownloadContractError < StandardError | |
| 4 4 | 
             
              end
         | 
| 5 5 | 
             
            end
         | 
| 6 6 |  | 
| 7 | 
            +
            class Contracto::CouldNotStartServer < StandardError
         | 
| 8 | 
            +
            end
         | 
| 9 | 
            +
             | 
| 7 10 | 
             
            class Contracto::ServerAlreadyRunningError < StandardError
         | 
| 8 11 | 
             
              def initialize
         | 
| 9 12 | 
             
                super 'Could not start: Contracto server is already running'
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            require 'sinatra/base'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Contracto::Server < Sinatra::Base
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              require_relative 'server/controller'
         | 
| 6 | 
            +
              require_relative 'stats'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              set :port, Contracto::Constants::PORT
         | 
| 9 | 
            +
              set :show_exceptions, false
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              get '/contracto' do
         | 
| 12 | 
            +
                "*** Contracto server is working! [#{Gem::Specification.find_by_name('contracto').version}] ***"
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              get '/contracto/terminate' do
         | 
| 16 | 
            +
                Thread.new { sleep 1; Process.kill 'INT', Process.pid }
         | 
| 17 | 
            +
                status 200
         | 
| 18 | 
            +
                Contracto::Stats.summary rescue ''
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              not_found do
         | 
| 22 | 
            +
                status 404
         | 
| 23 | 
            +
                "Could not found example for #{request.url}"
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              error do |ex|
         | 
| 27 | 
            +
                status 500
         | 
| 28 | 
            +
                ["#{ex.class}: #{ex.message}", ex.backtrace[0, 15].join("\n")].join("\n")
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| 31 | 
            +
             | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            class Contracto::Server < Sinatra::Base
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              jsons_with_contracts = Dir["#{Contracto::Config.root_dir}/**/*.contract.json"].map do |file_with_contract|
         | 
| 4 | 
            +
                File.read file_with_contract
         | 
| 5 | 
            +
              end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              if jsons_with_contracts.empty?
         | 
| 8 | 
            +
                puts "warning: no contracts found in #{Contracto::Config.root_dir}, create some *.contract.json files"
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              Contracto::Parser.new(jsons_with_contracts).contracts.each do |contract|
         | 
| 12 | 
            +
                send(contract.http_method, contract.url_pattern) do
         | 
| 13 | 
            +
                  contract.response_body(params, http_headers)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def http_headers
         | 
| 18 | 
            +
                env.select {|k,v| k.start_with? 'HTTP_'}
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            require 'daemons'
         | 
| 2 | 
            +
            require 'net/http'
         | 
| 3 | 
            +
            require 'uri'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class Contracto::Server < Sinatra::Base
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              extend Contracto::Constants
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              class << self
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def start_contracto_server!
         | 
| 12 | 
            +
                  if contracto_server_running?
         | 
| 13 | 
            +
                    puts 'contracto server is already running, enter "contracto stop" to kill it'
         | 
| 14 | 
            +
                    return
         | 
| 15 | 
            +
                  elsif !root_dir_exists?
         | 
| 16 | 
            +
                    puts "current dir does not contain required contracto dir (#{Contracto::Config.root_dir})"
         | 
| 17 | 
            +
                    return
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  create_routes_from_contract
         | 
| 21 | 
            +
                  start_daemon!
         | 
| 22 | 
            +
                  wait_until_server_is_running
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def stop_contracto_server!
         | 
| 26 | 
            +
                  uri = URI.parse("http://localhost:#{port}/contracto/terminate")
         | 
| 27 | 
            +
                  response = Net::HTTP.get_response(uri)
         | 
| 28 | 
            +
                  if response.is_a?(Net::HTTPOK)
         | 
| 29 | 
            +
                    puts 'contracto server killed'
         | 
| 30 | 
            +
                    puts response.body
         | 
| 31 | 
            +
                  else
         | 
| 32 | 
            +
                    puts "something went wrong: [#{response.code}] #{response.body}]"
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                rescue Errno::ECONNREFUSED
         | 
| 35 | 
            +
                  puts 'contracto server could not be killed (already dead or was never alive)'
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                private
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def root_dir_exists?
         | 
| 41 | 
            +
                  Dir.exists?(Contracto::Config.root_dir)
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def contracto_server_running?
         | 
| 45 | 
            +
                  uri = URI.parse("http://localhost:#{port}/contracto")
         | 
| 46 | 
            +
                  Net::HTTP.get_response(uri).is_a?(Net::HTTPOK)
         | 
| 47 | 
            +
                rescue Errno::ECONNREFUSED
         | 
| 48 | 
            +
                  false
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def create_routes_from_contract
         | 
| 52 | 
            +
                  require_relative 'contract_routes'
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def start_daemon!
         | 
| 56 | 
            +
                  Daemons.call(app_name: server_pidfile_name, dir: Contracto::Config.root_dir, dir_mode: :normal) do
         | 
| 57 | 
            +
                    Contracto::Server.run!
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def wait_until_server_is_running
         | 
| 62 | 
            +
                  10.downto(0).each do |n|
         | 
| 63 | 
            +
                    sleep 1
         | 
| 64 | 
            +
                    puts "waiting for contracto server, #{n} tries left..."
         | 
| 65 | 
            +
                    if contracto_server_running?
         | 
| 66 | 
            +
                      puts '...contracto server is working'
         | 
| 67 | 
            +
                      return true
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                  raise Contracto::CouldNotStartServer
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            end
         | 
| 75 | 
            +
             | 
    
        data/lib/contracto/stats.rb
    CHANGED
    
    | @@ -1,4 +1,7 @@ | |
| 1 1 | 
             
            class Contracto::Stats
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              NA_TEXT = 'N/A'
         | 
| 4 | 
            +
             | 
| 2 5 | 
             
              class << self
         | 
| 3 6 | 
             
                attr_accessor :all_contracts
         | 
| 4 7 |  | 
| @@ -13,5 +16,35 @@ class Contracto::Stats | |
| 13 16 | 
             
                def all_responses
         | 
| 14 17 | 
             
                  @all_responses ||= all_contracts.map(&:responses).map(&:count).inject(&:+)
         | 
| 15 18 | 
             
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def contracts_usage
         | 
| 21 | 
            +
                  return NA_TEXT if all_contracts.size.zero?
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  (used_contracts.size/all_contracts.size.to_f).round(2)
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def responses_usage
         | 
| 27 | 
            +
                  return NA_TEXT if all_responses.size.zero?
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  (used_responses.size/all_responses.size.to_f).round(2)
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
                
         | 
| 32 | 
            +
                def contracts_stats_summary
         | 
| 33 | 
            +
                  "contracts usage: #{used_contracts.size}/#{all_contracts.size} (#{contracts_usage * 100}%)"
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def responses_stats_summary
         | 
| 37 | 
            +
                  "examples usage: #{used_responses.size}/#{all_responses.size} (#{responses_usage * 100}%)"
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def summary
         | 
| 41 | 
            +
                  length = contracts_stats_summary.length
         | 
| 42 | 
            +
                  [
         | 
| 43 | 
            +
                    'stats'.center(length, '-'),
         | 
| 44 | 
            +
                    contracts_stats_summary,
         | 
| 45 | 
            +
                    responses_stats_summary,
         | 
| 46 | 
            +
                    ('-' * length) + ' '
         | 
| 47 | 
            +
                  ].join("\n")
         | 
| 48 | 
            +
                end
         | 
| 16 49 | 
             
              end
         | 
| 17 | 
            -
            end
         | 
| 50 | 
            +
            end
         | 
| @@ -1,8 +1,11 @@ | |
| 1 | 
            +
            require 'fileutils'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            class Contracto::SystemAction
         | 
| 2 | 
            -
               | 
| 4 | 
            +
              require_relative 'server'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              extend Contracto::Constants
         | 
| 3 7 |  | 
| 4 8 | 
             
              class << self
         | 
| 5 | 
            -
                include Contracto::Constants
         | 
| 6 9 |  | 
| 7 10 | 
             
                def create_sample_contract
         | 
| 8 11 | 
             
                  if Dir.exists?(Contracto::Config.root_dir)
         | 
| @@ -17,37 +20,15 @@ class Contracto::SystemAction | |
| 17 20 | 
             
                end
         | 
| 18 21 |  | 
| 19 22 | 
             
                def start_server
         | 
| 20 | 
            -
                   | 
| 21 | 
            -
             | 
| 22 | 
            -
                  require_relative 'server/ruby/server'
         | 
| 23 | 
            -
                  require 'daemons'
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                  options = {
         | 
| 26 | 
            -
                    app_name: server_pidfile_name,
         | 
| 27 | 
            -
                    dir: Contracto::Config.root_dir,
         | 
| 28 | 
            -
                    dir_mode: :normal
         | 
| 29 | 
            -
                  }
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                  Daemons.call(options) do
         | 
| 32 | 
            -
                    Contracto::Server.run!
         | 
| 33 | 
            -
                  end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                  5.downto(0).each do |n|
         | 
| 36 | 
            -
                    sleep 1
         | 
| 37 | 
            -
                    puts "waiting for contracto server, #{n} tries left..."
         | 
| 38 | 
            -
                    break if test_request(silent: true)
         | 
| 39 | 
            -
                  end
         | 
| 40 | 
            -
                end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                def stop_server
         | 
| 43 | 
            -
                  puts 'killing server...'
         | 
| 44 | 
            -
                  system "curl 0.0.0.0:#{port}/contracto_terminate"
         | 
| 45 | 
            -
                  puts '...server killed'
         | 
| 23 | 
            +
                  Contracto::Server.start_contracto_server!
         | 
| 46 24 | 
             
                end
         | 
| 47 25 |  | 
| 48 26 | 
             
                def revert_start_server
         | 
| 49 27 | 
             
                  stop_server
         | 
| 50 | 
            -
                 | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def stop_server
         | 
| 31 | 
            +
                  Contracto::Server.stop_contracto_server!
         | 
| 51 32 | 
             
                end
         | 
| 52 33 |  | 
| 53 34 | 
             
                def clone_repo
         | 
| @@ -66,15 +47,6 @@ class Contracto::SystemAction | |
| 66 47 | 
             
                  FileUtils.rm_rf Contracto::Config.root_dir
         | 
| 67 48 | 
             
                end
         | 
| 68 49 |  | 
| 69 | 
            -
                def server_already_running?
         | 
| 70 | 
            -
                  test_request(silent: true)
         | 
| 71 | 
            -
                end
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                def test_request(options = {})
         | 
| 74 | 
            -
                  args = ''
         | 
| 75 | 
            -
                  args << '-s -o /dev/null' if options[:silent]
         | 
| 76 | 
            -
                  system "curl #{args} 0.0.0.0:#{port}/contracto"
         | 
| 77 | 
            -
                end
         | 
| 78 50 | 
             
              end
         | 
| 79 51 | 
             
            end
         | 
| 80 52 |  | 
    
        data/lib/contracto/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: contracto
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.4. | 
| 4 | 
            +
              version: 0.4.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Kacper Walanus
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015- | 
| 11 | 
            +
            date: 2015-05-05 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: sinatra
         | 
| @@ -119,11 +119,13 @@ files: | |
| 119 119 | 
             
            - lib/contracto/config.rb
         | 
| 120 120 | 
             
            - lib/contracto/constants.rb
         | 
| 121 121 | 
             
            - lib/contracto/contract.rb
         | 
| 122 | 
            +
            - lib/contracto/contract/request.rb
         | 
| 122 123 | 
             
            - lib/contracto/contract/response.rb
         | 
| 123 124 | 
             
            - lib/contracto/errors.rb
         | 
| 124 125 | 
             
            - lib/contracto/parser.rb
         | 
| 125 | 
            -
            - lib/contracto/server | 
| 126 | 
            -
            - lib/contracto/server/ | 
| 126 | 
            +
            - lib/contracto/server.rb
         | 
| 127 | 
            +
            - lib/contracto/server/contract_routes.rb
         | 
| 128 | 
            +
            - lib/contracto/server/controller.rb
         | 
| 127 129 | 
             
            - lib/contracto/stats.rb
         | 
| 128 130 | 
             
            - lib/contracto/system_action.rb
         | 
| 129 131 | 
             
            - lib/contracto/system_action_chain.rb
         | 
| @@ -131,10 +133,9 @@ files: | |
| 131 133 | 
             
            - script/send_test_requests.sh
         | 
| 132 134 | 
             
            - script/start_from_remote.sh
         | 
| 133 135 | 
             
            - script/start_locally.sh
         | 
| 134 | 
            -
            - spec/fixtures/ | 
| 135 | 
            -
            - spec/fixtures/ | 
| 136 | 
            -
            - spec/fixtures/ | 
| 137 | 
            -
            - spec/fixtures/post_users.con.json
         | 
| 136 | 
            +
            - spec/fixtures/get_user_by_id.contract.json
         | 
| 137 | 
            +
            - spec/fixtures/get_users.contract.json
         | 
| 138 | 
            +
            - spec/fixtures/post_users.contract.json
         | 
| 138 139 | 
             
            - spec/fixtures/users/get_users.json
         | 
| 139 140 | 
             
            - spec/fixtures/users/get_users.xml
         | 
| 140 141 | 
             
            - spec/fixtures/users/get_users_by_id_id_1.json
         | 
| @@ -168,10 +169,9 @@ signing_key: | |
| 168 169 | 
             
            specification_version: 4
         | 
| 169 170 | 
             
            summary: XXX
         | 
| 170 171 | 
             
            test_files:
         | 
| 171 | 
            -
            - spec/fixtures/ | 
| 172 | 
            -
            - spec/fixtures/ | 
| 173 | 
            -
            - spec/fixtures/ | 
| 174 | 
            -
            - spec/fixtures/post_users.con.json
         | 
| 172 | 
            +
            - spec/fixtures/get_user_by_id.contract.json
         | 
| 173 | 
            +
            - spec/fixtures/get_users.contract.json
         | 
| 174 | 
            +
            - spec/fixtures/post_users.contract.json
         | 
| 175 175 | 
             
            - spec/fixtures/users/get_users.json
         | 
| 176 176 | 
             
            - spec/fixtures/users/get_users.xml
         | 
| 177 177 | 
             
            - spec/fixtures/users/get_users_by_id_id_1.json
         | 
| @@ -1,66 +0,0 @@ | |
| 1 | 
            -
            require 'sinatra/base'
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            class Contracto::Server < Sinatra::Base
         | 
| 4 | 
            -
              require_relative '../../stats'
         | 
| 5 | 
            -
             | 
| 6 | 
            -
              set :port, Contracto::Constants::PORT
         | 
| 7 | 
            -
             | 
| 8 | 
            -
              get '/contracto' do
         | 
| 9 | 
            -
                "*** Contracto server is working! [#{Gem::Specification.find_by_name('contracto').version}] ***"
         | 
| 10 | 
            -
              end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              get '/contracto_terminate' do
         | 
| 13 | 
            -
                Thread.new { sleep 1; Process.kill 'INT', Process.pid }
         | 
| 14 | 
            -
                status 200
         | 
| 15 | 
            -
                body_on_terminate
         | 
| 16 | 
            -
              end
         | 
| 17 | 
            -
             | 
| 18 | 
            -
              jsons_with_contracts = Dir["#{Contracto::Config.root_dir}/**/*.con.json"].map do |file_with_contract|
         | 
| 19 | 
            -
                File.read file_with_contract
         | 
| 20 | 
            -
              end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
              Contracto::Parser.new(jsons_with_contracts).contracts.each do |contract|
         | 
| 23 | 
            -
                send(contract.http_method, contract.url_pattern) do
         | 
| 24 | 
            -
                  begin
         | 
| 25 | 
            -
                    contract.response_body(params, http_headers)
         | 
| 26 | 
            -
                  rescue StandardError => ex
         | 
| 27 | 
            -
                    status 500
         | 
| 28 | 
            -
                    error_response(ex)
         | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
              end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
              def http_headers
         | 
| 34 | 
            -
                env.select {|k,v| k.start_with? 'HTTP_'}
         | 
| 35 | 
            -
              end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
              def error_response(ex)
         | 
| 38 | 
            -
                ["#{ex.class}: #{ex.message}", ex.backtrace[0, 15].join("\n")].join("\n")
         | 
| 39 | 
            -
              end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
              def body_on_terminate
         | 
| 42 | 
            -
                used_contracts_count = Contracto::Stats.used_contracts.size
         | 
| 43 | 
            -
                all_contracts_count = Contracto::Stats.all_contracts.size
         | 
| 44 | 
            -
                used_responses_count = Contracto::Stats.used_responses.size
         | 
| 45 | 
            -
                all_responses_count = Contracto::Stats.all_responses.size
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                contracts_usage = if all_contracts_count.zero?
         | 
| 48 | 
            -
                                    'N/A'
         | 
| 49 | 
            -
                                  else
         | 
| 50 | 
            -
                                    "#{(used_contracts_count / all_contracts_count.to_f).round(2)}%"
         | 
| 51 | 
            -
                                  end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                responses_usage = if all_responses_count.zero?
         | 
| 54 | 
            -
                                    'N/A'
         | 
| 55 | 
            -
                                  else
         | 
| 56 | 
            -
                                    "#{(used_responses_count / all_responses_count.to_f).round(2)}%"
         | 
| 57 | 
            -
                                  end
         | 
| 58 | 
            -
                
         | 
| 59 | 
            -
                [
         | 
| 60 | 
            -
                  "Used contracts: #{used_contracts_count}/#{all_contracts_count} (#{contracts_usage})",
         | 
| 61 | 
            -
                  "Used responses: #{used_responses_count}/#{all_responses_count} (#{responses_usage})",
         | 
| 62 | 
            -
                  ''
         | 
| 63 | 
            -
                ].join("\n")
         | 
| 64 | 
            -
              end
         | 
| 65 | 
            -
            end
         | 
| 66 | 
            -
             | 
| @@ -1,23 +0,0 @@ | |
| 1 | 
            -
            {
         | 
| 2 | 
            -
              "request": {
         | 
| 3 | 
            -
                "http_method": "get",
         | 
| 4 | 
            -
                "path": "/my/data",
         | 
| 5 | 
            -
                "meta": {
         | 
| 6 | 
            -
                  "request": {
         | 
| 7 | 
            -
                    
         | 
| 8 | 
            -
                  },
         | 
| 9 | 
            -
                  "response": {
         | 
| 10 | 
            -
                    "body": {
         | 
| 11 | 
            -
                      "type": "object",
         | 
| 12 | 
            -
                      "embedded": [
         | 
| 13 | 
            -
                        {
         | 
| 14 | 
            -
                          "name": "id",
         | 
| 15 | 
            -
                          "type": "string"
         | 
| 16 | 
            -
                        }
         | 
| 17 | 
            -
                      ]
         | 
| 18 | 
            -
                    }
         | 
| 19 | 
            -
                  }
         | 
| 20 | 
            -
                }
         | 
| 21 | 
            -
              },
         | 
| 22 | 
            -
              "responses": []
         | 
| 23 | 
            -
            }
         |