├── .gitignore ├── .rspec ├── .ruby-gemset ├── .ruby-version ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── lib ├── generators │ └── rails │ │ ├── hook │ │ ├── hook_generator.rb │ │ └── templates │ │ │ └── hook.rb │ │ └── install │ │ ├── install_generator.rb │ │ └── templates │ │ └── initializer.rb.erb ├── pokey.rb └── pokey │ ├── configuration.rb │ ├── helpers │ └── inflector.rb │ ├── hook.rb │ ├── hooks.rb │ ├── logger.rb │ ├── request.rb │ ├── scheduler.rb │ └── version.rb ├── pokey.gemspec └── spec ├── pokey ├── configure_spec.rb ├── hook_spec.rb ├── hooks_spec.rb ├── request_spec.rb ├── sample_hooks │ ├── another_sample_hook.rb │ └── sample_hook.rb └── scheduler_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | mkmf.log 15 | *.swp 16 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | pokey 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.2.2 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in pokey.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Chuck Callebs 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pokey 2 | 3 | [![Gem Version](https://badge.fury.io/rb/pokey.svg)](http://badge.fury.io/rb/pokey) [![Code Climate](https://codeclimate.com/github/ccallebs/pokey/badges/gpa.svg)](https://codeclimate.com/github/ccallebs/pokey) 4 | 5 | Pokey is a Ruby gem designed to easily simulate webhooks / other HTTP requests common 6 | to a production environment. 7 | 8 | ## Installation 9 | 10 | Add this line to your application's Gemfile: 11 | 12 | ```ruby 13 | gem 'pokey' 14 | ``` 15 | 16 | And then execute: 17 | 18 | $ bundle 19 | 20 | Or install it yourself as: 21 | 22 | $ gem install pokey 23 | 24 | ## Usage 25 | 26 | If you're using Rails, create the initializer by running: 27 | 28 | $ rails g pokey:install 29 | 30 | Otherwise, create a new file in your initializers directory named `pokey.rb`. You'll be 31 | setting the default hook directory and (optionally) defining custom hooks here. 32 | 33 | ``` RUBY 34 | Pokey.configure do |config| 35 | config.hook_dir = "app/pokey" # Defaults to app/pokey 36 | config.run_on = [:development, :qa] # Only set environments you want pokey to 37 | # simulate requests for. If not using Rails, 38 | # this currently has no effect 39 | 40 | config.add_hook do |hook| 41 | hook.destination = "/my/webhook/endpoint" 42 | hook.data = { 43 | name: "Test endpoint", 44 | endpoint_id: 1 45 | } 46 | hook.interval = 20 # in seconds 47 | hook.http_method = :post # supports GET and POST for right now 48 | end 49 | end 50 | ``` 51 | 52 | If you would like to add many hooks to your project, you can place them in the `hook_dir` 53 | you specified in the initializer. Please note that **each file** must have a `_hook.rb` 54 | suffix. If you're using Rails, you can run 55 | 56 | $ rails g pokey:hook sendgrid_event 57 | 58 | to create a new `Pokey::Hook` template. Otherwise, create a file like the following: 59 | 60 | ``` RUBY 61 | # app/pokey/my_custom_hook.rb 62 | class MyCustomHook < Pokey::Hook 63 | # The API endpoint to hit 64 | def destination 65 | end 66 | 67 | # The data to pass along to the API endpoint 68 | def data 69 | { } 70 | end 71 | 72 | # The HTTP method to use (only supports GET/POST right now) 73 | def http_method 74 | :post 75 | end 76 | 77 | # Time (in seconds) between requests 78 | def interval 79 | 5 80 | end 81 | end 82 | ``` 83 | 84 | As your data will inevitably get more complex to simulate actual events, 85 | `Pokey::Hook` subclasses are preferred over ad-hoc hook definitions. 86 | 87 | ## Pre-made Hooks 88 | I'm attempting to create a suite of pre-made hooks to make simulating 89 | production data easier. Here is a list: 90 | 91 | - https://github.com/ccallebs/pokey-sendgrid 92 | 93 | ## Contributing 94 | 95 | 1. Fork it ( https://github.com/ccallebs/pokey/fork ) 96 | 2. Create your feature branch (`git checkout -b my-new-feature`) 97 | 3. Commit your changes (`git commit -am 'Add some feature'`) 98 | 4. Push to the branch (`git push origin my-new-feature`) 99 | 5. Create a new Pull Request 100 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | -------------------------------------------------------------------------------- /lib/generators/rails/hook/hook_generator.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators' 2 | 3 | module Pokey 4 | module Generators 5 | class HookGenerator < Rails::Generators::NamedBase 6 | desc "Generates a Pokey hook" 7 | check_class_collision suffix: "Hook" 8 | 9 | source_root File.expand_path("../templates", __FILE__) 10 | 11 | def create_hook_file 12 | template "hook.rb", "#{Pokey.hook_dir}/#{file_path.tr('/', '_')}_hook.rb" 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/generators/rails/hook/templates/hook.rb: -------------------------------------------------------------------------------- 1 | class <%= class_name %>Hook < Pokey::Hook 2 | def destination 3 | end 4 | 5 | def data 6 | end 7 | 8 | def interval 9 | end 10 | 11 | def http_method 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/generators/rails/install/install_generator.rb: -------------------------------------------------------------------------------- 1 | require 'rails/generators' 2 | 3 | module Pokey 4 | module Generators 5 | class InstallGenerator < Rails::Generators::Base 6 | source_root File.expand_path("../templates", __FILE__) 7 | 8 | def copy_initializer 9 | template "initializer.rb.erb", "config/initializers/pokey.rb" 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/generators/rails/install/templates/initializer.rb.erb: -------------------------------------------------------------------------------- 1 | Pokey.configure do |config| 2 | config.hook_dir = "app/hooks" 3 | 4 | config.run_on = [:development, :qa] # Only set environments you want pokey 5 | # to simulate requests for 6 | 7 | # Add some hooks on-the-fly here. If your data is somewhat complicated, add 8 | # a hook instead with `rails g pokey:hook hook_name` 9 | # config.add_hook do |hook| 10 | # hook.destination = "/my/webhook/endpoint" 11 | # hook.data = { 12 | # name: "Test endpoint" 13 | # } 14 | # hook.interval = 120 # in seconds 15 | # hook.http_method = :post 16 | # end 17 | end 18 | -------------------------------------------------------------------------------- /lib/pokey.rb: -------------------------------------------------------------------------------- 1 | require "pokey/version" 2 | require "pokey/configuration" 3 | require "pokey/hook" 4 | require "pokey/hooks" 5 | require "pokey/logger" 6 | require "pokey/request" 7 | require "pokey/scheduler" 8 | 9 | if defined?(Rails) 10 | require "generators/rails/install/install_generator" 11 | require "generators/rails/hook/hook_generator" 12 | end 13 | 14 | module Pokey 15 | class << self 16 | attr_writer :configuration 17 | 18 | def configure 19 | yield(configuration) 20 | Pokey::Scheduler.run! if should_run? 21 | end 22 | 23 | def configuration 24 | @configuration ||= Pokey::Configuration.new 25 | end 26 | 27 | def hook_dir=(val) 28 | configuration.hook_dir = val 29 | end 30 | 31 | def hook_dir 32 | configuration.hook_dir 33 | end 34 | 35 | def accessible_environments 36 | configuration.run_on.map(&:to_s) 37 | end 38 | 39 | def should_run? 40 | current_env.nil? || accessible_environments.include?(current_env) 41 | end 42 | 43 | def current_env 44 | if defined?(Rails) 45 | Rails.env 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/pokey/configuration.rb: -------------------------------------------------------------------------------- 1 | class Pokey::Configuration 2 | attr_accessor :hook_dir, :hooks, :run_on 3 | 4 | def initialize 5 | @hook_dir = "app/pokey" 6 | @hooks = [] 7 | @run_on = [:development] 8 | end 9 | 10 | def add_hook(&block) 11 | Pokey::Hooks.add(&block) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/pokey/helpers/inflector.rb: -------------------------------------------------------------------------------- 1 | module Helpers 2 | class Inflector 3 | # File activesupport/lib/active_support/inflector/methods.rb, line 249 4 | def self.constantize(camel_cased_word) 5 | names = camel_cased_word.split('::') 6 | 7 | # Trigger a built-in NameError exception including the ill-formed constant in the message. 8 | Object.const_get(camel_cased_word) if names.empty? 9 | 10 | # Remove the first blank element in case of '::ClassName' notation. 11 | names.shift if names.size > 1 && names.first.empty? 12 | 13 | names.inject(Object) do |constant, name| 14 | if constant == Object 15 | constant.const_get(name) 16 | else 17 | candidate = constant.const_get(name) 18 | next candidate if constant.const_defined?(name, false) 19 | next candidate unless Object.const_defined?(name) 20 | 21 | # Go down the ancestors to check if it is owned directly. The check 22 | # stops when we reach Object or the end of ancestors tree. 23 | constant = constant.ancestors.inject do |const, ancestor| 24 | break const if ancestor == Object 25 | break ancestor if ancestor.const_defined?(name, false) 26 | const 27 | end 28 | 29 | # owner is in Object, so raise 30 | constant.const_get(name, false) 31 | end 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/pokey/hook.rb: -------------------------------------------------------------------------------- 1 | class Pokey::Hook 2 | attr_accessor :destination, :http_method, :data, :interval 3 | 4 | def initialize 5 | @http_method = :post 6 | @data = {} 7 | end 8 | 9 | def make_http_request! 10 | Pokey::Request.make!(destination, http_method, data) 11 | end 12 | 13 | def valid? 14 | validate_http_method! 15 | validate_interval! 16 | validate_destination! 17 | true 18 | end 19 | 20 | private 21 | 22 | def validate_http_method! 23 | raise Pokey::InvalidHTTPMethodError unless [:get, :post].include?(@http_method) 24 | end 25 | 26 | def validate_destination! 27 | raise Pokey::InvalidDestinationError if destination.nil? || destination == "" 28 | end 29 | 30 | def validate_interval! 31 | raise Pokey::InvalidIntervalError if @interval.nil? || @interval.zero? 32 | end 33 | end 34 | 35 | class Pokey::InvalidHTTPMethodError < Exception; end; 36 | class Pokey::InvalidDestinationError < Exception; end; 37 | class Pokey::InvalidIntervalError < Exception; end; 38 | -------------------------------------------------------------------------------- /lib/pokey/hooks.rb: -------------------------------------------------------------------------------- 1 | require 'pokey/helpers/inflector' 2 | 3 | class Pokey::Hooks 4 | @@hooks = [] 5 | 6 | def self.clear! 7 | @@hooks = [] 8 | end 9 | 10 | def self.all 11 | @@hooks 12 | end 13 | 14 | def self.count 15 | @@hooks.length 16 | end 17 | 18 | def self.add(&block) 19 | hook = Pokey::Hook.new 20 | block.call(hook) 21 | @@hooks << hook if hook.valid? 22 | end 23 | 24 | def self.add_from_class(klass) 25 | return unless klass 26 | @@hooks << klass.new 27 | end 28 | 29 | def self.add_from_dir(directory) 30 | directory += "/" if directory[-1] != "/" 31 | fetch_real_path = File.method(:realpath).to_proc 32 | files = Dir.glob("#{directory}*.rb").map { |f| fetch_real_path.call(f) } 33 | 34 | files.each do |file_path| 35 | require file_path 36 | 37 | base_name = File.basename(file_path, ".rb") 38 | klass = Helpers::Inflector.constantize(base_name.split('_').collect(&:capitalize).join) 39 | add_from_class(klass) 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /lib/pokey/logger.rb: -------------------------------------------------------------------------------- 1 | require 'logging' 2 | 3 | Logging.logger.root.appenders = Logging.appenders.stdout 4 | Logging.logger.root.level = :info 5 | 6 | class Pokey::Logger 7 | attr_reader :log 8 | 9 | def initialize 10 | @log = Logging.logger[self] 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/pokey/request.rb: -------------------------------------------------------------------------------- 1 | # Handles making the request to the webhook destination 2 | 3 | require 'net/http' 4 | 5 | class Pokey::Request 6 | attr_accessor :destination, :http_method, :data 7 | 8 | def initialize(destination, http_method = :post, data = {}) 9 | @destination, @http_method, @data = destination, http_method, data 10 | @log = Pokey::Logger.new.log 11 | end 12 | 13 | def raw_request 14 | http_object 15 | end 16 | 17 | def make! 18 | Net::HTTP.start(uri.host, uri.port) do |http| 19 | request = raw_request 20 | 21 | if request.is_a?(Net::HTTP::Post) 22 | request.set_form_data(@data) 23 | end 24 | 25 | response = http.request(request) 26 | 27 | if response 28 | @log.info "Made request to #{uri.host}:#{uri.port} with following data: #{@data}" 29 | end 30 | end 31 | end 32 | 33 | def uri 34 | raw_uri = URI.parse(@destination) 35 | 36 | if @http_method == :get 37 | raw_uri.query = URI.encode_www_form(@data) 38 | end 39 | 40 | raw_uri 41 | end 42 | 43 | def self.make!(destination, http_method, data) 44 | request = Pokey::Request.new(destination, http_method, data) 45 | request.make! 46 | request 47 | end 48 | 49 | private 50 | 51 | def http_object 52 | @http_object ||= begin 53 | if @http_method == :get 54 | Net::HTTP::Get.new(uri) 55 | elsif @http_method == :post 56 | Net::HTTP::Post.new(uri) 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/pokey/scheduler.rb: -------------------------------------------------------------------------------- 1 | require "rufus-scheduler" 2 | 3 | class Pokey::Scheduler 4 | def rufus 5 | @rufus ||= Rufus::Scheduler.new 6 | end 7 | 8 | def self.run! 9 | scheduler = new 10 | 11 | Pokey::Hooks.add_from_dir(Pokey.hook_dir) 12 | 13 | Pokey::Hooks.all.each do |hook| 14 | scheduler.rufus.every "#{hook.interval}s" do 15 | hook.make_http_request! 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/pokey/version.rb: -------------------------------------------------------------------------------- 1 | module Pokey 2 | VERSION = "0.2.0".freeze 3 | end 4 | -------------------------------------------------------------------------------- /pokey.gemspec: -------------------------------------------------------------------------------- 1 | require './lib/pokey/version' 2 | 3 | Gem::Specification.new do |spec| 4 | spec.name = "pokey" 5 | spec.version = Pokey::VERSION.dup 6 | spec.authors = ["Chuck Callebs"] 7 | spec.email = ["chuck@callebs.io"] 8 | spec.summary = %q{Automatically create HTTP requests in the background.} 9 | spec.description = %q{Automatically create HTTP requests in the background. You can use 10 | Pokey to simulate production webhooks on QA/development environments.} 11 | spec.homepage = "https://github.com/ccallebs/pokey" 12 | spec.license = "MIT" 13 | 14 | spec.files = `git ls-files -z`.split("\x0") 15 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 16 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 17 | 18 | spec.add_runtime_dependency 'rufus-scheduler', '~> 3.1.2' 19 | spec.add_runtime_dependency 'logging' 20 | 21 | spec.add_development_dependency "bundler", "~> 1.7" 22 | spec.add_development_dependency "rake", "~> 10.0" 23 | spec.add_development_dependency "rspec", "~> 3.2" 24 | spec.add_development_dependency "pry" 25 | spec.add_development_dependency "webmock" 26 | end 27 | -------------------------------------------------------------------------------- /spec/pokey/configure_spec.rb: -------------------------------------------------------------------------------- 1 | require "./lib/pokey" 2 | 3 | describe Pokey do 4 | describe "#configure" do 5 | describe "#hook_dir" do 6 | it "defaults to app/pokey" do 7 | Pokey.configure do |config| 8 | end 9 | 10 | expect(Pokey.hook_dir).to eq("app/pokey") 11 | end 12 | end 13 | 14 | describe "#hook_dir=" do 15 | it "sets value of #hook_dir successfully" do 16 | Pokey.configure do |config| 17 | config.hook_dir = "app/new_hook_dir" 18 | end 19 | 20 | expect(Pokey.hook_dir).to eq("app/new_hook_dir") 21 | end 22 | end 23 | 24 | describe "#add_hook" do 25 | it "increases hook count by 1" do 26 | expect { 27 | Pokey.configure do |config| 28 | config.add_hook do |hook| 29 | hook.destination = "/endpoint" 30 | hook.data = {} 31 | hook.interval = 3600 32 | end 33 | end 34 | }.to change { Pokey::Hooks.count }.by(1) 35 | end 36 | end 37 | end 38 | 39 | describe "#should_run?" do 40 | context "when configured for current Rails.env" do 41 | before do 42 | allow(Pokey).to receive(:current_env).and_return("development") 43 | 44 | Pokey.configure do |config| 45 | config.run_on = [:development, :qa] 46 | end 47 | end 48 | 49 | subject { Pokey.should_run? } 50 | 51 | it "returns true" do 52 | expect(subject).to eq true 53 | end 54 | end 55 | 56 | context "when not configured for current Rails.env" do 57 | before do 58 | allow(Pokey).to receive(:current_env).and_return("production") 59 | 60 | Pokey.configure do |config| 61 | config.run_on = [:development, :qa] 62 | end 63 | end 64 | 65 | subject { Pokey.should_run? } 66 | 67 | it "returns false" do 68 | expect(subject).to eq false 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /spec/pokey/hook_spec.rb: -------------------------------------------------------------------------------- 1 | require './lib/pokey' 2 | 3 | RSpec.describe Pokey::Hook do 4 | subject { Pokey::Hook.new } 5 | 6 | describe "#initialize" do 7 | it "defaults #http_method to :post" do 8 | expect(subject.http_method).to eq :post 9 | end 10 | 11 | it "defaults #data to empty hash" do 12 | expect(subject.data).to eq({}) 13 | end 14 | end 15 | 16 | context "when subclassed" do 17 | subject do 18 | class TestHook < Pokey::Hook 19 | def destination 20 | "/test/hook" 21 | end 22 | 23 | def http_method 24 | :get 25 | end 26 | 27 | def data 28 | { 29 | name: "Test Hook", 30 | id: 1 31 | } 32 | end 33 | end 34 | 35 | TestHook.new 36 | end 37 | 38 | it "uses overridden parameters instead of default values" do 39 | expect(subject.http_method).to eq(:get) 40 | expect(subject.data).to eq({ name: "Test Hook", id: 1 }) 41 | end 42 | 43 | describe '#make_http_request!' do 44 | it 'attempts to make an http request' do 45 | expect(Pokey::Request).to receive(:make!) 46 | subject.make_http_request! 47 | end 48 | end 49 | end 50 | end 51 | 52 | -------------------------------------------------------------------------------- /spec/pokey/hooks_spec.rb: -------------------------------------------------------------------------------- 1 | require './lib/pokey/hook' 2 | require './lib/pokey/hooks' 3 | 4 | RSpec.describe Pokey::Hooks do 5 | before do 6 | Pokey::Hooks.clear! 7 | end 8 | 9 | describe '.add' do 10 | subject do 11 | Pokey::Hooks.add do |hook| 12 | hook.destination = "http://test.com/destination" 13 | hook.data = { 14 | name: "Test", 15 | id: 1 16 | } 17 | hook.interval = 3600 18 | end 19 | end 20 | 21 | it 'succesfully adds hook to list' do 22 | expect { subject }.to change { Pokey::Hooks.all.length }.by(1) 23 | end 24 | 25 | it 'successfully retains hook data' do 26 | subject 27 | hook = Pokey::Hooks.all.first 28 | expect(hook.destination).to eq("http://test.com/destination") 29 | expect(hook.data).to eq({ name: "Test", id: 1 }) 30 | expect(hook.interval).to eq(3600) 31 | end 32 | 33 | context 'when destination is bad' do 34 | subject do 35 | Pokey::Hooks.add do |hook| 36 | hook.interval = 3600 37 | end 38 | end 39 | 40 | it 'throws exceptions' do 41 | expect { subject }.to raise_error(Pokey::InvalidDestinationError) 42 | end 43 | end 44 | 45 | context 'when interval is bad' do 46 | subject do 47 | Pokey::Hooks.add do |hook| 48 | hook.destination = "http://test.com/destination" 49 | end 50 | end 51 | 52 | it 'raises exception' do 53 | expect { subject }.to raise_error(Pokey::InvalidIntervalError) 54 | end 55 | end 56 | 57 | context 'when http_method is bad' do 58 | subject do 59 | Pokey::Hooks.add do |hook| 60 | hook.destination = "http://test.com/destination" 61 | hook.http_method = :does_not_exist 62 | end 63 | end 64 | 65 | it 'raises exception' do 66 | expect { subject }.to raise_error(Pokey::InvalidHTTPMethodError) 67 | end 68 | end 69 | end 70 | 71 | describe '.add_from_dir' do 72 | let(:dir) { './spec/pokey/sample_hooks/' } 73 | 74 | let(:subject) do 75 | Pokey::Hooks.add_from_dir(dir) 76 | end 77 | 78 | it 'has multiple files in the directory' do 79 | expect(Dir.entries(dir).size).to be > 1 80 | end 81 | 82 | it 'successfully adds multiple hooks' do 83 | Pokey::Hooks.clear! 84 | count = Dir.entries(dir).size - 2 85 | subject 86 | expect(Pokey::Hooks.all.length).to eq(count) 87 | end 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /spec/pokey/request_spec.rb: -------------------------------------------------------------------------------- 1 | require './lib/pokey/request' 2 | 3 | RSpec.describe Pokey::Request do 4 | let(:destination) { "http://test.com/test/endpoint" } 5 | let(:http_method) { :post } 6 | let(:data) { { name: "Test Endpoint", id: 1 } } 7 | 8 | describe 'defaults' do 9 | subject { Pokey::Request.new(destination) } 10 | 11 | it 'defaults http_method to post' do 12 | expect(subject.http_method).to eq(:post) 13 | end 14 | 15 | it 'defaults data to {}' do 16 | expect(subject.data).to eq({}) 17 | end 18 | end 19 | 20 | describe "#make!" do 21 | subject { Pokey::Request.make!(destination, http_method, data) } 22 | 23 | context 'when :post' do 24 | before(:each) do 25 | stub_request(:post, destination) 26 | end 27 | 28 | it "successfully makes http request" do 29 | expect(Net::HTTP::Post).to receive(:new) 30 | expect_any_instance_of(Net::HTTP).to receive(:request) 31 | subject 32 | end 33 | 34 | it "passes params along with it" do 35 | expect_any_instance_of(Net::HTTP::Post).to receive(:set_form_data).with(data) 36 | subject 37 | end 38 | end 39 | 40 | context 'when :get' do 41 | let(:http_method) { :get } 42 | 43 | it "successfully makes http request" do 44 | expect(Net::HTTP::Get).to receive(:new) 45 | expect_any_instance_of(Net::HTTP).to receive(:request) 46 | subject 47 | end 48 | 49 | it "passes params in the uri" do 50 | request = Pokey::Request.new(destination, http_method, data) 51 | expect(request.uri.to_s.length).to be > destination.length 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /spec/pokey/sample_hooks/another_sample_hook.rb: -------------------------------------------------------------------------------- 1 | class AnotherSampleHook < Pokey::Hook 2 | def destination 3 | "http://www.another.com/sample/hook" 4 | end 5 | 6 | def interval 7 | 2400 8 | end 9 | 10 | def data 11 | { 12 | name: "Another Sample Hook", 13 | id: 2, 14 | description: "George Bluth approves." 15 | } 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/pokey/sample_hooks/sample_hook.rb: -------------------------------------------------------------------------------- 1 | class SampleHook < Pokey::Hook 2 | def destination 3 | "http://test.com/sample/hook" 4 | end 5 | 6 | def interval 7 | 7200 8 | end 9 | 10 | def data 11 | { 12 | name: "Sample hook", 13 | id: 1 14 | } 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/pokey/scheduler_spec.rb: -------------------------------------------------------------------------------- 1 | require './lib/pokey' 2 | 3 | RSpec.describe Pokey::Scheduler do 4 | before(:all) do 5 | Pokey.configure do |config| 6 | config.hook_dir = "spec/sample_hooks" 7 | 8 | config.add_hook do |hook| 9 | hook.destination = "/my/webhook/endpoint" 10 | hook.interval = 5 11 | end 12 | end 13 | end 14 | 15 | before do 16 | allow_any_instance_of(Pokey::Hook).to receive(:make_http_request!).and_return(true) 17 | end 18 | 19 | describe "#run!" do 20 | it "adds hooks from specified directory" do 21 | expect(Pokey::Hooks).to receive(:add_from_dir).with(Pokey.hook_dir) 22 | Pokey::Scheduler.run! 23 | end 24 | 25 | it "includes hooks from both the initializer and hook_dir" do 26 | expect(Pokey::Hooks.count).to eq(3) 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file was generated by the `rspec --init` command. Conventionally, all 2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 3 | # The generated `.rspec` file contains `--require spec_helper` which will cause 4 | # this file to always be loaded, without a need to explicitly require it in any 5 | # files. 6 | # 7 | # Given that it is always loaded, you are encouraged to keep this file as 8 | # light-weight as possible. Requiring heavyweight dependencies from this file 9 | # will add to the boot time of your test suite on EVERY test run, even for an 10 | # individual file that may not need all of that loaded. Instead, consider making 11 | # a separate helper file that requires the additional dependencies and performs 12 | # the additional setup, and require it from the spec files that actually need 13 | # it. 14 | # 15 | # The `.rspec` file also contains a few flags that are not defaults but that 16 | # users commonly want. 17 | # 18 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 19 | 20 | require 'webmock/rspec' 21 | 22 | # Disable all requests 23 | WebMock.disable_net_connect!(allow_localhost: false) 24 | 25 | require 'pry' 26 | 27 | RSpec.configure do |config| 28 | # rspec-expectations config goes here. You can use an alternate 29 | # assertion/expectation library such as wrong or the stdlib/minitest 30 | # assertions if you prefer. 31 | config.expect_with :rspec do |expectations| 32 | # This option will default to `true` in RSpec 4. It makes the `description` 33 | # and `failure_message` of custom matchers include text for helper methods 34 | # defined using `chain`, e.g.: 35 | # be_bigger_than(2).and_smaller_than(4).description 36 | # # => "be bigger than 2 and smaller than 4" 37 | # ...rather than: 38 | # # => "be bigger than 2" 39 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 40 | end 41 | 42 | # rspec-mocks config goes here. You can use an alternate test double 43 | # library (such as bogus or mocha) by changing the `mock_with` option here. 44 | config.mock_with :rspec do |mocks| 45 | # Prevents you from mocking or stubbing a method that does not exist on 46 | # a real object. This is generally recommended, and will default to 47 | # `true` in RSpec 4. 48 | mocks.verify_partial_doubles = true 49 | end 50 | 51 | # The settings below are suggested to provide a good initial experience 52 | # with RSpec, but feel free to customize to your heart's content. 53 | =begin 54 | # These two settings work together to allow you to limit a spec run 55 | # to individual examples or groups you care about by tagging them with 56 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 57 | # get run. 58 | config.filter_run :focus 59 | config.run_all_when_everything_filtered = true 60 | 61 | # Limits the available syntax to the non-monkey patched syntax that is 62 | # recommended. For more details, see: 63 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 64 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 65 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 66 | config.disable_monkey_patching! 67 | 68 | # This setting enables warnings. It's recommended, but in some cases may 69 | # be too noisy due to issues in dependencies. 70 | config.warnings = true 71 | 72 | # Many RSpec users commonly either run the entire suite or an individual 73 | # file, and it's useful to allow more verbose output when running an 74 | # individual spec file. 75 | if config.files_to_run.one? 76 | # Use the documentation formatter for detailed output, 77 | # unless a formatter has already been configured 78 | # (e.g. via a command-line flag). 79 | config.default_formatter = 'doc' 80 | end 81 | 82 | # Print the 10 slowest examples and example groups at the 83 | # end of the spec run, to help surface which specs are running 84 | # particularly slow. 85 | config.profile_examples = 10 86 | 87 | # Run specs in random order to surface order dependencies. If you find an 88 | # order dependency and want to debug it, you can fix the order by providing 89 | # the seed, which is printed after each run. 90 | # --seed 1234 91 | config.order = :random 92 | 93 | # Seed global randomization in this process using the `--seed` CLI option. 94 | # Setting this allows you to use `--seed` to deterministically reproduce 95 | # test failures related to randomization by passing the same `--seed` value 96 | # as the one that triggered the failure. 97 | Kernel.srand config.seed 98 | =end 99 | end 100 | --------------------------------------------------------------------------------