status_page_ruby 0.0.1

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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +25 -0
  3. data/.gitignore +3 -0
  4. data/.rubocop.yml +10 -0
  5. data/Gemfile +14 -0
  6. data/Gemfile.lock +61 -0
  7. data/README.md +53 -0
  8. data/bin/status-page +6 -0
  9. data/lib/status_page_ruby.rb +20 -0
  10. data/lib/status_page_ruby/pages/base.rb +52 -0
  11. data/lib/status_page_ruby/pages/bitbucket.rb +14 -0
  12. data/lib/status_page_ruby/pages/cloudflare.rb +29 -0
  13. data/lib/status_page_ruby/pages/github.rb +19 -0
  14. data/lib/status_page_ruby/pages/rubygems.rb +14 -0
  15. data/lib/status_page_ruby/repositories/status.rb +40 -0
  16. data/lib/status_page_ruby/services/backup_data.rb +15 -0
  17. data/lib/status_page_ruby/services/build_history_table.rb +32 -0
  18. data/lib/status_page_ruby/services/build_log_table.rb +14 -0
  19. data/lib/status_page_ruby/services/build_stats_table.rb +79 -0
  20. data/lib/status_page_ruby/services/pull_statuses.rb +44 -0
  21. data/lib/status_page_ruby/services/restore_data.rb +15 -0
  22. data/lib/status_page_ruby/status.rb +36 -0
  23. data/lib/status_page_ruby/storage.rb +55 -0
  24. data/lib/status_page_ruby/version.rb +3 -0
  25. data/lib/status_page_ruby_cli.rb +76 -0
  26. data/spec/lib/status_page_ruby/pages/bitbucket_spec.rb +39 -0
  27. data/spec/lib/status_page_ruby/pages/cloudflare_spec.rb +64 -0
  28. data/spec/lib/status_page_ruby/pages/github_spec.rb +57 -0
  29. data/spec/lib/status_page_ruby/pages/rubygems_spec.rb +39 -0
  30. data/spec/lib/status_page_ruby/repositories/status_spec.rb +124 -0
  31. data/spec/lib/status_page_ruby/services/backup_data_spec.rb +13 -0
  32. data/spec/lib/status_page_ruby/services/build_history_table_spec.rb +71 -0
  33. data/spec/lib/status_page_ruby/services/build_log_table_spec.rb +43 -0
  34. data/spec/lib/status_page_ruby/services/build_stats_table_spec.rb +72 -0
  35. data/spec/lib/status_page_ruby/services/pull_statuses_spec.rb +30 -0
  36. data/spec/lib/status_page_ruby/services/restore_data_spec.rb +13 -0
  37. data/spec/lib/status_page_ruby/status_spec.rb +65 -0
  38. data/spec/lib/status_page_ruby/storage_spec.rb +134 -0
  39. data/spec/spec_helper.rb +15 -0
  40. data/status_page_ruby.gemspec +22 -0
  41. metadata +139 -0
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StatusPageRuby::Pages::Rubygems do
4
+ let(:html) { "<html><body><div class='page-status'><div class='status'>#{status}</div></div></body></html>" }
5
+
6
+ before { allow(OpenURI).to receive(:open_uri).with('https://status.rubygems.org/') { html } }
7
+
8
+ describe '#status' do
9
+ subject { described_class.open.status }
10
+
11
+ context 'when success status' do
12
+ let(:status) { 'All Systems Operational' }
13
+
14
+ it { is_expected.to eq('All Systems Operational') }
15
+ end
16
+
17
+ context 'when not success status' do
18
+ let(:status) { 'All is Failed' }
19
+
20
+ it { is_expected.to eq('All is Failed') }
21
+ end
22
+ end
23
+
24
+ describe '#success?' do
25
+ subject { described_class.open.success? }
26
+
27
+ context 'when success status' do
28
+ let(:status) { 'All Systems Operational' }
29
+
30
+ it { is_expected.to be_truthy }
31
+ end
32
+
33
+ context 'when not success status' do
34
+ let(:status) { 'All is Failed' }
35
+
36
+ it { is_expected.to be_falsey }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StatusPageRuby::Repositories::Status do
4
+ let(:storage) { double }
5
+ let(:repository) { described_class.new(storage) }
6
+
7
+ describe '#exist?' do
8
+ subject { repository.exist?(status) }
9
+ let(:status) { double(record: double) }
10
+
11
+ before { allow(storage).to receive(:include?).with(status.record) { is_include } }
12
+
13
+ context 'when storage includes status record' do
14
+ let(:is_include) { true }
15
+ it { is_expected.to be_truthy }
16
+ end
17
+
18
+ context 'when storage does not include status record' do
19
+ let(:is_include) { false }
20
+ it { is_expected.to be_falsey }
21
+ end
22
+ end
23
+
24
+ describe '#where' do
25
+ subject { repository.where(service: 'a') }
26
+
27
+ context 'when storage is not empty' do
28
+ context 'when service exists' do
29
+ before { allow(storage).to receive(:read) { [%w[a b c]] } }
30
+
31
+ it 'builds statuses' do
32
+ expect(StatusPageRuby::Status).to receive(:new).with('a', 'b', 'c')
33
+ subject
34
+ end
35
+ end
36
+
37
+ context 'when service does not exist' do
38
+ before { allow(storage).to receive(:read) { [%w[x x x]] } }
39
+
40
+ it 'builds statuses' do
41
+ expect(StatusPageRuby::Status).not_to receive(:new)
42
+ subject
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'when storage is empty' do
48
+ before { allow(storage).to receive(:read) { [] } }
49
+
50
+ it 'does not build statuses' do
51
+ expect(StatusPageRuby::Status).not_to receive(:new)
52
+ subject
53
+ end
54
+ end
55
+ end
56
+
57
+ describe '#all' do
58
+ subject { repository.all }
59
+
60
+ context 'when storage is not empty' do
61
+ before { allow(storage).to receive(:read) { [%w[a b c]] } }
62
+
63
+ it 'builds statuses' do
64
+ expect(StatusPageRuby::Status).to receive(:new).with('a', 'b', 'c')
65
+ subject
66
+ end
67
+ end
68
+ context 'when storage is empty' do
69
+ before { allow(storage).to receive(:read) { [] } }
70
+
71
+ it 'does not build statuses' do
72
+ expect(StatusPageRuby::Status).not_to receive(:new)
73
+ subject
74
+ end
75
+ end
76
+ end
77
+
78
+ describe '#create' do
79
+ subject { repository.create(status) }
80
+ let(:status) { double(record: double) }
81
+
82
+ before { allow(repository).to receive(:exist?) { status_exists } }
83
+
84
+ context 'when status does not exist' do
85
+ let(:status_exists) { false }
86
+
87
+ it 'triggers write on storage' do
88
+ expect(storage).to receive(:write).with(status.record).once
89
+ subject
90
+ end
91
+ end
92
+
93
+ context 'with status exists' do
94
+ let(:status_exists) { true }
95
+
96
+ it 'does not trigger write on storage' do
97
+ expect(storage).not_to receive(:write)
98
+ subject
99
+ end
100
+ end
101
+ end
102
+
103
+ describe '#create_batch' do
104
+ subject { repository.create_batch(statuses) }
105
+
106
+ context 'with statuses' do
107
+ let(:statuses) { [double(record: double)] }
108
+
109
+ it 'triggers merge on storage' do
110
+ expect(storage).to receive(:merge).with(statuses.map(&:record)).once
111
+ subject
112
+ end
113
+ end
114
+
115
+ context 'with empty statuses' do
116
+ let(:statuses) { [] }
117
+
118
+ it 'does not trigger merge on storage' do
119
+ expect(storage).not_to receive(:merge)
120
+ subject
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StatusPageRuby::Services::BackupData do
4
+ let(:storage) { double }
5
+ let(:service) { described_class.new(storage) }
6
+
7
+ describe '#call' do
8
+ it 'triggers copy on storage' do
9
+ expect(storage).to receive(:copy).with('test_path').once
10
+ service.call('test_path')
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StatusPageRuby::Services::BuildHistoryTable do
4
+ let(:data_file_path) { Tempfile.new('data_file_path').path }
5
+ let(:service) do
6
+ described_class.new(
7
+ StatusPageRuby::Repositories::Status.new(
8
+ StatusPageRuby::Storage.new(data_file_path)
9
+ )
10
+ )
11
+ end
12
+
13
+ describe '#call' do
14
+ before do
15
+ File.write(data_file_path, <<-CSV.delete(' '))
16
+ test1,up,Success,1539506590
17
+ test1,down,Failure,1539507591
18
+ test2,up,Success,1539508592
19
+ CSV
20
+ end
21
+
22
+ context 'with service parameter' do
23
+ context 'when service exists' do
24
+ subject { service.call('test1') }
25
+ let(:expected_table) do
26
+ <<-TABLE.gsub(/^ +/, '').strip
27
+ +---------+--------+---------------------+
28
+ | Service | Status | Time |
29
+ +---------+--------+---------------------+
30
+ | test1 | up | 14.10.2018 08:43:10 |
31
+ | test1 | down | 14.10.2018 08:59:51 |
32
+ +---------+--------+---------------------+
33
+ TABLE
34
+ end
35
+
36
+ it { is_expected.to eq(expected_table) }
37
+ end
38
+
39
+ context 'when service does not exists' do
40
+ subject { service.call('test3') }
41
+ let(:expected_table) do
42
+ <<-TABLE.gsub(/^ +/, '').strip
43
+ +---------+--------+------+
44
+ | Service | Status | Time |
45
+ +---------+--------+------+
46
+ +---------+--------+------+
47
+ TABLE
48
+ end
49
+
50
+ it { is_expected.to eq(expected_table) }
51
+ end
52
+ end
53
+
54
+ context 'without service parameter' do
55
+ subject { service.call }
56
+ let(:expected_table) do
57
+ <<-TABLE.gsub(/^ +/, '').strip
58
+ +---------+--------+---------------------+
59
+ | Service | Status | Time |
60
+ +---------+--------+---------------------+
61
+ | test1 | up | 14.10.2018 08:43:10 |
62
+ | test1 | down | 14.10.2018 08:59:51 |
63
+ | test2 | up | 14.10.2018 09:16:32 |
64
+ +---------+--------+---------------------+
65
+ TABLE
66
+ end
67
+
68
+ it { is_expected.to eq(expected_table) }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StatusPageRuby::Services::BuildLogTable do
4
+ describe '#call' do
5
+ subject { described_class.new.call(records) }
6
+
7
+ context 'with records' do
8
+ let(:records) do
9
+ [
10
+ StatusPageRuby::Status.new('test1', 'up', 'Success', '1539506590'),
11
+ StatusPageRuby::Status.new('test2', 'up', 'Success', '1539508592')
12
+ ]
13
+ end
14
+
15
+ let(:expected_table) do
16
+ <<-TABLE.gsub(/^ +/, '').strip
17
+ +---------+--------+---------------------+
18
+ | Service | Status | Time |
19
+ +---------+--------+---------------------+
20
+ | test1 | up | 14.10.2018 08:43:10 |
21
+ | test2 | up | 14.10.2018 09:16:32 |
22
+ +---------+--------+---------------------+
23
+ TABLE
24
+ end
25
+
26
+ it { is_expected.to eq(expected_table) }
27
+ end
28
+
29
+ context 'with empty records' do
30
+ let(:records) { [] }
31
+ let(:expected_table) do
32
+ <<-TABLE.gsub(/^ +/, '').strip
33
+ +---------+--------+------+
34
+ | Service | Status | Time |
35
+ +---------+--------+------+
36
+ +---------+--------+------+
37
+ TABLE
38
+ end
39
+
40
+ it { is_expected.to eq(expected_table) }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StatusPageRuby::Services::BuildStatsTable do
4
+ let(:data_file_path) { Tempfile.new('data_file_path').path }
5
+ let(:service) do
6
+ described_class.new(
7
+ StatusPageRuby::Repositories::Status.new(
8
+ StatusPageRuby::Storage.new(data_file_path)
9
+ )
10
+ )
11
+ end
12
+
13
+ describe '#call' do
14
+ before do
15
+ Timecop.freeze(Time.at(1_539_520_990))
16
+ File.write(data_file_path, <<-CSV.delete(' '))
17
+ test1,up,Success,1539506590
18
+ test1,down,Failure,1539510190
19
+ test1,down,Failure,1539513790
20
+ test2,up,Success,1539519190
21
+ test1,up,Success,1539517390
22
+ CSV
23
+ end
24
+
25
+ context 'with service parameter' do
26
+ context 'when service exists' do
27
+ subject { service.call('test1') }
28
+ let(:expected_table) do
29
+ <<-TABLE.gsub(/^ +/, '').strip
30
+ +---------+----------+-----------+
31
+ | Service | Up since | Down time |
32
+ +---------+----------+-----------+
33
+ | test1 | 1 hours | 2 hours |
34
+ +---------+----------+-----------+
35
+ TABLE
36
+ end
37
+
38
+ it { is_expected.to eq(expected_table) }
39
+ end
40
+
41
+ context 'when service does not exists' do
42
+ subject { service.call('test3') }
43
+ let(:expected_table) do
44
+ <<-TABLE.gsub(/^ +/, '').strip
45
+ +---------+----------+-----------+
46
+ | Service | Up since | Down time |
47
+ +---------+----------+-----------+
48
+ +---------+----------+-----------+
49
+ TABLE
50
+ end
51
+
52
+ it { is_expected.to eq(expected_table) }
53
+ end
54
+ end
55
+
56
+ context 'without service parameter' do
57
+ subject { service.call }
58
+ let(:expected_table) do
59
+ <<-TABLE.gsub(/^ +/, '').strip
60
+ +---------+------------+-----------+
61
+ | Service | Up since | Down time |
62
+ +---------+------------+-----------+
63
+ | test1 | 1 hours | 2 hours |
64
+ | test2 | 30 minutes | 0 minutes |
65
+ +---------+------------+-----------+
66
+ TABLE
67
+ end
68
+
69
+ it { is_expected.to eq(expected_table) }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StatusPageRuby::Services::PullStatuses do
4
+ let(:status_repository) { double }
5
+ let(:service) { described_class.new(status_repository) }
6
+
7
+ describe '#call' do
8
+ context 'when there is page classes' do
9
+ let(:page_class) { double(open: page) }
10
+ let(:page) { double(class: double(name: 'TestPage'), success?: true, status: 'Success', time: 123) }
11
+ let(:status) { double }
12
+ before { allow(service).to receive(:page_classes) { [page_class] } }
13
+
14
+ it 'does not trigger create_batch for status_repository' do
15
+ expect(status_repository).to receive(:create_batch).with([status]).once
16
+ expect(StatusPageRuby::Status).to receive(:new).with('TestPage', 'up', 'Success', 123) { status }.once
17
+ service.call
18
+ end
19
+ end
20
+
21
+ context 'when there is no page classes' do
22
+ before { allow(service).to receive(:page_class?) { false } }
23
+
24
+ it 'does not trigger create_batch for status_repository' do
25
+ expect(status_repository).not_to receive(:create_batch)
26
+ service.call
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StatusPageRuby::Services::RestoreData do
4
+ let(:storage) { double }
5
+ let(:service) { described_class.new(storage) }
6
+
7
+ describe '#call' do
8
+ it 'triggers restore on storage' do
9
+ expect(storage).to receive(:restore).with('test_path').once
10
+ service.call('test_path')
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe StatusPageRuby::Status do
4
+ describe '.new' do
5
+ [
6
+ [nil, nil, nil, nil],
7
+ ['', '', '', ''],
8
+ [1, 2, 2, 3],
9
+ ['Github', 'up', 'All Good', 1_539_506_590]
10
+ ].each do |service, state, status, time|
11
+ context "with service: #{service}, state: #{state}, status: #{status} and time: #{time}" do
12
+ subject { described_class.new(service, state, status, time) }
13
+
14
+ it { expect(subject.service).to eq(service.to_s) }
15
+ it { expect(subject.state).to eq(state.to_s) }
16
+ it { expect(subject.time).to eq(time.to_s) }
17
+ end
18
+ end
19
+ end
20
+
21
+ describe '#record' do
22
+ [
23
+ [nil, nil, nil, nil],
24
+ ['', '', '', ''],
25
+ [1, 2, 3, 4],
26
+ ['Github', 'up', 'All Good', 1_539_506_590]
27
+ ].each do |service, state, status, time|
28
+ context "with service: #{service}, state: #{state}, status: #{status} and time: #{time}" do
29
+ subject { described_class.new(service, state, status, time).record }
30
+
31
+ it { is_expected.to eq([service.to_s, state.to_s, status.to_s, time.to_s]) }
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '#history_record' do
37
+ [
38
+ [[nil, nil, nil, 1_539_506_590], ['', '', '14.10.2018 08:43:10']],
39
+ [['', '', '', 1_539_506_590], ['', '', '14.10.2018 08:43:10']],
40
+ [[1, 2, 3, 1_539_506_590], ['1', '2', '14.10.2018 08:43:10']],
41
+ [['Github', 'up', 'All Good', 1_539_506_590], ['Github', 'up', '14.10.2018 08:43:10']]
42
+ ].each do |args, result|
43
+ context "with service: #{args[0]}, state: #{args[1]}, status: #{args[2]} and time: #{args[3]}" do
44
+ subject { described_class.new(*args).history_record }
45
+
46
+ it { is_expected.to eq(result) }
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#to_csv' do
52
+ [
53
+ [[nil, nil, nil, nil], "\"\",\"\",\"\",\"\"\n"],
54
+ [['', '', '', ''], "\"\",\"\",\"\",\"\"\n"],
55
+ [[1, 2, 3, 4], "1,2,3,4\n"],
56
+ [['Github', 'up', 'All Good', 1_539_506_590], "Github,up,All Good,1539506590\n"]
57
+ ].each do |args, result|
58
+ context "with service: #{args[0]}, state: #{args[1]}, status: #{args[2]} and time: #{args[3]}" do
59
+ subject { described_class.new(*args).to_csv }
60
+
61
+ it { is_expected.to eq(result) }
62
+ end
63
+ end
64
+ end
65
+ end