dboard 1.1.0 → 2.0.2

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 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
-