anmo2 0.0.31
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/.gitignore +5 -0
- data/.rubocop.yml +112 -0
- data/.ruby-version +1 -0
- data/.rvmrc +1 -0
- data/.travis.yml +4 -0
- data/Dockerfile +9 -0
- data/Gemfile +4 -0
- data/README.md +41 -0
- data/Rakefile +20 -0
- data/anmo.gemspec +31 -0
- data/features/api.feature +204 -0
- data/features/step_definitions/api_steps.rb +87 -0
- data/features/support/env.rb +13 -0
- data/lib/anmo.rb +57 -0
- data/lib/anmo/application.rb +212 -0
- data/lib/anmo/version.rb +3 -0
- data/run.sh +8 -0
- data/test/anmo/application_test.rb +201 -0
- metadata +191 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: c7310ced86159b67bd2c3341222a7e33b2a135f0
         | 
| 4 | 
            +
              data.tar.gz: bfb7d3107fc3e36ddd6f65daaa84e91ae8ae8474
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 88d83b15443d8152dd009b7501a3e4c2f0b13dd1dfcb418826236a474b30184cf7bf1a9339b166c9e48e616c049e5d7a6a79f3269adac3bf342bc60069d76bb0
         | 
| 7 | 
            +
              data.tar.gz: 00e8186c8d03d2fd29fb3b8fa7dab14a56ab7d9a54007726083a76cec88c3349b286a604707ddddd38f0080d31bbd64a545534abbf888b785fd84277a980363d
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rubocop.yml
    ADDED
    
    | @@ -0,0 +1,112 @@ | |
| 1 | 
            +
            Lint/SpaceBeforeFirstArg:
         | 
| 2 | 
            +
              Severity: fatal
         | 
| 3 | 
            +
              Enabled: true
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Lint/RescueException:
         | 
| 6 | 
            +
              Severity: fatal
         | 
| 7 | 
            +
              Enabled: true
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Lint/UnusedBlockArgument:
         | 
| 10 | 
            +
              Severity: fatal
         | 
| 11 | 
            +
              Enabled: true
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Metrics/LineLength:
         | 
| 14 | 
            +
              Severity: fatal
         | 
| 15 | 
            +
              Enabled: true
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            Metrics/MethodLength:
         | 
| 18 | 
            +
              Severity: convention
         | 
| 19 | 
            +
              Enabled: true
         | 
| 20 | 
            +
              Max: 5
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            Style/AlignHash:
         | 
| 23 | 
            +
              Severity: fatal
         | 
| 24 | 
            +
              Enabled: true
         | 
| 25 | 
            +
              EnforcedHashRocketStyle: table
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            Style/AlignParameters:
         | 
| 28 | 
            +
              Severity: fatal
         | 
| 29 | 
            +
              Enabled: true
         | 
| 30 | 
            +
              EnforcedStyle: with_fixed_indentation
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            Style/BracesAroundHashParameters:
         | 
| 33 | 
            +
              Severity: fatal
         | 
| 34 | 
            +
              Enabled: true
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            Style/ConstantName:
         | 
| 37 | 
            +
              Severity: fatal
         | 
| 38 | 
            +
              Enabled: true
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            Style/Documentation:
         | 
| 41 | 
            +
              Enabled: false
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            Style/EmptyLinesAroundClassBody:
         | 
| 44 | 
            +
              Severity: fatal
         | 
| 45 | 
            +
              Enabled: true
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            Style/ExtraSpacing:
         | 
| 48 | 
            +
              Enabled: false
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            Style/FileName:
         | 
| 51 | 
            +
              Enabled: false
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            Style/HashSyntax:
         | 
| 54 | 
            +
              Severity: fatal
         | 
| 55 | 
            +
              Enabled: true
         | 
| 56 | 
            +
              EnforcedStyle: hash_rockets
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            Style/IndentationConsistency:
         | 
| 59 | 
            +
              Severity: fatal
         | 
| 60 | 
            +
              Enabled: true
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            Style/IndentationWidth:
         | 
| 63 | 
            +
              Severity: fatal
         | 
| 64 | 
            +
              Enabled: true
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            Style/IndentHash:
         | 
| 67 | 
            +
              Severity: fatal
         | 
| 68 | 
            +
              Enabled: true
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            Style/InlineComment:
         | 
| 71 | 
            +
              Severity: fatal
         | 
| 72 | 
            +
              Enabled: true
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            Style/LineEndConcatenation:
         | 
| 75 | 
            +
              Severity: fatal
         | 
| 76 | 
            +
              Enabled: true
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            Style/MethodName:
         | 
| 79 | 
            +
              Severity: fatal
         | 
| 80 | 
            +
              Enabled: true
         | 
| 81 | 
            +
             | 
| 82 | 
            +
            Style/MultilineTernaryOperator:
         | 
| 83 | 
            +
              Enabled: false
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            Style/NegatedIf:
         | 
| 86 | 
            +
              Severity: fatal
         | 
| 87 | 
            +
              Enabled: true
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            Style/Not:
         | 
| 90 | 
            +
              Severity: fatal
         | 
| 91 | 
            +
              Enabled: true
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            Style/SpaceInsideHashLiteralBraces:
         | 
| 94 | 
            +
              Severity: fatal
         | 
| 95 | 
            +
              Enabled: true
         | 
| 96 | 
            +
             | 
| 97 | 
            +
            Style/StringLiterals:
         | 
| 98 | 
            +
              Severity: fatal
         | 
| 99 | 
            +
              Enabled: true
         | 
| 100 | 
            +
              EnforcedStyle: double_quotes
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            Style/TrailingBlankLines:
         | 
| 103 | 
            +
              Severity: fatal
         | 
| 104 | 
            +
              Enabled: true
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            Style/TrailingWhitespace:
         | 
| 107 | 
            +
              Severity: fatal
         | 
| 108 | 
            +
              Enabled: true
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            Style/VariableName:
         | 
| 111 | 
            +
              Severity: fatal
         | 
| 112 | 
            +
              Enabled: true
         | 
    
        data/.ruby-version
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            2.1.2
         | 
    
        data/.rvmrc
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            rvm ruby-1.9.2-p318
         | 
    
        data/.travis.yml
    ADDED
    
    
    
        data/Dockerfile
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            Anmo
         | 
| 2 | 
            +
            ====
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            [](https://travis-ci.org/sthulbourn/anmo)
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            What?
         | 
| 7 | 
            +
            -----
         | 
| 8 | 
            +
            Anmo acts as a mock api and can be used to store arbitrary pieces of data for integration testing flaky APIs.
         | 
| 9 | 
            +
            This is generally *not a good idea*, but where you can't use [VCR](https://github.com/myronmarston/vcr) anmo is now an option.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            How?
         | 
| 12 | 
            +
            ----
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            ```
         | 
| 15 | 
            +
            require "anmo"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            Thread.new { Anmo.launch_server }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            Anmo.create_request({
         | 
| 20 | 
            +
              :path => "/lookatmyhorse",
         | 
| 21 | 
            +
              :body => "my horse is amazing"
         | 
| 22 | 
            +
            })
         | 
| 23 | 
            +
            ```
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ```
         | 
| 26 | 
            +
            curl http://localhost:8787/lookatmyhorse
         | 
| 27 | 
            +
            my horse is amazing
         | 
| 28 | 
            +
            ```
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            Docker
         | 
| 31 | 
            +
            ----
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            To run using docker containers, start memcached and then start anmo.
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            ```sh
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            docker run --name memcache -d memcached
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            docker run --link memcache:memcache -d -p 9999:9999 bbcnews/anmo
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            ```
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require "bundler/gem_tasks"
         | 
| 2 | 
            +
            require "cucumber"
         | 
| 3 | 
            +
            require "cucumber/rake/task"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            task :default => [:test, :features]
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            task :test do
         | 
| 8 | 
            +
              Dir.glob("test/**/*_test.rb").each do |f|
         | 
| 9 | 
            +
                require File.expand_path(File.join(File.dirname(__FILE__), f))
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            task :run do
         | 
| 14 | 
            +
              require "anmo"
         | 
| 15 | 
            +
              Anmo.launch_server 1234
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Cucumber::Rake::Task.new(:features) do |t|
         | 
| 19 | 
            +
              t.cucumber_opts = "features --format pretty"
         | 
| 20 | 
            +
            end
         | 
    
        data/anmo.gemspec
    ADDED
    
    | @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            $LOAD_PATH.push File.expand_path("../lib", __FILE__)
         | 
| 3 | 
            +
            require "anmo/version"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Gem::Specification.new do |s|
         | 
| 6 | 
            +
              s.name        = "anmo2"
         | 
| 7 | 
            +
              s.version     = Anmo::VERSION
         | 
| 8 | 
            +
              s.authors     = ["Andrew Vos"]
         | 
| 9 | 
            +
              s.email       = ["andrew.vos@gmail.com"]
         | 
| 10 | 
            +
              s.homepage    = ""
         | 
| 11 | 
            +
              s.summary     = ""
         | 
| 12 | 
            +
              s.description = ""
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              s.rubyforge_project = "anmo"
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              s.files         = `git ls-files`.split("\n")
         | 
| 17 | 
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         | 
| 18 | 
            +
              s.executables   = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
         | 
| 19 | 
            +
              s.require_paths = ["lib"]
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              s.add_runtime_dependency "rack"
         | 
| 22 | 
            +
              s.add_runtime_dependency "thin", "1.6.3"
         | 
| 23 | 
            +
              s.add_runtime_dependency "httparty"
         | 
| 24 | 
            +
              s.add_runtime_dependency "dalli"
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              s.add_development_dependency "rake"
         | 
| 27 | 
            +
              s.add_development_dependency "minitest"
         | 
| 28 | 
            +
              s.add_development_dependency "rack-test"
         | 
| 29 | 
            +
              s.add_development_dependency "cucumber"
         | 
| 30 | 
            +
              s.add_development_dependency "rspec"
         | 
| 31 | 
            +
            end
         | 
| @@ -0,0 +1,204 @@ | |
| 1 | 
            +
            Feature: API
         | 
| 2 | 
            +
              In order to test applications against stable APIs
         | 
| 3 | 
            +
              As a developer
         | 
| 4 | 
            +
              I want to be able to mock http endpoints
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              Scenario: Launch a server
         | 
| 7 | 
            +
                When I execute the following code in a new thread
         | 
| 8 | 
            +
                """
         | 
| 9 | 
            +
                Anmo.launch_server
         | 
| 10 | 
            +
                """
         | 
| 11 | 
            +
                Then I see an anmo server on port 8787
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              Scenario: Launch a server with a port
         | 
| 14 | 
            +
                When I execute the following code in a new thread
         | 
| 15 | 
            +
                """
         | 
| 16 | 
            +
                Anmo.launch_server 9393
         | 
| 17 | 
            +
                """
         | 
| 18 | 
            +
                Then I see an anmo server on port 9393
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              Scenario: Create a request
         | 
| 21 | 
            +
                Given an anmo server
         | 
| 22 | 
            +
                When I execute the code
         | 
| 23 | 
            +
                """
         | 
| 24 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 25 | 
            +
                Anmo.create_request({
         | 
| 26 | 
            +
                  :path             => "/lollll",
         | 
| 27 | 
            +
                  :body             => "can't think of anything",
         | 
| 28 | 
            +
                  :required_headers => {"meh" => "bleh", "blah" => "blah"}
         | 
| 29 | 
            +
                })
         | 
| 30 | 
            +
                """
         | 
| 31 | 
            +
                And I request the uri "http://localhost:8787/lollll" with the headers
         | 
| 32 | 
            +
                """
         | 
| 33 | 
            +
                {
         | 
| 34 | 
            +
                  "meh": "bleh",
         | 
| 35 | 
            +
                  "blah": "blah"
         | 
| 36 | 
            +
                }
         | 
| 37 | 
            +
                """
         | 
| 38 | 
            +
                Then I see the response body "can't think of anything"
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              Scenario: Save object
         | 
| 41 | 
            +
                Given an anmo server
         | 
| 42 | 
            +
                When I execute the code
         | 
| 43 | 
            +
                """
         | 
| 44 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 45 | 
            +
                Anmo.create_request({
         | 
| 46 | 
            +
                  :path             => "/some/object",
         | 
| 47 | 
            +
                  :body             => "some data"
         | 
| 48 | 
            +
                })
         | 
| 49 | 
            +
                """
         | 
| 50 | 
            +
                And I request the uri "http://localhost:8787/some/object"
         | 
| 51 | 
            +
                Then I see the response body "some data"
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              Scenario: Request only returns object if it has correct query parameters
         | 
| 54 | 
            +
                Given an anmo server
         | 
| 55 | 
            +
                When I execute the code
         | 
| 56 | 
            +
                """
         | 
| 57 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 58 | 
            +
                Anmo.create_request({
         | 
| 59 | 
            +
                  :path             => "/path?monkeys=12",
         | 
| 60 | 
            +
                  :body             => "some data"
         | 
| 61 | 
            +
                })
         | 
| 62 | 
            +
                """
         | 
| 63 | 
            +
                When I request the uri "http://localhost:8787/path?monkeys=12"
         | 
| 64 | 
            +
                Then I see the response code 200
         | 
| 65 | 
            +
                And I see the response body "some data"
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              Scenario: Save object with http status code
         | 
| 68 | 
            +
                Given an anmo server
         | 
| 69 | 
            +
                When I execute the code
         | 
| 70 | 
            +
                """
         | 
| 71 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 72 | 
            +
                Anmo.create_request({
         | 
| 73 | 
            +
                  :path             => "/some/object",
         | 
| 74 | 
            +
                  :status           => 123
         | 
| 75 | 
            +
                })
         | 
| 76 | 
            +
                """
         | 
| 77 | 
            +
                And I request the uri "http://localhost:8787/some/object"
         | 
| 78 | 
            +
                Then I see the response code 123
         | 
| 79 | 
            +
             | 
| 80 | 
            +
              Scenario: Save object with specific method
         | 
| 81 | 
            +
                Given an anmo server
         | 
| 82 | 
            +
                When I execute the code
         | 
| 83 | 
            +
                """
         | 
| 84 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 85 | 
            +
                Anmo.create_request({
         | 
| 86 | 
            +
                  :path             => "/some/object",
         | 
| 87 | 
            +
                  :body             => "some data",
         | 
| 88 | 
            +
                  :method           => :put
         | 
| 89 | 
            +
                })
         | 
| 90 | 
            +
                """
         | 
| 91 | 
            +
                And I issue a put request to the uri "http://localhost:8787/some/object"
         | 
| 92 | 
            +
                Then I see the response body "some data"
         | 
| 93 | 
            +
                And I issue a get request to the uri "http://localhost:8787/some/object"
         | 
| 94 | 
            +
                Then I see the response code 404
         | 
| 95 | 
            +
             | 
| 96 | 
            +
              Scenario: Request without required headers 404s
         | 
| 97 | 
            +
                Given an anmo server
         | 
| 98 | 
            +
                When I execute the code
         | 
| 99 | 
            +
                """
         | 
| 100 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 101 | 
            +
                Anmo.create_request({
         | 
| 102 | 
            +
                  :path             => "/some/object",
         | 
| 103 | 
            +
                  :required_headers => {:meh => "bleh", :durp => "derp"}
         | 
| 104 | 
            +
                })
         | 
| 105 | 
            +
                """
         | 
| 106 | 
            +
                And I request the uri "http://localhost:8787/some/object"
         | 
| 107 | 
            +
                Then I see the response code 404
         | 
| 108 | 
            +
             | 
| 109 | 
            +
              Scenario: Request with required headers
         | 
| 110 | 
            +
                Given an anmo server
         | 
| 111 | 
            +
                When I execute the code
         | 
| 112 | 
            +
                """
         | 
| 113 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 114 | 
            +
                Anmo.create_request({
         | 
| 115 | 
            +
                  :path             => "/some/object",
         | 
| 116 | 
            +
                  :body             => "helloow",
         | 
| 117 | 
            +
                  :required_headers => {:meh => "bleh", :durp => "derp"}
         | 
| 118 | 
            +
                })
         | 
| 119 | 
            +
                """
         | 
| 120 | 
            +
                And I request the uri "http://localhost:8787/some/object" with the headers
         | 
| 121 | 
            +
                """
         | 
| 122 | 
            +
                {
         | 
| 123 | 
            +
                  "meh": "bleh",
         | 
| 124 | 
            +
                  "durp": "derp"
         | 
| 125 | 
            +
                }
         | 
| 126 | 
            +
                """
         | 
| 127 | 
            +
                Then I see the response body "helloow"
         | 
| 128 | 
            +
                And I see the response code 200
         | 
| 129 | 
            +
             | 
| 130 | 
            +
              Scenario: Delete all saved objects
         | 
| 131 | 
            +
                Given an anmo server
         | 
| 132 | 
            +
                When I execute the code
         | 
| 133 | 
            +
                """
         | 
| 134 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 135 | 
            +
                Anmo.create_request({
         | 
| 136 | 
            +
                  :path             => "/some/object",
         | 
| 137 | 
            +
                  :body             => "some data"
         | 
| 138 | 
            +
                })
         | 
| 139 | 
            +
                """
         | 
| 140 | 
            +
                And I execute the code
         | 
| 141 | 
            +
                """
         | 
| 142 | 
            +
                Anmo.delete_all
         | 
| 143 | 
            +
                """
         | 
| 144 | 
            +
                And I request the uri "http://localhost:8787/some/object"
         | 
| 145 | 
            +
                Then I see the response code 404
         | 
| 146 | 
            +
             | 
| 147 | 
            +
              Scenario: Store all requests
         | 
| 148 | 
            +
                Given an anmo server
         | 
| 149 | 
            +
                When I request the uri "http://localhost:8787/some/object"
         | 
| 150 | 
            +
                Then that request should be stored
         | 
| 151 | 
            +
             | 
| 152 | 
            +
              Scenario: Delete all requests
         | 
| 153 | 
            +
                Given an anmo server
         | 
| 154 | 
            +
                When I request the uri "http://localhost:8787/some/object"
         | 
| 155 | 
            +
                And I execute the code
         | 
| 156 | 
            +
                """
         | 
| 157 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 158 | 
            +
                Anmo.delete_all_requests
         | 
| 159 | 
            +
                """
         | 
| 160 | 
            +
                Then there should be no stored requests
         | 
| 161 | 
            +
             | 
| 162 | 
            +
              Scenario: List all saved objects
         | 
| 163 | 
            +
                Given an anmo server
         | 
| 164 | 
            +
                When I execute the code
         | 
| 165 | 
            +
                """
         | 
| 166 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 167 | 
            +
                Anmo.create_request({
         | 
| 168 | 
            +
                  :path             => "/some/object",
         | 
| 169 | 
            +
                  :body             => "some data"
         | 
| 170 | 
            +
                })
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                @result = Anmo.stored_objects
         | 
| 173 | 
            +
                """
         | 
| 174 | 
            +
                Then I should see the value
         | 
| 175 | 
            +
                """
         | 
| 176 | 
            +
                [
         | 
| 177 | 
            +
                  {"path" => "/some/object", "body" => "some data"}
         | 
| 178 | 
            +
                ]
         | 
| 179 | 
            +
                """
         | 
| 180 | 
            +
             | 
| 181 | 
            +
              Scenario: Anmo knows if a server is not running
         | 
| 182 | 
            +
                When I execute the code
         | 
| 183 | 
            +
                """
         | 
| 184 | 
            +
                Anmo.server = "http://localhost:8459"
         | 
| 185 | 
            +
                @result = Anmo.running?
         | 
| 186 | 
            +
                """
         | 
| 187 | 
            +
                Then I see that the anmo server is not running
         | 
| 188 | 
            +
             | 
| 189 | 
            +
              Scenario: Anmo knows if a server is running
         | 
| 190 | 
            +
                Given an anmo server
         | 
| 191 | 
            +
                When I execute the code
         | 
| 192 | 
            +
                """
         | 
| 193 | 
            +
                Anmo.server = "http://localhost:8787"
         | 
| 194 | 
            +
                @result = Anmo.running?
         | 
| 195 | 
            +
                """
         | 
| 196 | 
            +
                Then I see that the anmo server is running
         | 
| 197 | 
            +
             | 
| 198 | 
            +
              Scenario: Anmo knows what version the server is running
         | 
| 199 | 
            +
                Given an anmo server
         | 
| 200 | 
            +
                When I execute the code
         | 
| 201 | 
            +
                """
         | 
| 202 | 
            +
                Anmo.server_version
         | 
| 203 | 
            +
                """
         | 
| 204 | 
            +
                Then I see the anmo version
         | 
| @@ -0,0 +1,87 @@ | |
| 1 | 
            +
            require "stringio"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            When /^I execute the following code in a new thread$/ do |code|
         | 
| 4 | 
            +
              Thread.new do
         | 
| 5 | 
            +
                eval code
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
            end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            When /^I execute the code$/ do |code|
         | 
| 10 | 
            +
              @result = eval code
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Then /^I see an anmo server on port (\d+)$/ do |port|
         | 
| 14 | 
            +
              response = nil
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              timeout 5 do
         | 
| 17 | 
            +
                while response.nil?
         | 
| 18 | 
            +
                  response = HTTParty.get("http://localhost:#{port}") rescue nil
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              response.body.should include "Not Found"
         | 
| 23 | 
            +
            end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            Given /^an anmo server$/ do
         | 
| 26 | 
            +
              Thread.new do
         | 
| 27 | 
            +
                Anmo.launch_server
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              timeout 5 do
         | 
| 31 | 
            +
                response = nil
         | 
| 32 | 
            +
                while response.nil?
         | 
| 33 | 
            +
                  response = HTTParty.get("http://localhost:8787") rescue nil
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                sleep 0.1
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            Then /^I issue a get request to the uri "([^"]*)"$/ do |uri|
         | 
| 40 | 
            +
              @response = HTTParty.get(uri)
         | 
| 41 | 
            +
            end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            When /^I issue a put request to the uri "([^"]*)"$/ do |uri|
         | 
| 44 | 
            +
              @response = HTTParty.put(uri)
         | 
| 45 | 
            +
            end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            When /^I request the uri "([^"]*)"$/ do |uri|
         | 
| 48 | 
            +
              @requested_uri = uri
         | 
| 49 | 
            +
              @response = HTTParty.get(uri)
         | 
| 50 | 
            +
            end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            When /^I request the uri "([^"]*)" with the headers$/ do |uri, headers|
         | 
| 53 | 
            +
              headers = JSON.parse(headers)
         | 
| 54 | 
            +
              @response = HTTParty.get(uri, :headers => headers)
         | 
| 55 | 
            +
            end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            Then /^I see the response body "([^"]*)"$/ do |body|
         | 
| 58 | 
            +
              @response.body.should == body
         | 
| 59 | 
            +
            end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            Then /^I see the response code (\d+)$/ do |code|
         | 
| 62 | 
            +
              @response.code.should == code.to_i
         | 
| 63 | 
            +
            end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            Then /^that request should be stored$/ do
         | 
| 66 | 
            +
              Anmo.requests.last["PATH_INFO"].should == @requested_uri.gsub("http://localhost:8787", "")
         | 
| 67 | 
            +
            end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            Then /^there should be no stored requests$/ do
         | 
| 70 | 
            +
              Anmo.requests.size.should == 0
         | 
| 71 | 
            +
            end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            Then /^I should see the value$/ do |code|
         | 
| 74 | 
            +
              @result.should == eval(code)
         | 
| 75 | 
            +
            end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            Then /^I see that the anmo server is not running$/ do
         | 
| 78 | 
            +
              @result.should == false
         | 
| 79 | 
            +
            end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            Then /^I see that the anmo server is running$/ do
         | 
| 82 | 
            +
              @result.should == true
         | 
| 83 | 
            +
            end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            Then /^I see the anmo version$/ do
         | 
| 86 | 
            +
              @result.should == Anmo::VERSION
         | 
| 87 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            require "rack"
         | 
| 2 | 
            +
            require "rack/test"
         | 
| 3 | 
            +
            require "httparty"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), "../../lib")))
         | 
| 6 | 
            +
            require "anmo"
         | 
| 7 | 
            +
            require "anmo/application"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            World(Rack::Test::Methods)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            def app
         | 
| 12 | 
            +
              Anmo::Application.new
         | 
| 13 | 
            +
            end
         | 
    
        data/lib/anmo.rb
    ADDED
    
    | @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            require "anmo/version"
         | 
| 2 | 
            +
            require "anmo/application"
         | 
| 3 | 
            +
            require "thin"
         | 
| 4 | 
            +
            require "httparty"
         | 
| 5 | 
            +
            require "json"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Anmo
         | 
| 8 | 
            +
              def self.server
         | 
| 9 | 
            +
                @server ||= "http://localhost:#{@port}"
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              class << self
         | 
| 13 | 
            +
                attr_writer :server
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def self.server_version
         | 
| 17 | 
            +
                HTTParty.get(anmo_url("__VERSION__")).body
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def self.launch_server(port = 8787)
         | 
| 21 | 
            +
                @port = port
         | 
| 22 | 
            +
                Thin::Server.start("0.0.0.0", port, Anmo::Application.new)
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def self.create_request(options)
         | 
| 26 | 
            +
                HTTParty.post(anmo_url("__CREATE_OBJECT__"), :body => options.to_json, :headers => { "Content-Type" => "application/json" })
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def self.delete_all
         | 
| 30 | 
            +
                HTTParty.post(anmo_url("__DELETE_ALL_OBJECTS__"))
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def self.requests
         | 
| 34 | 
            +
                json = HTTParty.get(anmo_url("__REQUESTS__"))
         | 
| 35 | 
            +
                JSON.parse(json.body)
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              def self.delete_all_requests
         | 
| 39 | 
            +
                HTTParty.post(anmo_url("__DELETE_ALL_REQUESTS__"))
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              def self.stored_objects
         | 
| 43 | 
            +
                json = HTTParty.get(anmo_url("__OBJECTS__"))
         | 
| 44 | 
            +
                JSON.parse(json.body)
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              def self.running?
         | 
| 48 | 
            +
                HTTParty.get(anmo_url("__ALIVE__")).code == 200 rescue false
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              private
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def self.anmo_url(path)
         | 
| 54 | 
            +
                "#{server}/#{path}"
         | 
| 55 | 
            +
                # URI.join(server, path).to_s
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
            end
         | 
| @@ -0,0 +1,212 @@ | |
| 1 | 
            +
            require "dalli"
         | 
| 2 | 
            +
            require "uri"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Anmo
         | 
| 5 | 
            +
              class ApplicationDataStore
         | 
| 6 | 
            +
                TTL = 1_000_000
         | 
| 7 | 
            +
                def self.objects
         | 
| 8 | 
            +
                  cached_objects = server.get("objects")
         | 
| 9 | 
            +
                  return JSON.load(cached_objects) if cached_objects
         | 
| 10 | 
            +
                  []
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def self.requests
         | 
| 14 | 
            +
                  cached_requests = server.get("requests")
         | 
| 15 | 
            +
                  return JSON.load(cached_requests) if cached_requests
         | 
| 16 | 
            +
                  []
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def self.insert_object(object)
         | 
| 20 | 
            +
                  all_objects = objects
         | 
| 21 | 
            +
                  all_objects.unshift(object)
         | 
| 22 | 
            +
                  server.set("objects", JSON.dump(all_objects), TTL)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def self.save_request(request)
         | 
| 26 | 
            +
                  all_requests = requests
         | 
| 27 | 
            +
                  all_requests << request
         | 
| 28 | 
            +
                  server.set("requests", JSON.dump(all_requests), TTL)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def self.clear_objects
         | 
| 32 | 
            +
                  server.delete("objects")
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def self.clear_requests
         | 
| 36 | 
            +
                  server.delete("requests")
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def self.find(path, query_string)
         | 
| 40 | 
            +
                  objects.each do |object|
         | 
| 41 | 
            +
                    object_path = object["path"].gsub(/(\?.*)$/, "")
         | 
| 42 | 
            +
                    if path == object_path
         | 
| 43 | 
            +
                      object_query_string = Rack::Utils.parse_query(object["path"].gsub(/(.*?)\?/, ""))
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                      if query_string == object_query_string
         | 
| 46 | 
            +
                        p object
         | 
| 47 | 
            +
                        return object
         | 
| 48 | 
            +
                      end
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                private
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def self.server
         | 
| 56 | 
            +
                  @server ||= if ENV["MEMCACHE_SERVERS"]
         | 
| 57 | 
            +
                                Dalli::Client.new(ENV["MEMCACHE_SERVERS"],
         | 
| 58 | 
            +
                                  :username  => ENV["MEMCACHE_USERNAME"],
         | 
| 59 | 
            +
                                  :password  => ENV["MEMCACHE_PASSWORD"],
         | 
| 60 | 
            +
                                  :namespace => Process.pid.to_s
         | 
| 61 | 
            +
                                )
         | 
| 62 | 
            +
                              else
         | 
| 63 | 
            +
                                Dalli::Client.new "127.0.0.1:11211", :namespace => Process.pid.to_s
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              class Application
         | 
| 69 | 
            +
                def initialize
         | 
| 70 | 
            +
                  ApplicationDataStore.clear_objects
         | 
| 71 | 
            +
                  ApplicationDataStore.clear_requests
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                def call(env)
         | 
| 75 | 
            +
                  request = Rack::Request.new(env)
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  if request.request_method.upcase == "OPTIONS"
         | 
| 78 | 
            +
                    return [
         | 
| 79 | 
            +
                      200,
         | 
| 80 | 
            +
                      {
         | 
| 81 | 
            +
                        "Access-Control-Allow-Origin"  => "*",
         | 
| 82 | 
            +
                        "Access-Control-Allow-Methods" => "*",
         | 
| 83 | 
            +
                        "Access-Control-Allow-Headers" => "X-Requested-With,Content-Type,Authorization"
         | 
| 84 | 
            +
                      },
         | 
| 85 | 
            +
                      ""
         | 
| 86 | 
            +
                    ]
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  controller_methods = [
         | 
| 90 | 
            +
                    :alive,
         | 
| 91 | 
            +
                    :version,
         | 
| 92 | 
            +
                    :create_object,
         | 
| 93 | 
            +
                    :objects,
         | 
| 94 | 
            +
                    :requests,
         | 
| 95 | 
            +
                    :delete_all_objects,
         | 
| 96 | 
            +
                    :delete_all_requests
         | 
| 97 | 
            +
                  ]
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                  method = controller_methods.find { |m| request.path_info =~ /\/?__#{m.to_s.upcase}__\/?/ }
         | 
| 100 | 
            +
                  method ||= :process_normal_request
         | 
| 101 | 
            +
                  send(method, request)
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                private
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                def text(text, status = 200)
         | 
| 107 | 
            +
                  [status, { "Content-Type" => "text/html", "Access-Control-Allow-Origin" => "*" }, [text]]
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                def json(json, status = 200)
         | 
| 111 | 
            +
                  [status, { "Content-Type" => "application/json", "Access-Control-Allow-Origin" => "*" }, [json]]
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                def alive(_request)
         | 
| 115 | 
            +
                  text "<h1>anmo is alive</h1>"
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                def version(_request)
         | 
| 119 | 
            +
                  text Anmo::VERSION
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                def create_object(request)
         | 
| 123 | 
            +
                  request_info = JSON.parse(read_request_body(request))
         | 
| 124 | 
            +
                  ApplicationDataStore.insert_object(request_info)
         | 
| 125 | 
            +
                  text "", 201
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                def delete_all_objects(_request)
         | 
| 129 | 
            +
                  ApplicationDataStore.clear_objects
         | 
| 130 | 
            +
                  text ""
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                def process_normal_request(request)
         | 
| 134 | 
            +
                  ApplicationDataStore.save_request(request.env)
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                  if found_request = find_stored_request(request)
         | 
| 137 | 
            +
                    text found_request["body"], Integer(found_request["status"] || 200)
         | 
| 138 | 
            +
                  else
         | 
| 139 | 
            +
                    text "Not Found", 404
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                def requests(_request)
         | 
| 144 | 
            +
                  json ApplicationDataStore.requests.to_json
         | 
| 145 | 
            +
                end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                def delete_all_requests(_request)
         | 
| 148 | 
            +
                  ApplicationDataStore.clear_requests
         | 
| 149 | 
            +
                  text ""
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                def objects(_request)
         | 
| 153 | 
            +
                  json ApplicationDataStore.objects.to_json
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                def find_stored_request(actual_request)
         | 
| 157 | 
            +
                  actual_request_query = Rack::Utils.parse_query(actual_request.query_string)
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                  suspected_request = ApplicationDataStore.objects.find do |r|
         | 
| 160 | 
            +
                    uri = URI(r["path"])
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                    query = Rack::Utils.parse_query(uri.query)
         | 
| 163 | 
            +
                    method = r["method"] || "GET"
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                    if uri.query.nil?
         | 
| 166 | 
            +
                      uri.path == actual_request.path_info && method.upcase == actual_request.request_method.upcase
         | 
| 167 | 
            +
                    else
         | 
| 168 | 
            +
                      uri.path == actual_request.path_info && query == actual_request_query && method.upcase == actual_request.request_method.upcase
         | 
| 169 | 
            +
                    end
         | 
| 170 | 
            +
                  end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                  unless suspected_request.nil?
         | 
| 173 | 
            +
                    return unless request_has_required_headers(actual_request, suspected_request)
         | 
| 174 | 
            +
                  end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                  suspected_request
         | 
| 177 | 
            +
                end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                def request_has_same_method(initial_request, suspected_request)
         | 
| 180 | 
            +
                  return true if suspected_request["method"].nil?
         | 
| 181 | 
            +
                  suspected_request["method"].upcase == initial_request.request_method
         | 
| 182 | 
            +
                end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                def request_has_same_query(initial_request, suspected_request)
         | 
| 185 | 
            +
                  return true if suspected_request["path"].include?("?") == false
         | 
| 186 | 
            +
                  query = Rack::Utils.parse_query(suspected_request["path"].gsub(/.*\?/, ""))
         | 
| 187 | 
            +
                  query == Rack::Utils.parse_query(initial_request.query_string)
         | 
| 188 | 
            +
                end
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                def request_has_required_headers(initial_request, suspected_request)
         | 
| 191 | 
            +
                  required_headers = suspected_request["required_headers"] || {}
         | 
| 192 | 
            +
                  required_headers.each do |name, value|
         | 
| 193 | 
            +
                    if initial_request.env[convert_header_name_to_rack_style_name(name)] != value
         | 
| 194 | 
            +
                      return false
         | 
| 195 | 
            +
                    end
         | 
| 196 | 
            +
                  end
         | 
| 197 | 
            +
                  true
         | 
| 198 | 
            +
                end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                def convert_header_name_to_rack_style_name(name)
         | 
| 201 | 
            +
                  name = "HTTP_#{name}"
         | 
| 202 | 
            +
                  name.gsub!("-", "_")
         | 
| 203 | 
            +
                  name.upcase!
         | 
| 204 | 
            +
                  name
         | 
| 205 | 
            +
                end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                def read_request_body(request)
         | 
| 208 | 
            +
                  request.body.rewind
         | 
| 209 | 
            +
                  request.body.read
         | 
| 210 | 
            +
                end
         | 
| 211 | 
            +
              end
         | 
| 212 | 
            +
            end
         | 
    
        data/lib/anmo/version.rb
    ADDED
    
    
    
        data/run.sh
    ADDED
    
    
| @@ -0,0 +1,201 @@ | |
| 1 | 
            +
            require "minitest/pride"
         | 
| 2 | 
            +
            require "minitest/autorun"
         | 
| 3 | 
            +
            require "minitest/unit"
         | 
| 4 | 
            +
            require "rack/test"
         | 
| 5 | 
            +
            require "json"
         | 
| 6 | 
            +
            require File.expand_path(File.join(File.dirname(__FILE__), "../../lib/anmo/application"))
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Anmo
         | 
| 9 | 
            +
              class ApplicationTest < MiniTest::Unit::TestCase
         | 
| 10 | 
            +
                include Rack::Test::Methods
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def app
         | 
| 13 | 
            +
                  Application.new
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def setup
         | 
| 17 | 
            +
                  ApplicationDataStore.clear_objects
         | 
| 18 | 
            +
                  ApplicationDataStore.clear_requests
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def save_object(path, body, status, required_headers, method)
         | 
| 22 | 
            +
                  options = {
         | 
| 23 | 
            +
                    :path             => path,
         | 
| 24 | 
            +
                    :body             => body,
         | 
| 25 | 
            +
                    :status           => status,
         | 
| 26 | 
            +
                    :required_headers => required_headers
         | 
| 27 | 
            +
                  }
         | 
| 28 | 
            +
                  options[:method] = method if method
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  put "__CREATE_OBJECT__", options.to_json
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def test_404s_if_object_does_not_exist
         | 
| 34 | 
            +
                  get "/bla/bla/bla.json"
         | 
| 35 | 
            +
                  assert_equal "Not Found", last_response.body
         | 
| 36 | 
            +
                  assert last_response.not_found?
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def test_stores_mock_data
         | 
| 40 | 
            +
                  save_object "/this/is/the/path.object", "please save this", nil, nil, nil
         | 
| 41 | 
            +
                  assert_equal 201, last_response.status
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  get "/this/is/the/path.object"
         | 
| 44 | 
            +
                  assert_equal "please save this", last_response.body
         | 
| 45 | 
            +
                  assert last_response.ok?
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def test_does_not_return_object_if_request_has_different_query_parameters
         | 
| 49 | 
            +
                  save_object "/path/?hello=true", "please save this", nil, nil, nil
         | 
| 50 | 
            +
                  get "/path/?hello=false"
         | 
| 51 | 
            +
                  assert_equal 404, last_response.status
         | 
| 52 | 
            +
                  assert_equal "Not Found", last_response.body
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def test_returns_object_if_request_has_same_query_parameters
         | 
| 56 | 
            +
                  save_object "/?hello=true&bla=bla", "please save this", nil, nil, nil
         | 
| 57 | 
            +
                  get "/?hello=true&bla=bla"
         | 
| 58 | 
            +
                  assert_equal 200, last_response.status
         | 
| 59 | 
            +
                  assert_equal "please save this", last_response.body
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def test_returns_object_if_request_has_query_parameters_in_different_order
         | 
| 63 | 
            +
                  save_object "/?aaa=aaa&bbb=bbb", "please save this", nil, nil, nil
         | 
| 64 | 
            +
                  get "/?bbb=bbb&aaa=aaa"
         | 
| 65 | 
            +
                  assert_equal 200, last_response.status
         | 
| 66 | 
            +
                  assert_equal "please save this", last_response.body
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def test_stores_status_code
         | 
| 70 | 
            +
                  save_object "/monkeys", nil, 123, nil, nil
         | 
| 71 | 
            +
                  get "/monkeys"
         | 
| 72 | 
            +
                  assert_equal 123, last_response.status
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def test_similar_query_string
         | 
| 76 | 
            +
                  save_object "/pulsar/assets?channel=foo.bar.baz.qux.quux.1", "Something", 200, nil, :get
         | 
| 77 | 
            +
                  save_object "/pulsar/assets?channel=foo.bar.baz.qux.quux.2", "Something else", 200, nil, :get
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  get "/pulsar/assets?channel=foo.bar.baz.qux.quux.1"
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                  assert_equal 200, last_response.status
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                def test_allows_deleting_all_objects
         | 
| 85 | 
            +
                  save_object "/this/is/the/path.object", "please save this", nil, nil, nil
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  get "/this/is/the/path.object"
         | 
| 88 | 
            +
                  first_response = last_response
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                  post "__DELETE_ALL_OBJECTS__"
         | 
| 91 | 
            +
                  assert_equal 200, last_response.status
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  get "/this/is/the/path.object"
         | 
| 94 | 
            +
                  second_response = last_response
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  assert_equal "please save this", first_response.body
         | 
| 97 | 
            +
                  assert_equal "Not Found", second_response.body
         | 
| 98 | 
            +
                  assert_equal 404, second_response.status
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def test_404s_if_request_does_not_have_required_headers
         | 
| 102 | 
            +
                  save_object "/oh/hai", nil, nil, { "ruby" => "hipsters", "meh" => "bleh" }, nil
         | 
| 103 | 
            +
                  get "/oh/hai"
         | 
| 104 | 
            +
                  assert_equal 404, last_response.status
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                def test_returns_value_if_request_has_required_headers
         | 
| 108 | 
            +
                  save_object "/oh/hai", "the content", nil, { "lol-ruby" => "hipsters", "meh" => "bleh" }, nil
         | 
| 109 | 
            +
                  header "lol-ruby", "hipsters"
         | 
| 110 | 
            +
                  header "meh", "bleh"
         | 
| 111 | 
            +
                  get "/oh/hai"
         | 
| 112 | 
            +
                  assert_equal 200, last_response.status
         | 
| 113 | 
            +
                  assert_equal "the content", last_response.body
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                def test_404s_if_request_does_not_have_correct_method
         | 
| 117 | 
            +
                  save_object "/meh", "content", nil, nil, :delete
         | 
| 118 | 
            +
                  get "/meh"
         | 
| 119 | 
            +
                  assert_equal 404, last_response.status
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                def test_returns_vaue_if_request_has_correct_method
         | 
| 123 | 
            +
                  save_object "/meh", "content", nil, nil, :delete
         | 
| 124 | 
            +
                  delete "/meh"
         | 
| 125 | 
            +
                  assert_equal 200, last_response.status
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                def test_returns_the_last_added_object_first
         | 
| 129 | 
            +
                  save_object "/oh/hai", "the first content", nil, nil, nil
         | 
| 130 | 
            +
                  save_object "/oh/hai", "the second content", nil, nil, nil
         | 
| 131 | 
            +
                  get "/oh/hai"
         | 
| 132 | 
            +
                  assert_equal "the second content", last_response.body
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                def test_stores_all_requests
         | 
| 136 | 
            +
                  get "/hello"
         | 
| 137 | 
            +
                  get "/hai"
         | 
| 138 | 
            +
                  get "/__REQUESTS__"
         | 
| 139 | 
            +
                  json = JSON.parse(last_response.body)
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  assert_equal 2, json.size
         | 
| 142 | 
            +
                  assert_equal "/hello", json.first["PATH_INFO"]
         | 
| 143 | 
            +
                  assert_equal "/hai", json.last["PATH_INFO"]
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                def test_does_not_store_create_or_delete_requests
         | 
| 147 | 
            +
                  save_object "/oh/hai", "the first content", nil, nil, nil
         | 
| 148 | 
            +
                  post "__DELETE_ALL_OBJECTS__"
         | 
| 149 | 
            +
                  get "/__REQUESTS__"
         | 
| 150 | 
            +
                  json = JSON.parse(last_response.body)
         | 
| 151 | 
            +
                  assert_equal 0, json.size
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                def test_returns_requests_as_json
         | 
| 155 | 
            +
                  get "/hello"
         | 
| 156 | 
            +
                  get "/__REQUESTS__"
         | 
| 157 | 
            +
                  json = JSON.parse(last_response.body)
         | 
| 158 | 
            +
                  assert_equal 1, json.size
         | 
| 159 | 
            +
                  assert_equal "/hello", json.first["PATH_INFO"]
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                def test_deletes_all_requests
         | 
| 163 | 
            +
                  get "/hello"
         | 
| 164 | 
            +
                  get "/__REQUESTS__"
         | 
| 165 | 
            +
                  json = JSON.parse(last_response.body)
         | 
| 166 | 
            +
                  assert_equal 1, json.size
         | 
| 167 | 
            +
                  post "/__DELETE_ALL_REQUESTS__"
         | 
| 168 | 
            +
                  get "/__REQUESTS__"
         | 
| 169 | 
            +
                  json = JSON.parse(last_response.body)
         | 
| 170 | 
            +
                  assert_equal 0, json.size
         | 
| 171 | 
            +
                end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                def test_returns_empty_list_of_stored_objects
         | 
| 174 | 
            +
                  get "/__OBJECTS__"
         | 
| 175 | 
            +
                  json = JSON.parse(last_response.body)
         | 
| 176 | 
            +
                  assert_equal "application/json", last_response.content_type
         | 
| 177 | 
            +
                  assert_equal 0, json.size
         | 
| 178 | 
            +
                end
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                def test_lists_stored_objects
         | 
| 181 | 
            +
                  save_object "/some/path", nil, nil, nil, nil
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                  get "/__OBJECTS__"
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                  json = JSON.parse(last_response.body)
         | 
| 186 | 
            +
                  assert_equal 1, json.size
         | 
| 187 | 
            +
                  assert_equal "/some/path", json.first["path"]
         | 
| 188 | 
            +
                end
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                def test_shows_that_its_alive
         | 
| 191 | 
            +
                  get "/__ALIVE__"
         | 
| 192 | 
            +
                  assert last_response.ok?
         | 
| 193 | 
            +
                  assert_equal "<h1>anmo is alive</h1>", last_response.body
         | 
| 194 | 
            +
                end
         | 
| 195 | 
            +
             | 
| 196 | 
            +
                def test_exposes_server_version
         | 
| 197 | 
            +
                  get "/__VERSION__"
         | 
| 198 | 
            +
                  assert_equal Anmo::VERSION, last_response.body
         | 
| 199 | 
            +
                end
         | 
| 200 | 
            +
              end
         | 
| 201 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,191 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: anmo2
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.31
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Andrew Vos
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2015-07-22 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: rack
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - ">="
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - ">="
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: thin
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - '='
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: 1.6.3
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - '='
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: 1.6.3
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: httparty
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - ">="
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '0'
         | 
| 48 | 
            +
              type: :runtime
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - ">="
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: dalli
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ">="
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
              type: :runtime
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - ">="
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '0'
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            +
              name: rake
         | 
| 71 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            +
                requirements:
         | 
| 73 | 
            +
                - - ">="
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: '0'
         | 
| 76 | 
            +
              type: :development
         | 
| 77 | 
            +
              prerelease: false
         | 
| 78 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
                requirements:
         | 
| 80 | 
            +
                - - ">="
         | 
| 81 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            +
                    version: '0'
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: minitest
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - ">="
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '0'
         | 
| 90 | 
            +
              type: :development
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - ">="
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '0'
         | 
| 97 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 98 | 
            +
              name: rack-test
         | 
| 99 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 100 | 
            +
                requirements:
         | 
| 101 | 
            +
                - - ">="
         | 
| 102 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            +
                    version: '0'
         | 
| 104 | 
            +
              type: :development
         | 
| 105 | 
            +
              prerelease: false
         | 
| 106 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
                requirements:
         | 
| 108 | 
            +
                - - ">="
         | 
| 109 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 110 | 
            +
                    version: '0'
         | 
| 111 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 112 | 
            +
              name: cucumber
         | 
| 113 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 114 | 
            +
                requirements:
         | 
| 115 | 
            +
                - - ">="
         | 
| 116 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 117 | 
            +
                    version: '0'
         | 
| 118 | 
            +
              type: :development
         | 
| 119 | 
            +
              prerelease: false
         | 
| 120 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 121 | 
            +
                requirements:
         | 
| 122 | 
            +
                - - ">="
         | 
| 123 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 124 | 
            +
                    version: '0'
         | 
| 125 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 126 | 
            +
              name: rspec
         | 
| 127 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 128 | 
            +
                requirements:
         | 
| 129 | 
            +
                - - ">="
         | 
| 130 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 131 | 
            +
                    version: '0'
         | 
| 132 | 
            +
              type: :development
         | 
| 133 | 
            +
              prerelease: false
         | 
| 134 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 135 | 
            +
                requirements:
         | 
| 136 | 
            +
                - - ">="
         | 
| 137 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 138 | 
            +
                    version: '0'
         | 
| 139 | 
            +
            description: ''
         | 
| 140 | 
            +
            email:
         | 
| 141 | 
            +
            - andrew.vos@gmail.com
         | 
| 142 | 
            +
            executables: []
         | 
| 143 | 
            +
            extensions: []
         | 
| 144 | 
            +
            extra_rdoc_files: []
         | 
| 145 | 
            +
            files:
         | 
| 146 | 
            +
            - ".gitignore"
         | 
| 147 | 
            +
            - ".rubocop.yml"
         | 
| 148 | 
            +
            - ".ruby-version"
         | 
| 149 | 
            +
            - ".rvmrc"
         | 
| 150 | 
            +
            - ".travis.yml"
         | 
| 151 | 
            +
            - Dockerfile
         | 
| 152 | 
            +
            - Gemfile
         | 
| 153 | 
            +
            - README.md
         | 
| 154 | 
            +
            - Rakefile
         | 
| 155 | 
            +
            - anmo.gemspec
         | 
| 156 | 
            +
            - features/api.feature
         | 
| 157 | 
            +
            - features/step_definitions/api_steps.rb
         | 
| 158 | 
            +
            - features/support/env.rb
         | 
| 159 | 
            +
            - lib/anmo.rb
         | 
| 160 | 
            +
            - lib/anmo/application.rb
         | 
| 161 | 
            +
            - lib/anmo/version.rb
         | 
| 162 | 
            +
            - run.sh
         | 
| 163 | 
            +
            - test/anmo/application_test.rb
         | 
| 164 | 
            +
            homepage: ''
         | 
| 165 | 
            +
            licenses: []
         | 
| 166 | 
            +
            metadata: {}
         | 
| 167 | 
            +
            post_install_message: 
         | 
| 168 | 
            +
            rdoc_options: []
         | 
| 169 | 
            +
            require_paths:
         | 
| 170 | 
            +
            - lib
         | 
| 171 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 172 | 
            +
              requirements:
         | 
| 173 | 
            +
              - - ">="
         | 
| 174 | 
            +
                - !ruby/object:Gem::Version
         | 
| 175 | 
            +
                  version: '0'
         | 
| 176 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 177 | 
            +
              requirements:
         | 
| 178 | 
            +
              - - ">="
         | 
| 179 | 
            +
                - !ruby/object:Gem::Version
         | 
| 180 | 
            +
                  version: '0'
         | 
| 181 | 
            +
            requirements: []
         | 
| 182 | 
            +
            rubyforge_project: anmo
         | 
| 183 | 
            +
            rubygems_version: 2.4.2
         | 
| 184 | 
            +
            signing_key: 
         | 
| 185 | 
            +
            specification_version: 4
         | 
| 186 | 
            +
            summary: ''
         | 
| 187 | 
            +
            test_files:
         | 
| 188 | 
            +
            - features/api.feature
         | 
| 189 | 
            +
            - features/step_definitions/api_steps.rb
         | 
| 190 | 
            +
            - features/support/env.rb
         | 
| 191 | 
            +
            - test/anmo/application_test.rb
         |