dboard 1.1.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ba48cb0ffab690f4b38502e4bdf8f28d1e94422d
4
- data.tar.gz: fc969a6e7516b14b8f4a222abde3db307f998a99
2
+ SHA256:
3
+ metadata.gz: 5951c2ae51009668ef1be098f094dbccf11366acad2fde130cff31e11d05935f
4
+ data.tar.gz: 102f5ece6e4ed289f357282f6a9d5a07bf7ed0214d85ae7c3a0352cad16579d2
5
5
  SHA512:
6
- metadata.gz: d4df321724dde11ae0227ba274290a71da77d01cf7655488016f2f95d8a12d790d7dd1cf3c35bddca804d292baa365cb412719da0253f3fa832033467d9dbda2
7
- data.tar.gz: 1e7f06619130542469f208ffbc53ce86dc3f6d759f8c2040d7bac7c97bb1284766117f907f410645fa6d811a6d9b529df6b3be2d6768b4140d8fcf9e59d18579
6
+ metadata.gz: a36cbfe80bd520d218b67d32325eb2107b75216a0c18c6ffb65f6794a78b92226fa6020177c24254fea5d6971bcecebc0ca823c7b0c66a0fd0a010ed28e7efaf
7
+ data.tar.gz: fa3b7a05f4d5478ad6c841a6192bfcf01c09950b69ac71fdb09d142ce29c5976694d9e1fa208149e026088438df23b38cc9f23d898151eaed1bcd8eab9d7a272
@@ -0,0 +1,26 @@
1
+ name: Ruby CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+
12
+ runs-on: ubuntu-latest
13
+
14
+ strategy:
15
+ matrix:
16
+ ruby-version: ["3.0", "2.7", "2.6"]
17
+
18
+ steps:
19
+ - uses: actions/checkout@v2
20
+ - name: Set up Ruby ${{ matrix.ruby-version }}
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ matrix.ruby-version }}
24
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
25
+ - name: Run tests
26
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  Gemfile.lock
4
4
  pkg/*
5
5
  todo.txt
6
+ /tmp
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ AllCops:
2
+ Exclude:
3
+ - "tmp/**/*"
4
+ inherit_gem:
5
+ barsoom_utils: shared_rubocop.yml
data/Gemfile CHANGED
@@ -1,2 +1,11 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
  gemspec
3
+
4
+ gem "net_http_timeout_errors"
5
+
6
+ group :development, :test do
7
+ gem "barsoom_utils"
8
+ gem "rspec"
9
+ gem "rubocop"
10
+ gem "webmock"
11
+ end
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Ruby CI](https://github.com/barsoom/dboard/actions/workflows/ci.yml/badge.svg)](https://github.com/barsoom/dboard/actions/workflows/ci.yml)
2
+
1
3
  A dashboard framework.
2
4
 
3
5
  It handles collecting data from user defined sources (simple ruby classes) and provides a simple API to poll for updates. See the [example app](https://github.com/joakimk/dboard_example) for information on how to use it.
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
- require 'bundler'
2
- require 'rspec/core/rake_task'
1
+ require "bundler"
2
+ require "rspec/core/rake_task"
3
3
 
4
4
  Bundler::GemHelper.install_tasks
5
5
 
@@ -7,4 +7,4 @@ desc "Run specs"
7
7
  RSpec::Core::RakeTask.new do |t|
8
8
  end
9
9
 
10
- task :default => :spec
10
+ task default: :spec
data/dboard.gemspec CHANGED
@@ -6,22 +6,20 @@ Gem::Specification.new do |s|
6
6
  s.name = "dboard"
7
7
  s.version = Dboard::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Joakim Kolsjö"]
10
- s.email = ["joakim.kolsjo@gmail.com"]
9
+ s.authors = [ "Joakim Kolsjö" ]
10
+ s.email = [ "joakim.kolsjo@gmail.com" ]
11
11
  s.homepage = ""
12
12
  s.summary = %q{Dashboard framework}
13
13
  s.description = %q{Dashboard framework}
14
14
  s.license = "MIT"
15
+ s.metadata = { "rubygems_mfa_required" => "true" }
15
16
 
16
17
  s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {spec}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
19
- s.require_paths = ["lib"]
18
+ s.require_paths = [ "lib" ]
20
19
 
20
+ s.add_dependency "dalli"
21
21
  s.add_dependency "httparty"
22
- s.add_dependency "rake"
23
22
  s.add_dependency "json"
24
- s.add_dependency "dalli"
23
+ s.add_dependency "rake"
25
24
  s.add_dependency "sinatra"
26
- s.add_development_dependency "rspec", "2.6.0"
27
25
  end
data/lib/api.rb CHANGED
@@ -1,8 +1,9 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'cache'))
2
- require File.expand_path(File.join(File.dirname(__FILE__), 'collector.rb'))
3
- require 'digest/md5'
4
- require 'json'
5
- require 'httparty'
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "cache"))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), "collector.rb"))
3
+ require "digest/md5"
4
+ require "json"
5
+ require "httparty"
6
+ require "net_http_timeout_errors"
6
7
 
7
8
  module Dboard
8
9
  class Api
@@ -11,16 +12,37 @@ module Dboard
11
12
 
12
13
  class Client
13
14
  include HTTParty
15
+
16
+ def self.post(*, **)
17
+ with_retries { super }
18
+ end
19
+
20
+ private
21
+
22
+ private_class_method \
23
+ def self.with_retries
24
+ remaining_attempts = 3
25
+
26
+ begin
27
+ remaining_attempts -= 1
28
+ yield
29
+ rescue *NetHttpTimeoutErrors.all
30
+ raise if remaining_attempts == 0
31
+
32
+ sleep((ENV["RACK_ENV"] == "test") ? 0 : 5)
33
+ retry
34
+ end
35
+ end
14
36
  end
15
37
 
16
38
  def self.get(params)
17
39
  types = {}
18
- params[:types].split(',').each do |type|
40
+ params[:types].split(",").each do |type|
19
41
  raw_data = CACHE.get("dashboard::source::#{type}")
20
42
  data = raw_data ? JSON.parse(raw_data) : {}
21
- types.merge!(type => { :data => data, :checksum => Digest::MD5.hexdigest(data.inspect) })
43
+ types.merge!(type => { data: data, checksum: Digest::MD5.hexdigest(data.inspect) })
22
44
  end
23
- { :version => (@@version || ENV["COMMIT_HASH"] || "unversioned"), :sources => types }.to_json
45
+ { version: (@@version || ENV["COMMIT_HASH"] || "unversioned"), sources: types }.to_json
24
46
  end
25
47
 
26
48
  def self.version=(version)
data/lib/cache.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'dalli'
1
+ require "dalli"
2
2
 
3
3
  module Dboard
4
4
  if Config.config[:memcache]
data/lib/collector.rb CHANGED
@@ -1,5 +1,5 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'publisher'))
2
- require 'singleton'
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "publisher"))
2
+ require "singleton"
3
3
 
4
4
  module Dboard
5
5
  class Collector
data/lib/dboard.rb CHANGED
@@ -1,3 +1,3 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'config.rb'))
2
- require File.expand_path(File.join(File.dirname(__FILE__), 'api.rb'))
3
- require File.expand_path(File.join(File.dirname(__FILE__), 'collector.rb'))
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "config.rb"))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), "api.rb"))
3
+ require File.expand_path(File.join(File.dirname(__FILE__), "collector.rb"))
data/lib/publisher.rb CHANGED
@@ -1,9 +1,9 @@
1
- require 'json'
1
+ require "json"
2
2
 
3
3
  module Dboard
4
4
  class Publisher
5
5
  def self.publish(source, data)
6
- Api::Client.post("/sources/#{source}", :body => { :data => data.to_json }, :timeout => 10000)
6
+ Api::Client.post("/sources/#{source}", body: { data: data.to_json }, timeout: 10000)
7
7
  rescue SocketError => ex
8
8
  puts "SocketError: #{ex.message}"
9
9
  end
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dboard
2
- VERSION = "1.1.0"
2
+ VERSION = "2.0.2"
3
3
  end
@@ -1,25 +1,25 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
2
 
3
- describe Dboard::Collector, "register_source" do
3
+ describe Dboard::Collector, ".register_source" do
4
4
  before do
5
5
  Dboard::Collector.instance.sources.clear
6
6
  end
7
7
 
8
8
  it "can register a source" do
9
- new_relic = mock
10
- new_relic.stub!(:update_interval).and_return(5)
9
+ new_relic = double
10
+ allow(new_relic).to receive(:update_interval).and_return(5)
11
11
  Dboard::Collector.register_source :new_relic, new_relic
12
- Dboard::Collector.instance.sources.should == { :new_relic => new_relic }
12
+ expect(Dboard::Collector.instance.sources).to eq({ new_relic: new_relic })
13
13
  end
14
14
 
15
15
  it "can register an after update callback" do
16
- new_relic = mock
17
- new_relic.stub!(:fetch).and_return({ :db => "100%" })
18
- callback = mock
16
+ new_relic = double
17
+ allow(new_relic).to receive(:fetch).and_return({ db: "100%" })
18
+ callback = double
19
19
  Dboard::Collector.register_after_update_callback callback
20
20
 
21
- callback.should_receive(:call)
22
- Dboard::Publisher.stub!(:publish)
21
+ expect(callback).to receive(:call)
22
+ allow(Dboard::Publisher).to receive(:publish)
23
23
  Dboard::Collector.instance.update_source(:new_relic, new_relic)
24
24
 
25
25
  # since it is a singleton, and this callbacks leaks into the other tests
@@ -27,14 +27,15 @@ describe Dboard::Collector, "register_source" do
27
27
  end
28
28
 
29
29
  it "can register an error callback" do
30
- new_relic = mock
30
+ new_relic = double
31
31
  error = RuntimeError.new("error")
32
- new_relic.stub!(:fetch).and_raise(error)
33
- callback = mock
32
+ allow(new_relic).to receive(:fetch).and_raise(error)
33
+ callback = double
34
34
  Dboard::Collector.register_error_callback callback
35
35
 
36
- callback.should_receive(:call).with(error)
37
- Dboard::Publisher.stub!(:publish)
36
+ expect(callback).to receive(:call).with(error)
37
+ allow(Dboard::Publisher).to receive(:publish)
38
+ allow_any_instance_of(Dboard::Collector).to receive(:puts)
38
39
  Dboard::Collector.instance.update_source(:new_relic, new_relic)
39
40
 
40
41
  # since it is a singleton, and this callbacks leaks into the other tests
@@ -47,17 +48,17 @@ describe Dboard::Collector, "update_source" do
47
48
  Dboard::Collector.instance.sources.clear
48
49
  end
49
50
 
50
- it "should collect and publish data from sources" do
51
- new_relic = mock
52
- new_relic.stub!(:fetch).and_return({ :db => "100%" })
53
- Dboard::Publisher.should_receive(:publish).with(:new_relic, { :db => "100%" })
51
+ it "collects and publishes data from sources" do
52
+ new_relic = double
53
+ allow(new_relic).to receive(:fetch).and_return({ db: "100%" })
54
+ expect(Dboard::Publisher).to receive(:publish).with(:new_relic, { db: "100%" })
54
55
  Dboard::Collector.instance.update_source(:new_relic, new_relic)
55
56
  end
56
57
 
57
- it "should print out debugging info" do
58
- new_relic = mock
59
- new_relic.stub!(:fetch).and_raise(Exception.new("some error"))
60
- Dboard::Collector.instance.should_receive(:puts).twice
58
+ it "prints out debugging info" do
59
+ new_relic = double
60
+ allow(new_relic).to receive(:fetch).and_raise(Exception.new("some error"))
61
+ expect(Dboard::Collector.instance).to receive(:puts).twice
61
62
  Dboard::Collector.instance.update_source(:new_relic, new_relic)
62
63
  end
63
64
  end
@@ -1,16 +1,33 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
2
 
3
- describe "Publisher", "publish" do
4
-
5
- it "should send data to the dashboard server" do
6
- Dboard::Api::Client.should_receive(:post).with("/sources/new_relic", :body => { :data => { :db => "80%" }.to_json }, :timeout => 10000)
7
- Dboard::Publisher.publish(:new_relic, { :db => "80%" })
3
+ describe "Publisher", ".publish" do
4
+ it "sends data to the dashboard server" do
5
+ expect(Dboard::Api::Client).to receive(:post).with("/sources/new_relic", body: { data: { db: "80%" }.to_json }, timeout: 10000)
6
+ Dboard::Publisher.publish(:new_relic, { db: "80%" })
8
7
  end
9
8
 
10
- it "should handle and log socket errors" do
11
- Dboard::Api::Client.should_receive(:post).and_raise(SocketError.new("failed to connect"))
12
- Dboard::Publisher.should_receive(:puts).with("SocketError: failed to connect")
9
+ it "retries network errors" do
10
+ stub_request(:post, "http://api.example/sources/new_relic").
11
+ to_timeout.times(2).
12
+ to_return({ body: "OK!" })
13
+
13
14
  Dboard::Publisher.publish(:new_relic, {})
14
15
  end
15
16
 
17
+ it "raises network errors if we run out of retries" do
18
+ stub_request(:post, "http://api.example/sources/new_relic").
19
+ to_timeout.times(3).
20
+ to_return({ body: "OK!" })
21
+
22
+ expect {
23
+ Dboard::Publisher.publish(:new_relic, {})
24
+ }.to raise_error(Net::OpenTimeout)
25
+ end
26
+
27
+ # 2021-12-07: No idea why we've treated this one specially, but keeping it for now.
28
+ it "logs socket errors if we run out of retries" do
29
+ expect(Dboard::Api::Client).to receive(:post).and_raise(SocketError.new("failed to connect"))
30
+ expect(Dboard::Publisher).to receive(:puts).with("SocketError: failed to connect")
31
+ Dboard::Publisher.publish(:new_relic, {})
32
+ end
16
33
  end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  require "rspec"
2
+ require 'webmock/rspec'
2
3
 
3
- ENV["RACK_ENV"] ||= 'test'
4
- ENV['API_URL'] = "http://localhost:20843"
5
- ENV['API_USER'] = 'test'
6
- ENV['API_PASSWORD'] = 'test'
4
+ ENV["RACK_ENV"] ||= "test"
5
+ ENV["API_URL"] = "http://api.example"
6
+ ENV["API_USER"] = "test"
7
+ ENV["API_PASSWORD"] = "test"
7
8
 
8
- require File.expand_path(File.join(File.dirname(__FILE__), '../lib/dboard'))
9
+ require File.expand_path(File.join(File.dirname(__FILE__), "../lib/dboard"))
9
10
 
10
- Dboard::Api::Client.basic_auth(ENV['API_USER'], ENV['API_PASSWORD'])
11
- Dboard::Api::Client.base_uri(ENV['API_URL'])
11
+ Dboard::Api::Client.basic_auth(ENV["API_USER"], ENV["API_PASSWORD"])
12
+ Dboard::Api::Client.base_uri(ENV["API_URL"])
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dboard
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joakim Kolsjö
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-20 00:00:00.000000000 Z
11
+ date: 2021-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: httparty
14
+ name: dalli
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: httparty
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: dalli
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -80,20 +80,6 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rspec
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - '='
88
- - !ruby/object:Gem::Version
89
- version: 2.6.0
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - '='
95
- - !ruby/object:Gem::Version
96
- version: 2.6.0
97
83
  description: Dashboard framework
98
84
  email:
99
85
  - joakim.kolsjo@gmail.com
@@ -101,8 +87,9 @@ executables: []
101
87
  extensions: []
102
88
  extra_rdoc_files: []
103
89
  files:
90
+ - ".github/workflows/ci.yml"
104
91
  - ".gitignore"
105
- - ".rvmrc"
92
+ - ".rubocop.yml"
106
93
  - Gemfile
107
94
  - LICENCE
108
95
  - README.md
@@ -116,13 +103,13 @@ files:
116
103
  - lib/publisher.rb
117
104
  - lib/version.rb
118
105
  - spec/collector_spec.rb
119
- - spec/integration_spec.rb
120
106
  - spec/publisher_spec.rb
121
107
  - spec/spec_helper.rb
122
108
  homepage: ''
123
109
  licenses:
124
110
  - MIT
125
- metadata: {}
111
+ metadata:
112
+ rubygems_mfa_required: 'true'
126
113
  post_install_message:
127
114
  rdoc_options: []
128
115
  require_paths:
@@ -138,8 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
125
  - !ruby/object:Gem::Version
139
126
  version: '0'
140
127
  requirements: []
141
- rubyforge_project:
142
- rubygems_version: 2.2.1
128
+ rubygems_version: 3.2.32
143
129
  signing_key:
144
130
  specification_version: 4
145
131
  summary: Dashboard framework
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm ruby-2.1.0@dboard --create
@@ -1,54 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
-
3
- # Test app
4
- require 'sinatra'
5
-
6
- get "/sources" do
7
- Dboard::Api.get(params)
8
- end
9
-
10
- post "/sources/:type" do
11
- Dboard::Api.update(params)
12
- end
13
-
14
- describe "Dashboard" do
15
-
16
- def app
17
- Sinatra::Application
18
- end
19
-
20
- def start_app
21
- app.port = 20843
22
- app.environment = 'test'
23
- @app_thread = Thread.new { app.run! }
24
- sleep 1
25
- end
26
-
27
- def stop_app
28
- @app_thread && @app_thread.kill
29
- end
30
-
31
- before do
32
- ENV['API_URL'] = "http://localhost:20843"
33
- ENV['API_USER'] = 'test'
34
- ENV['API_PASSWORD'] = 'test'
35
- @new_relic = mock
36
- @new_relic.stub!(:fetch).and_return({ :db => "33.3%", :memory => "33333 MB" })
37
- Dboard::CACHE.delete "dashboard::source::new_relic"
38
- end
39
-
40
- it "should collect stats and post them to the server" do
41
- start_app
42
- body = Dboard::Api::Client.get("/sources?types=new_relic")
43
- JSON.parse(body)["sources"]["new_relic"]["data"].should == {}
44
- Dboard::Collector.instance.update_source(:new_relic, @new_relic)
45
- body = Dboard::Api::Client.get("/sources?types=new_relic")
46
- JSON.parse(body)["sources"]["new_relic"]["data"].should == { "db" => "33.3%", "memory" => "33333 MB" }
47
- end
48
-
49
- after do
50
- stop_app
51
- end
52
-
53
- end
54
-