glowworm 0.3.0
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 +15 -0
 - data/.gitignore +6 -0
 - data/.yardopts +1 -0
 - data/Gemfile +5 -0
 - data/Gemfile.lock +129 -0
 - data/LICENSE +19 -0
 - data/README.md +326 -0
 - data/Rakefile +29 -0
 - data/bin/basic_server_tester +311 -0
 - data/bin/em_server/config.ru +2 -0
 - data/bin/em_server/em_server.rb +19 -0
 - data/bin/em_server_tester +68 -0
 - data/bin/glowworm +90 -0
 - data/bin/load_tester +84 -0
 - data/ci_jobs/glowworm-continuous-deploy-next-staging/run.sh +10 -0
 - data/ci_jobs/glowworm-integrations/run.sh +15 -0
 - data/ci_jobs/glowworm-performance/run.sh +2 -0
 - data/ci_jobs/glowworm-robustness/run.sh +2 -0
 - data/ci_jobs/glowworm-units/run.sh +13 -0
 - data/ci_jobs/setup.sh +119 -0
 - data/example/example_server.ecology +6 -0
 - data/example/example_server.rb +32 -0
 - data/glowworm.gemspec +54 -0
 - data/lib/glowworm.rb +501 -0
 - data/lib/glowworm/em.rb +8 -0
 - data/lib/glowworm/no_bg.rb +2 -0
 - data/lib/glowworm/version.rb +3 -0
 - data/server/Gemfile +27 -0
 - data/server/Gemfile.lock +87 -0
 - data/server/PROTOCOL +39 -0
 - data/server/check_mk_checks/check_glowworm_server +43 -0
 - data/server/db_migrations/20111004214649_change_feature_accounts_to_string.rb +60 -0
 - data/server/db_migrations/20111028104546_add_value_to_account_set_features.rb +12 -0
 - data/server/db_migrations/20120217090636_add_fully_active_flag_to_features.rb +15 -0
 - data/server/example_test_data.rb +66 -0
 - data/server/glowworm_server.ecology.erb +16 -0
 - data/server/glowworm_server.rb +226 -0
 - data/server/run/server.sh +7 -0
 - data/server/server_test.rb +72 -0
 - data/server/version.rb +3 -0
 - data/test/integration/basic_server_test.rb +90 -0
 - data/test/integration/create_sqlite_data.rb +196 -0
 - data/test/integration/em_server_test.rb +68 -0
 - data/test/integration/gemfile_for_specific_glowworm_version +17 -0
 - data/test/integration/gemfile_for_specific_glowworm_version.lock +55 -0
 - data/test/integration/integration_test_helper.rb +153 -0
 - data/test/integration/load_test.rb +59 -0
 - data/test/integration/nginx.conf +23 -0
 - data/test/integration/server_test.ecology.erb +6 -0
 - data/test/test_helper.rb +47 -0
 - data/test/units/em_test.rb +41 -0
 - data/test/units/feature_flag_test.rb +297 -0
 - data/test/units/no_bg_test.rb +40 -0
 - data/test/units/request_test.rb +51 -0
 - metadata +410 -0
 
| 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/bin/bash -e
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            APP_ROOT=/opt/ooyala/glowworm/current
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            cd $APP_ROOT && \
         
     | 
| 
      
 6 
     | 
    
         
            +
            source $APP_ROOT/config/pushed_environment.rb && \
         
     | 
| 
      
 7 
     | 
    
         
            +
            /opt/ruby/1.9/bin/bundle exec /opt/ruby/1.9/bin/ruby glowworm_server.rb 2>&1 |cronolog --symlink=$SHARED_PATH/log/current $SHARED_PATH/log/glowworm.log.%Y-%m-%d
         
     | 
| 
         @@ -0,0 +1,72 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "rubygems"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "bundler"
         
     | 
| 
      
 3 
     | 
    
         
            +
            Bundler.require(:default, :development)
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "minitest/autorun"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # For testing Glowworm itself, use the local version *first*.
         
     | 
| 
      
 7 
     | 
    
         
            +
            $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "..", "lib")
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            require "glowworm"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            class Scope::TestCase
         
     | 
| 
      
 12 
     | 
    
         
            +
              def set_up_ecology(file_contents, filename = "some.ecology")
         
     | 
| 
      
 13 
     | 
    
         
            +
                ENV["ECOLOGY_SPEC"] = filename
         
     | 
| 
      
 14 
     | 
    
         
            +
                File.expects(:exist?).with(filename).returns(true)
         
     | 
| 
      
 15 
     | 
    
         
            +
                File.expects(:read).with(filename).returns(file_contents)
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            class GlowwormServerTest < Scope::TestCase
         
     | 
| 
      
 20 
     | 
    
         
            +
              def mock_sequel_query(mock_db, name, data)
         
     | 
| 
      
 21 
     | 
    
         
            +
                data_stub = stub(:all => data) do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  stubs(:select).returns(self)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  stubs(:filter).returns(self)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  stubs(:join).returns(self)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  stubs(:right_join).returns(self)
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
                mock_db.stubs(:[]).with(name).returns(data_stub)
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                # Yield each line of data in turn when somebody calls .each
         
     | 
| 
      
 30 
     | 
    
         
            +
                data[1..-1].inject(mock_db.stubs(:each).yields(data[0])) do |expectation, data_item|
         
     | 
| 
      
 31 
     | 
    
         
            +
                  expectation.then.yields(data_item)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
              setup do
         
     | 
| 
      
 36 
     | 
    
         
            +
                set_up_ecology <<JSON
         
     | 
| 
      
 37 
     | 
    
         
            +
            {
         
     | 
| 
      
 38 
     | 
    
         
            +
              "application": "Glowworm Server Test",
         
     | 
| 
      
 39 
     | 
    
         
            +
              "features": {
         
     | 
| 
      
 40 
     | 
    
         
            +
              }
         
     | 
| 
      
 41 
     | 
    
         
            +
            }
         
     | 
| 
      
 42 
     | 
    
         
            +
            JSON
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              context "with mocked test data" do
         
     | 
| 
      
 46 
     | 
    
         
            +
                setup do
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @mock_db = mock("Sequel Database object")
         
     | 
| 
      
 48 
     | 
    
         
            +
                  Sequel.expects(:connect).returns(@mock_db)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  @logger_mock = mock("Termite logger")
         
     | 
| 
      
 50 
     | 
    
         
            +
                  @logger_mock.stubs(:warn => nil, :info => nil, :debug => nil)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  Termite::Logger.expects(:new).returns(@logger_mock)
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                should "Return results for all accounts and features" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                  mock_sequel_query(@mock_db, :account_set_accounts,
         
     | 
| 
      
 56 
     | 
    
         
            +
                                    [
         
     | 
| 
      
 57 
     | 
    
         
            +
                                     {:account => "123", :account_set_id => 1},
         
     | 
| 
      
 58 
     | 
    
         
            +
                                     {:account => "456", :account_set_id => 2},
         
     | 
| 
      
 59 
     | 
    
         
            +
                                    ])
         
     | 
| 
      
 60 
     | 
    
         
            +
                  mock_sequel_query(@mock_db, :account_set_features,
         
     | 
| 
      
 61 
     | 
    
         
            +
                                    [
         
     | 
| 
      
 62 
     | 
    
         
            +
                                     {:name => "foo_feature", :account_set_id => 1}
         
     | 
| 
      
 63 
     | 
    
         
            +
                                    ])
         
     | 
| 
      
 64 
     | 
    
         
            +
                  mock_sequel_query(@mock_db, :feature_account_overrides,
         
     | 
| 
      
 65 
     | 
    
         
            +
                                    [
         
     | 
| 
      
 66 
     | 
    
         
            +
                                     {:name => "foo_feature", :account => "456", :value => true}
         
     | 
| 
      
 67 
     | 
    
         
            +
                                    ])
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  assert true
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
              end
         
     | 
| 
      
 72 
     | 
    
         
            +
            end
         
     | 
    
        data/server/version.rb
    ADDED
    
    
| 
         @@ -0,0 +1,90 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require File.join(File.dirname(__FILE__), "integration_test_helper")
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "net/http"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'multi_json'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "trollop"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require "psych"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            BASIC_SERVER_TESTER_BIN="#{GLOWWORM_ROOT}/bin/basic_server_tester"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            class BasicServerTest < Scope::TestCase
         
     | 
| 
      
 12 
     | 
    
         
            +
              setup_once do
         
     | 
| 
      
 13 
     | 
    
         
            +
                system("ECOLOGY_SPEC=\"#{GLOWWORM_ECOLOGY_FILE}\" #{GLOWWORM_ROOT}/test/integration/create_sqlite_data.rb")
         
     | 
| 
      
 14 
     | 
    
         
            +
                fail "Couldn't create SQLite data successfully!" unless $?.success?
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              context "with Glowworm server and tester" do
         
     | 
| 
      
 18 
     | 
    
         
            +
                setup_once do
         
     | 
| 
      
 19 
     | 
    
         
            +
                  tester_tapy = results_path('basic_server_test.yaml')
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  # The tester command outputs results via TAP-Y and diagnostics to STDERR
         
     | 
| 
      
 22 
     | 
    
         
            +
                  tester_cmd = cmd_in_client_ruby_dist(BASIC_SERVER_TESTER_BIN, "--server #{GW_URI} | tee #{tester_tapy}")
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @topology = start_tester_topology(tester_cmd)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  STDERR.puts "tester status #{@topology[:gw_tester].status}"
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  @tester_results = Psych.parse_stream(IO.read(tester_tapy)).to_ruby
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                teardown_once do
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @topology.stop_all
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  # TODO(noah): Hideous hack until we have real RVM/Nodule integration
         
     | 
| 
      
 34 
     | 
    
         
            +
                  system("pkill -9 -f glowworm_server.rb")
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                should "test server response" do
         
     | 
| 
      
 38 
     | 
    
         
            +
                  contained_summary = false
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @tester_results.each do |tap_entry|
         
     | 
| 
      
 40 
     | 
    
         
            +
                    if "final" == tap_entry["type"]
         
     | 
| 
      
 41 
     | 
    
         
            +
                      contained_summary = true
         
     | 
| 
      
 42 
     | 
    
         
            +
                      counts = tap_entry["counts"]
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                      assert_equal(0, counts["fail"], "tester should have no assertion failures")
         
     | 
| 
      
 45 
     | 
    
         
            +
                      assert_equal(0, counts["error"], "tester should not have encountered any errors")
         
     | 
| 
      
 46 
     | 
    
         
            +
                      assert(counts["total"] > 0, "tester should have performed at least a single test")
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  assert(contained_summary, "the tester must have produced a complete output stream")
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              context "with Glowworm server and threadless tester" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                setup_once do
         
     | 
| 
      
 56 
     | 
    
         
            +
                  tester_tapy = results_path('basic_server_nbg_test.yaml')
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  # The tester command outputs results via TAP-Y and diagnostics to STDERR
         
     | 
| 
      
 59 
     | 
    
         
            +
                  tester_cmd = cmd_in_client_ruby_dist(BASIC_SERVER_TESTER_BIN, "--server #{GW_URI} --nbg true | tee #{tester_tapy}")
         
     | 
| 
      
 60 
     | 
    
         
            +
                  @topology = start_tester_topology(tester_cmd)
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  STDERR.puts "tester status #{@topology[:gw_tester].status}"
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  @tester_results = Psych.parse_stream(IO.read(tester_tapy)).to_ruby
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                teardown_once do
         
     | 
| 
      
 68 
     | 
    
         
            +
                  @topology.stop_all
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  # TODO(noah): Hideous hack until we have real RVM/Nodule integration
         
     | 
| 
      
 71 
     | 
    
         
            +
                  system("pkill -9 -f glowworm_server.rb")
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                should "test server response" do
         
     | 
| 
      
 75 
     | 
    
         
            +
                  contained_summary = false
         
     | 
| 
      
 76 
     | 
    
         
            +
                  @tester_results.each do |tap_entry|
         
     | 
| 
      
 77 
     | 
    
         
            +
                    if "final" == tap_entry["type"]
         
     | 
| 
      
 78 
     | 
    
         
            +
                      contained_summary = true
         
     | 
| 
      
 79 
     | 
    
         
            +
                      counts = tap_entry["counts"]
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                      assert_equal(0, counts["fail"], "tester should have no assertion failures")
         
     | 
| 
      
 82 
     | 
    
         
            +
                      assert_equal(0, counts["error"], "tester should not have encountered any errors")
         
     | 
| 
      
 83 
     | 
    
         
            +
                      assert(counts["total"] > 0, "tester should have performed at least a single test")
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  assert(contained_summary, "the tester must have produced a complete output stream") unless ENV["TEST_GLOWWORM_VERSION"].nil? || ENV["TEST_GLOWWORM_VERSION"] < "0.1.6"
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
              end
         
     | 
| 
      
 90 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,196 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "ecology"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "sequel"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "termite"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            # Can be overridden with ECOLOGY_SPEC
         
     | 
| 
      
 8 
     | 
    
         
            +
            Ecology.read("glowworm_server.ecology")
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            db_spec = Ecology.property("db") || { :adapter => 'sqlite', :database => 'test_data.sqlite' }
         
     | 
| 
      
 11 
     | 
    
         
            +
            STDERR.puts "Connecting to #{db_spec.inspect}"
         
     | 
| 
      
 12 
     | 
    
         
            +
            DB = Sequel.connect db_spec
         
     | 
| 
      
 13 
     | 
    
         
            +
            MyLogger = Termite::Logger.new
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            # The table creation below duplicates a lot of stuff from
         
     | 
| 
      
 16 
     | 
    
         
            +
            # server/db_migrations.  Alas.
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            DB.create_table!(:account_sets) do
         
     | 
| 
      
 19 
     | 
    
         
            +
              primary_key :id
         
     | 
| 
      
 20 
     | 
    
         
            +
              Datetime :created_at, :null => false
         
     | 
| 
      
 21 
     | 
    
         
            +
              Datetime :updated_at, :null => false
         
     | 
| 
      
 22 
     | 
    
         
            +
              String :name, :null => false
         
     | 
| 
      
 23 
     | 
    
         
            +
              String :description
         
     | 
| 
      
 24 
     | 
    
         
            +
              index :name, :unique => true
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            DB.create_table!(:features) do
         
     | 
| 
      
 28 
     | 
    
         
            +
              primary_key :id
         
     | 
| 
      
 29 
     | 
    
         
            +
              Datetime :created_at, :null => false
         
     | 
| 
      
 30 
     | 
    
         
            +
              Datetime :updated_at, :null => false
         
     | 
| 
      
 31 
     | 
    
         
            +
              String :name, :null => false
         
     | 
| 
      
 32 
     | 
    
         
            +
              String :description
         
     | 
| 
      
 33 
     | 
    
         
            +
              Boolean :fully_active, :default => false
         
     | 
| 
      
 34 
     | 
    
         
            +
              index :name, :unique => true
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            DB.create_table!(:account_set_accounts) do
         
     | 
| 
      
 38 
     | 
    
         
            +
              primary_key :id
         
     | 
| 
      
 39 
     | 
    
         
            +
              Datetime :added_at, :null => false
         
     | 
| 
      
 40 
     | 
    
         
            +
              Integer :account_set_id, :null => false
         
     | 
| 
      
 41 
     | 
    
         
            +
              Integer :provider_id, :null => true
         
     | 
| 
      
 42 
     | 
    
         
            +
              String :account, :limit => 10, :null => false
         
     | 
| 
      
 43 
     | 
    
         
            +
              index :account_set_id
         
     | 
| 
      
 44 
     | 
    
         
            +
              index :provider_id
         
     | 
| 
      
 45 
     | 
    
         
            +
              index :account
         
     | 
| 
      
 46 
     | 
    
         
            +
              index [:account_set_id, :account], :unique => true
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            DB.create_table!(:account_set_features) do
         
     | 
| 
      
 50 
     | 
    
         
            +
              primary_key :id
         
     | 
| 
      
 51 
     | 
    
         
            +
              Datetime :added_at, :null => false
         
     | 
| 
      
 52 
     | 
    
         
            +
              Integer :account_set_id, :null => false
         
     | 
| 
      
 53 
     | 
    
         
            +
              Integer :feature_id, :null => false
         
     | 
| 
      
 54 
     | 
    
         
            +
              Integer :value, :null => false, :default => 1
         
     | 
| 
      
 55 
     | 
    
         
            +
              index :feature_id
         
     | 
| 
      
 56 
     | 
    
         
            +
              index [:account_set_id, :feature_id], :unique => true
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            DB.create_table!(:feature_account_overrides) do
         
     | 
| 
      
 60 
     | 
    
         
            +
              Integer :provider_id, :null => true
         
     | 
| 
      
 61 
     | 
    
         
            +
              String :account, :limit => 10, :null => false
         
     | 
| 
      
 62 
     | 
    
         
            +
              Integer :feature_id, :null => false
         
     | 
| 
      
 63 
     | 
    
         
            +
              Integer :value, :null => false
         
     | 
| 
      
 64 
     | 
    
         
            +
              index :provider_id
         
     | 
| 
      
 65 
     | 
    
         
            +
              index :feature_id
         
     | 
| 
      
 66 
     | 
    
         
            +
              index [:account, :feature_id], :unique => true
         
     | 
| 
      
 67 
     | 
    
         
            +
            end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            # Probably gone already, but let's be sure.
         
     | 
| 
      
 70 
     | 
    
         
            +
            DB[:account_sets].delete
         
     | 
| 
      
 71 
     | 
    
         
            +
            DB[:features].delete
         
     | 
| 
      
 72 
     | 
    
         
            +
            DB[:account_set_accounts].delete
         
     | 
| 
      
 73 
     | 
    
         
            +
            DB[:account_set_features].delete
         
     | 
| 
      
 74 
     | 
    
         
            +
            DB[:feature_account_overrides].delete
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            def unique_id
         
     | 
| 
      
 77 
     | 
    
         
            +
              @id_counter ||= 10_000
         
     | 
| 
      
 78 
     | 
    
         
            +
              @id_counter += 1
         
     | 
| 
      
 79 
     | 
    
         
            +
              @id_counter
         
     | 
| 
      
 80 
     | 
    
         
            +
            end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
            # "Hello, world" for features - feature_flag(123, "foo") should return true.
         
     | 
| 
      
 83 
     | 
    
         
            +
            FOO_FEATURE = 1
         
     | 
| 
      
 84 
     | 
    
         
            +
            DB[:features].insert(:id => FOO_FEATURE, :name => "foo", :description => "hello world feature",
         
     | 
| 
      
 85 
     | 
    
         
            +
                                 :created_at => Time.now, :updated_at => Time.now)
         
     | 
| 
      
 86 
     | 
    
         
            +
            DB[:feature_account_overrides].insert(:account => "123", :provider_id => 123, :feature_id => FOO_FEATURE,
         
     | 
| 
      
 87 
     | 
    
         
            +
                                                  :value => 1)
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            # Accounts sets for basic testing
         
     | 
| 
      
 90 
     | 
    
         
            +
            ONE_HORSE_TOWN = 1
         
     | 
| 
      
 91 
     | 
    
         
            +
            DB[:account_sets].insert(:id => ONE_HORSE_TOWN, :name => "solo", :description => "one-horse town",
         
     | 
| 
      
 92 
     | 
    
         
            +
                                     :created_at => Time.now, :updated_at => Time.now)
         
     | 
| 
      
 93 
     | 
    
         
            +
            TWO_HORSE_TOWN = 2
         
     | 
| 
      
 94 
     | 
    
         
            +
            DB[:account_sets].insert(:id => TWO_HORSE_TOWN, :name => "duo", :description => "two-horse town",
         
     | 
| 
      
 95 
     | 
    
         
            +
                                     :created_at => Time.now, :updated_at => Time.now)
         
     | 
| 
      
 96 
     | 
    
         
            +
            NO_HORSE_TOWN = 3
         
     | 
| 
      
 97 
     | 
    
         
            +
            DB[:account_sets].insert(:id => NO_HORSE_TOWN, :name => "nowhere", :description => "no-horse town",
         
     | 
| 
      
 98 
     | 
    
         
            +
                                     :created_at => Time.now, :updated_at => Time.now)
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
            # Account sets for get_value testing
         
     | 
| 
      
 101 
     | 
    
         
            +
            LOW_ID_SET = 4
         
     | 
| 
      
 102 
     | 
    
         
            +
            DB[:account_sets].insert(:id => LOW_ID_SET, :name => "low-id", :description => "acct set, low id #",
         
     | 
| 
      
 103 
     | 
    
         
            +
                                     :created_at => Time.now, :updated_at => Time.now)
         
     | 
| 
      
 104 
     | 
    
         
            +
            BIG_VALUE_SET = 5
         
     | 
| 
      
 105 
     | 
    
         
            +
            DB[:account_sets].insert(:id => BIG_VALUE_SET, :name => "big-val",
         
     | 
| 
      
 106 
     | 
    
         
            +
                                     :description => "acct set, big value",
         
     | 
| 
      
 107 
     | 
    
         
            +
                                     :created_at => Time.now, :updated_at => Time.now)
         
     | 
| 
      
 108 
     | 
    
         
            +
            LITTLE_VALUE_SET = 6
         
     | 
| 
      
 109 
     | 
    
         
            +
            DB[:account_sets].insert(:id => LITTLE_VALUE_SET, :name => "little-val",
         
     | 
| 
      
 110 
     | 
    
         
            +
                                     :description => "acct set, little value",
         
     | 
| 
      
 111 
     | 
    
         
            +
                                     :created_at => Time.now, :updated_at => Time.now)
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
            VALUE_FOR_ACCT_SET = {
         
     | 
| 
      
 114 
     | 
    
         
            +
              ONE_HORSE_TOWN => 1,
         
     | 
| 
      
 115 
     | 
    
         
            +
              TWO_HORSE_TOWN => 2,
         
     | 
| 
      
 116 
     | 
    
         
            +
              BIG_VALUE_SET => 100,
         
     | 
| 
      
 117 
     | 
    
         
            +
              LITTLE_VALUE_SET => 7,
         
     | 
| 
      
 118 
     | 
    
         
            +
              LOW_ID_SET => 21,
         
     | 
| 
      
 119 
     | 
    
         
            +
            }
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
            # Features in 0, 1 and 2 account sets, with no override, true override and false override
         
     | 
| 
      
 122 
     | 
    
         
            +
            [false, true].each do |fully_active|
         
     | 
| 
      
 123 
     | 
    
         
            +
              [nil, true, false].each do |override|
         
     | 
| 
      
 124 
     | 
    
         
            +
                [[],
         
     | 
| 
      
 125 
     | 
    
         
            +
                 [ONE_HORSE_TOWN],
         
     | 
| 
      
 126 
     | 
    
         
            +
                 [ONE_HORSE_TOWN, TWO_HORSE_TOWN],
         
     | 
| 
      
 127 
     | 
    
         
            +
                ].each do |acct_sets|
         
     | 
| 
      
 128 
     | 
    
         
            +
                  offset = override.nil? ? 0 : (override == true ? 1 : 2)
         
     | 
| 
      
 129 
     | 
    
         
            +
                  offset += 3 if fully_active
         
     | 
| 
      
 130 
     | 
    
         
            +
                  num_accts = acct_sets.size
         
     | 
| 
      
 131 
     | 
    
         
            +
                  id = 1000 + offset * 100 + num_accts
         
     | 
| 
      
 132 
     | 
    
         
            +
                  desc = "#{fully_active ? "Fully Active " : ""}Feature w/ #{num_accts} acct sets and override #{override.inspect}"
         
     | 
| 
      
 133 
     | 
    
         
            +
                  account = "account_for_acct_sets_#{num_accts}_#{override.inspect}"
         
     | 
| 
      
 134 
     | 
    
         
            +
                  feature = "#{fully_active ? "fully_active_" : ""}feature_for_acct_sets_#{num_accts}_#{override.inspect}"
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                  DB[:features].insert(:id => id, :name => feature, :description => desc,
         
     | 
| 
      
 137 
     | 
    
         
            +
                                       :created_at => Time.now, :updated_at => Time.now, :fully_active => fully_active)
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                  acct_sets.each do |acct_set|
         
     | 
| 
      
 140 
     | 
    
         
            +
                    DB[:account_set_accounts].insert(:id => unique_id, :account_set_id => acct_set, :account => account,
         
     | 
| 
      
 141 
     | 
    
         
            +
                                                     :added_at => Time.now) unless fully_active # Only need to do this once
         
     | 
| 
      
 142 
     | 
    
         
            +
                    DB[:account_set_features].insert(:id => unique_id, :account_set_id => acct_set, :feature_id => id,
         
     | 
| 
      
 143 
     | 
    
         
            +
                                                     :value => fully_active ? 0 : 1, :added_at => Time.now) # Opposite of default
         
     | 
| 
      
 144 
     | 
    
         
            +
                  end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                  case override
         
     | 
| 
      
 147 
     | 
    
         
            +
                  when true
         
     | 
| 
      
 148 
     | 
    
         
            +
                    DB[:feature_account_overrides].insert(:account => account, :feature_id => id, :value => 1)
         
     | 
| 
      
 149 
     | 
    
         
            +
                  when false
         
     | 
| 
      
 150 
     | 
    
         
            +
                    DB[:feature_account_overrides].insert(:account => account, :feature_id => id, :value => 0)
         
     | 
| 
      
 151 
     | 
    
         
            +
                  when nil
         
     | 
| 
      
 152 
     | 
    
         
            +
                    # No-op
         
     | 
| 
      
 153 
     | 
    
         
            +
                  else
         
     | 
| 
      
 154 
     | 
    
         
            +
                    raise "Illegal value for override!"
         
     | 
| 
      
 155 
     | 
    
         
            +
                  end
         
     | 
| 
      
 156 
     | 
    
         
            +
                end
         
     | 
| 
      
 157 
     | 
    
         
            +
              end
         
     | 
| 
      
 158 
     | 
    
         
            +
            end
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
            [nil, 0, 1, 2, 5].each do |override|
         
     | 
| 
      
 161 
     | 
    
         
            +
              counter = 0
         
     | 
| 
      
 162 
     | 
    
         
            +
              [[],
         
     | 
| 
      
 163 
     | 
    
         
            +
               [LITTLE_VALUE_SET],
         
     | 
| 
      
 164 
     | 
    
         
            +
               [BIG_VALUE_SET, LITTLE_VALUE_SET],
         
     | 
| 
      
 165 
     | 
    
         
            +
               [BIG_VALUE_SET, LITTLE_VALUE_SET, LOW_ID_SET]].each do |acct_sets|
         
     | 
| 
      
 166 
     | 
    
         
            +
                acct_key = acct_sets.map(&:to_s).join("/")
         
     | 
| 
      
 167 
     | 
    
         
            +
                id = 2000 + (override.nil? ? 0 : override + 1) * 100 + counter
         
     | 
| 
      
 168 
     | 
    
         
            +
                counter += 1
         
     | 
| 
      
 169 
     | 
    
         
            +
                desc = "Feature w/ value and  w/ acct sets #{acct_key} and override #{override.inspect}"
         
     | 
| 
      
 170 
     | 
    
         
            +
                account = "account_for_value_acct_sets_#{acct_key}_#{override.inspect}"
         
     | 
| 
      
 171 
     | 
    
         
            +
                feature = "feature_for_value_acct_sets_#{acct_key}_#{override.inspect}"
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
                DB[:features].insert(:id => id, :name => feature, :description => desc,
         
     | 
| 
      
 174 
     | 
    
         
            +
                                     :created_at => Time.now, :updated_at => Time.now)
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                acct_sets.each do |acct_set|
         
     | 
| 
      
 177 
     | 
    
         
            +
                  DB[:account_set_accounts].insert(:id => unique_id, :account_set_id => acct_set, :account => account,
         
     | 
| 
      
 178 
     | 
    
         
            +
                                                   :added_at => Time.now)
         
     | 
| 
      
 179 
     | 
    
         
            +
                  DB[:account_set_features].insert(:id => unique_id, :account_set_id => acct_set, :feature_id => id,
         
     | 
| 
      
 180 
     | 
    
         
            +
                                                   :value => VALUE_FOR_ACCT_SET[acct_set], :added_at => Time.now)
         
     | 
| 
      
 181 
     | 
    
         
            +
                end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                if override != nil
         
     | 
| 
      
 184 
     | 
    
         
            +
                  DB[:feature_account_overrides].insert(:account => account, :feature_id => id,
         
     | 
| 
      
 185 
     | 
    
         
            +
                                                        :value => override)
         
     | 
| 
      
 186 
     | 
    
         
            +
                end
         
     | 
| 
      
 187 
     | 
    
         
            +
              end
         
     | 
| 
      
 188 
     | 
    
         
            +
            end
         
     | 
| 
      
 189 
     | 
    
         
            +
             
     | 
| 
      
 190 
     | 
    
         
            +
            $stderr.puts "Features: #{DB[:features].count}"
         
     | 
| 
      
 191 
     | 
    
         
            +
            $stderr.puts "Account Sets: #{DB[:account_sets].count}"
         
     | 
| 
      
 192 
     | 
    
         
            +
            $stderr.puts "Accounts/set joins: #{DB[:account_set_accounts].count}"
         
     | 
| 
      
 193 
     | 
    
         
            +
            $stderr.puts "Set/feature joins: #{DB[:account_set_features].count}"
         
     | 
| 
      
 194 
     | 
    
         
            +
            $stderr.puts "Overrides: #{DB[:feature_account_overrides].count}"
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
            $stderr.puts "Added test data successfully!"
         
     | 
| 
         @@ -0,0 +1,68 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require File.join(File.dirname(__FILE__), "integration_test_helper")
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "net/http"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'multi_json'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "trollop"
         
     | 
| 
      
 7 
     | 
    
         
            +
            require "psych"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            EM_SERVER_TESTER_BIN = "#{GLOWWORM_ROOT}/bin/em_server_tester"
         
     | 
| 
      
 10 
     | 
    
         
            +
            EM_SERVER_CONFIG = "#{GLOWWORM_ROOT}/bin/em_server/config.ru"
         
     | 
| 
      
 11 
     | 
    
         
            +
            EM_PORT = Nodule::Util.random_tcp_port
         
     | 
| 
      
 12 
     | 
    
         
            +
            EM_HOST = "http://localhost:#{EM_PORT}"
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            class EMServerTest < Scope::TestCase
         
     | 
| 
      
 15 
     | 
    
         
            +
              setup_once do
         
     | 
| 
      
 16 
     | 
    
         
            +
                system("ECOLOGY_SPEC=\"#{GLOWWORM_ECOLOGY_FILE}\" #{GLOWWORM_ROOT}/test/integration/create_sqlite_data.rb")
         
     | 
| 
      
 17 
     | 
    
         
            +
                fail "Couldn't create SQLite data successfully!" unless $?.success?
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              context "with Glowworm server and tester" do
         
     | 
| 
      
 21 
     | 
    
         
            +
                setup_once do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  tester_tapy = results_path('em_server_test.yaml')
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  # The tester command outputs results via TAP-Y and diagnostics to STDERR
         
     | 
| 
      
 25 
     | 
    
         
            +
                  tester_cmd = cmd_in_client_ruby_dist(EM_SERVER_TESTER_BIN, "--server #{EM_HOST} | tee #{tester_tapy}")
         
     | 
| 
      
 26 
     | 
    
         
            +
                  # The tester may be run under ruby 1.8. Fake like 1.9 by using RUBYOPT to include rubygems
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # support
         
     | 
| 
      
 28 
     | 
    
         
            +
                  em_server = {
         
     | 
| 
      
 29 
     | 
    
         
            +
                    :em_server    => Nodule::Process.new({
         
     | 
| 
      
 30 
     | 
    
         
            +
                      "ECOLOGY_SPEC" => GLOWWORM_ECOLOGY_FILE,
         
     | 
| 
      
 31 
     | 
    
         
            +
                      "GW_URI"  => GW_URI,
         
     | 
| 
      
 32 
     | 
    
         
            +
                      "GLOWWORM_ROOT" => GLOWWORM_ROOT },
         
     | 
| 
      
 33 
     | 
    
         
            +
                      "bash", "-l", "-c", "cd #{GLOWWORM_ROOT} && bundle exec thin -p #{EM_PORT} -R #{EM_SERVER_CONFIG} start",
         
     | 
| 
      
 34 
     | 
    
         
            +
                      :stdout => :capture, :stderr => :capture, :verbose => :cyanio
         
     | 
| 
      
 35 
     | 
    
         
            +
                    )
         
     | 
| 
      
 36 
     | 
    
         
            +
                  }
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @topology = start_tester_topology(tester_cmd, 10, em_server)
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  STDERR.puts "tester status #{@topology[:gw_tester].status}"
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  @tester_results = Psych.parse_stream(IO.read(tester_tapy)).to_ruby
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                teardown_once do
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @topology.stop_all
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  # TODO(noah): Hideous hack until we have real RVM/Nodule integration
         
     | 
| 
      
 48 
     | 
    
         
            +
                  system("pkill -9 -f glowworm_server.rb")
         
     | 
| 
      
 49 
     | 
    
         
            +
                  system("pkill -9 -f thin")
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                should "test server response" do
         
     | 
| 
      
 53 
     | 
    
         
            +
                  contained_summary = false
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @tester_results.each do |tap_entry|
         
     | 
| 
      
 55 
     | 
    
         
            +
                    if "final" == tap_entry["type"]
         
     | 
| 
      
 56 
     | 
    
         
            +
                      contained_summary = true
         
     | 
| 
      
 57 
     | 
    
         
            +
                      counts = tap_entry["counts"]
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                      assert_equal(0, counts["fail"], "tester should have no assertion failures")
         
     | 
| 
      
 60 
     | 
    
         
            +
                      assert_equal(0, counts["error"], "tester should not have encountered any errors")
         
     | 
| 
      
 61 
     | 
    
         
            +
                      assert(counts["total"] > 0, "tester should have performed at least a single test")
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  assert(contained_summary, "the tester must have produced a complete output stream")
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            source "http://rubygems.org"
         
     | 
| 
      
 2 
     | 
    
         
            +
            source "http://gems.sv2"  # Ooyala-specific!
         
     | 
| 
      
 3 
     | 
    
         
            +
            source "http://gems.us-east-1.ooyala.com:8080"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            fail "requires TEST_GLOWWORM_VERSION in environment" unless ENV['TEST_GLOWWORM_VERSION']
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            gem "glowworm", ENV['TEST_GLOWWORM_VERSION']
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            # plus development dependencies
         
     | 
| 
      
 10 
     | 
    
         
            +
            gem "ansi"
         
     | 
| 
      
 11 
     | 
    
         
            +
            gem "minitap", ">=0.3.5"
         
     | 
| 
      
 12 
     | 
    
         
            +
            gem "minitest"
         
     | 
| 
      
 13 
     | 
    
         
            +
            gem "mocha"
         
     | 
| 
      
 14 
     | 
    
         
            +
            gem "rake"
         
     | 
| 
      
 15 
     | 
    
         
            +
            gem "scope"
         
     | 
| 
      
 16 
     | 
    
         
            +
            gem "tapout"
         
     | 
| 
      
 17 
     | 
    
         
            +
            gem "httparty"
         
     |