datadog_backup 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe DatadogBackup::Dashboards do
6
+ let(:client_double) { double }
7
+ let(:tempdir) { Dir.mktmpdir }
8
+ let(:dashboards) do
9
+ DatadogBackup::Dashboards.new(
10
+ action: 'backup',
11
+ client: client_double,
12
+ backup_dir: tempdir,
13
+ output_format: :json,
14
+ resources: [],
15
+ logger: Logger.new('/dev/null')
16
+ )
17
+ end
18
+ let(:dashboard_description) do
19
+ {
20
+ 'description' => 'bar',
21
+ 'id' => 'abc-123-def',
22
+ 'title' => 'foo'
23
+ }
24
+ end
25
+ let(:all_boards) do
26
+ [
27
+ '200',
28
+ {
29
+ 'dashboards' => [
30
+ dashboard_description
31
+ ]
32
+ }
33
+ ]
34
+ end
35
+ let(:example_dashboard) do
36
+ [
37
+ '200',
38
+ board_abc_123_def
39
+ ]
40
+ end
41
+ let(:board_abc_123_def) do
42
+ {
43
+ 'graphs' => [
44
+ {
45
+ 'definition' => {
46
+ 'viz' => 'timeseries',
47
+ 'requests' => [
48
+ {
49
+ 'q' => 'min:foo.bar{a:b}',
50
+ 'stacked' => false
51
+ }
52
+ ]
53
+ },
54
+ 'title' => 'example graph'
55
+ }
56
+ ],
57
+ 'description' => 'example dashboard',
58
+ 'title' => 'example dashboard'
59
+ }
60
+ end
61
+ before(:example) do
62
+ allow(client_double).to receive(:get_all_boards).and_return(all_boards)
63
+ allow(client_double).to receive(:get_board).and_return(example_dashboard)
64
+ end
65
+
66
+ describe '#backup' do
67
+ subject { dashboards.backup }
68
+
69
+ it 'is expected to create a file' do
70
+ file = double('file')
71
+ allow(File).to receive(:open).with(dashboards.filename('abc-123-def'), 'w').and_return(file)
72
+ expect(file).to receive(:write).with(::JSON.pretty_generate(board_abc_123_def.deep_sort))
73
+ allow(file).to receive(:close)
74
+
75
+ dashboards.backup
76
+ end
77
+ end
78
+
79
+ describe '#all_boards' do
80
+ subject { dashboards.all_boards }
81
+
82
+ it 'calls get_all_boards' do
83
+ subject
84
+ expect(client_double).to have_received(:get_all_boards)
85
+ end
86
+
87
+ it { is_expected.to eq [dashboard_description] }
88
+ end
89
+
90
+ describe '#diff' do
91
+ it 'calls the api only once' do
92
+ dashboards.write_file('{"a":"b"}', dashboards.filename('abc-123-def'))
93
+ dashboards.diff('abc-123-def')
94
+ expect(client_double).to have_received(:get_board).exactly(1).times
95
+ end
96
+ end
97
+
98
+ describe '#get_by_id' do
99
+ subject { dashboards.get_by_id('abc-123-def') }
100
+ it { is_expected.to eq board_abc_123_def }
101
+ end
102
+ end
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe DatadogBackup::LocalFilesystem do
6
+ let(:client_double) { double }
7
+ let(:tempdir) { Dir.mktmpdir }
8
+ let(:core) do
9
+ DatadogBackup::Core.new(
10
+ action: 'backup',
11
+ client: client_double,
12
+ backup_dir: tempdir,
13
+ resources: [DatadogBackup::Dashboards],
14
+ output_format: :json,
15
+ logger: Logger.new('/dev/null')
16
+ )
17
+ end
18
+ let(:core_yaml) do
19
+ DatadogBackup::Core.new(
20
+ action: 'backup',
21
+ client: client_double,
22
+ backup_dir: tempdir,
23
+ resources: [],
24
+ output_format: :yaml,
25
+ logger: Logger.new('/dev/null')
26
+ )
27
+ end
28
+
29
+ describe '#all_files' do
30
+ before(:example) do
31
+ File.new("#{tempdir}/all_files.json", 'w')
32
+ end
33
+
34
+ after(:example) do
35
+ FileUtils.rm "#{tempdir}/all_files.json"
36
+ end
37
+
38
+ subject { core.all_files }
39
+ it { is_expected.to eq(["#{tempdir}/all_files.json"]) }
40
+ end
41
+
42
+ describe '#all_file_ids_for_selected_resources' do
43
+ before(:example) do
44
+ Dir.mkdir("#{tempdir}/dashboards")
45
+ Dir.mkdir("#{tempdir}/monitors")
46
+ File.new("#{tempdir}/dashboards/all_files.json", 'w')
47
+ File.new("#{tempdir}/monitors/12345.json", 'w')
48
+ end
49
+
50
+ after(:example) do
51
+ FileUtils.rm "#{tempdir}/dashboards/all_files.json"
52
+ FileUtils.rm "#{tempdir}/monitors/12345.json"
53
+ end
54
+
55
+ subject { core.all_file_ids_for_selected_resources }
56
+ it { is_expected.to eq(['all_files']) }
57
+ end
58
+
59
+ describe '#class_from_id' do
60
+ before(:example) do
61
+ core.write_file('abc', "#{tempdir}/core/abc-123-def.json")
62
+ end
63
+
64
+ after(:example) do
65
+ FileUtils.rm "#{tempdir}/core/abc-123-def.json"
66
+ end
67
+ subject { core.class_from_id('abc-123-def') }
68
+ it { is_expected.to eq DatadogBackup::Core }
69
+ end
70
+
71
+ describe '#dump' do
72
+ context ':json' do
73
+ subject { core.dump({ a: :b }) }
74
+ it { is_expected.to eq(%({\n "a": "b"\n})) }
75
+ end
76
+
77
+ context ':yaml' do
78
+ subject { core_yaml.dump({ 'a' => 'b' }) }
79
+ it { is_expected.to eq(%(---\na: b\n)) }
80
+ end
81
+ end
82
+
83
+ describe '#filename' do
84
+ context ':json' do
85
+ subject { core.filename('abc-123-def') }
86
+ it { is_expected.to eq("#{tempdir}/core/abc-123-def.json") }
87
+ end
88
+
89
+ context ':yaml' do
90
+ subject { core_yaml.filename('abc-123-def') }
91
+ it { is_expected.to eq("#{tempdir}/core/abc-123-def.yaml") }
92
+ end
93
+ end
94
+
95
+ describe '#file_type' do
96
+ before(:example) do
97
+ File.new("#{tempdir}/file_type.json", 'w')
98
+ end
99
+
100
+ after(:example) do
101
+ FileUtils.rm "#{tempdir}/file_type.json"
102
+ end
103
+
104
+ subject { core.file_type("#{tempdir}/file_type.json") }
105
+ it { is_expected.to eq :json }
106
+ end
107
+
108
+ describe '#find_file_by_id' do
109
+ before(:example) do
110
+ File.new("#{tempdir}/find_file.json", 'w')
111
+ end
112
+
113
+ after(:example) do
114
+ FileUtils.rm "#{tempdir}/find_file.json"
115
+ end
116
+
117
+ subject { core.find_file_by_id('find_file') }
118
+ it { is_expected.to eq "#{tempdir}/find_file.json" }
119
+ end
120
+
121
+ describe '#load_from_file' do
122
+ context ':json' do
123
+ subject { core.load_from_file(%({\n "a": "b"\n}), :json) }
124
+ it { is_expected.to eq('a' => 'b') }
125
+ end
126
+
127
+ context ':yaml' do
128
+ subject { core.load_from_file(%(---\na: b\n), :yaml) }
129
+ it { is_expected.to eq('a' => 'b') }
130
+ end
131
+ end
132
+
133
+ describe '#load_from_file_by_id' do
134
+ context 'written in json read in yaml mode' do
135
+ before(:example) { core.write_file(%({"a": "b"}), "#{tempdir}/core/abc-123-def.json") }
136
+ after(:example) { FileUtils.rm "#{tempdir}/core/abc-123-def.json" }
137
+
138
+ subject { core_yaml.load_from_file_by_id('abc-123-def') }
139
+ it { is_expected.to eq('a' => 'b') }
140
+ end
141
+ context 'written in yaml read in json mode' do
142
+ before(:example) { core.write_file(%(---\na: b), "#{tempdir}/core/abc-123-def.yaml") }
143
+ after(:example) { FileUtils.rm "#{tempdir}/core/abc-123-def.yaml" }
144
+
145
+ subject { core.load_from_file_by_id('abc-123-def') }
146
+ it { is_expected.to eq('a' => 'b') }
147
+ end
148
+
149
+ context 'Integer as parameter' do
150
+ before(:example) { core.write_file(%(---\na: b), "#{tempdir}/core/12345.yaml") }
151
+ after(:example) { FileUtils.rm "#{tempdir}/core/12345.yaml" }
152
+
153
+ subject { core.load_from_file_by_id(12_345) }
154
+ it { is_expected.to eq('a' => 'b') }
155
+ end
156
+ end
157
+
158
+ describe '#write_file' do
159
+ subject { core.write_file('abc123', "#{tempdir}/core/abc-123-def.json") }
160
+ let(:file_like_object) { double }
161
+
162
+ it 'writes a file to abc-123-def.json' do
163
+ allow(File).to receive(:open).and_call_original
164
+ allow(File).to receive(:open).with("#{tempdir}/core/abc-123-def.json", 'w').and_return(file_like_object)
165
+ allow(file_like_object).to receive(:write)
166
+ allow(file_like_object).to receive(:close)
167
+
168
+ subject
169
+
170
+ expect(file_like_object).to have_received(:write).with('abc123')
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe DatadogBackup::Monitors do
6
+ let(:client_double) { double }
7
+ let(:tempdir) { Dir.mktmpdir }
8
+ let(:monitors) do
9
+ DatadogBackup::Monitors.new(
10
+ action: 'backup',
11
+ client: client_double,
12
+ backup_dir: tempdir,
13
+ output_format: :json,
14
+ resources: [],
15
+ logger: Logger.new('/dev/null')
16
+ )
17
+ end
18
+ let(:monitor_description) do
19
+ {
20
+ 'query' => 'bar',
21
+ 'message' => 'foo',
22
+ 'id' => 123_455,
23
+ 'name' => 'foo',
24
+ 'overall_state' => 'OK',
25
+ 'overall_state_modified' => '2020-07-27T22:00:00+00:00'
26
+ }
27
+ end
28
+ let(:clean_monitor_description) do
29
+ {
30
+ 'id' => 123_455,
31
+ 'message' => 'foo',
32
+ 'name' => 'foo',
33
+ 'query' => 'bar'
34
+ }
35
+ end
36
+ let(:all_monitors) do
37
+ [
38
+ '200',
39
+ [
40
+ monitor_description
41
+ ]
42
+ ]
43
+ end
44
+ let(:example_monitor) do
45
+ [
46
+ '200',
47
+ monitor_description
48
+ ]
49
+ end
50
+ before(:example) do
51
+ allow(client_double).to receive(:get_all_monitors).and_return(all_monitors)
52
+ allow(client_double).to receive(:get_monitor).and_return(example_monitor)
53
+ end
54
+
55
+ describe '#all_monitors' do
56
+ subject { monitors.all_monitors }
57
+
58
+ it 'calls get_all_monitors' do
59
+ subject
60
+ expect(client_double).to have_received(:get_all_monitors)
61
+ end
62
+
63
+ it { is_expected.to eq [monitor_description] }
64
+ end
65
+
66
+ describe '#backup' do
67
+ subject { monitors.backup }
68
+
69
+ it 'is expected to create a file' do
70
+ file = double('file')
71
+ allow(File).to receive(:open).with(monitors.filename(123_455), 'w').and_return(file)
72
+ expect(file).to receive(:write).with(::JSON.pretty_generate(clean_monitor_description))
73
+ allow(file).to receive(:close)
74
+
75
+ monitors.backup
76
+ end
77
+ end
78
+
79
+ describe '#diff' do
80
+ example 'it ignores `overall_state` and `overall_state_modified`' do
81
+ monitors.write_file(monitors.dump(monitor_description), monitors.filename(123_455))
82
+ allow(client_double).to receive(:get_all_monitors).and_return(
83
+ [
84
+ '200',
85
+ [
86
+ {
87
+ 'query' => 'bar',
88
+ 'message' => 'foo',
89
+ 'id' => 123_455,
90
+ 'name' => 'foo',
91
+ 'overall_state' => 'NO DATA',
92
+ 'overall_state_modified' => '2020-07-27T22:55:55+00:00'
93
+ }
94
+ ]
95
+ ]
96
+ )
97
+
98
+ expect(monitors.diff(123_455)).to eq ''
99
+
100
+ FileUtils.rm monitors.filename(123_455)
101
+ end
102
+ end
103
+
104
+ describe '#filename' do
105
+ subject { monitors.filename(123_455) }
106
+ it { is_expected.to eq("#{tempdir}/monitors/123455.json") }
107
+ end
108
+
109
+ describe '#get_by_id' do
110
+ context 'Integer' do
111
+ subject { monitors.get_by_id(123_455) }
112
+ it { is_expected.to eq monitor_description }
113
+ end
114
+ context 'String' do
115
+ subject { monitors.get_by_id('123455') }
116
+ it { is_expected.to eq monitor_description }
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require 'climate_control'
5
+ require 'timeout'
6
+
7
+ describe 'bin/datadog_backup' do
8
+ # Contract Or[nil,String] => self
9
+ def run_bin(args = '', input = nil)
10
+ status = nil
11
+ output = ''
12
+ cmd = "bin/datadog_backup #{args}"
13
+ Open3.popen2e(cmd) do |i, oe, t|
14
+ pid = t.pid
15
+
16
+ if input
17
+ i.puts input
18
+ i.close
19
+ end
20
+
21
+ Timeout.timeout(1.0) do
22
+ oe.each do |v|
23
+ output += v
24
+ end
25
+ end
26
+ rescue Timeout::Error
27
+ LOGGER.warn "Timing out #{t.inspect} after 1 second"
28
+ Process.kill(15, pid)
29
+ ensure
30
+ status = t.value
31
+ end
32
+ [output, status]
33
+ end
34
+
35
+ required_vars = %w[
36
+ DATADOG_API_KEY
37
+ DATADOG_APP_KEY
38
+ ]
39
+
40
+ before do
41
+ required_vars.each do |v|
42
+ ClimateControl.env[v] = v.downcase
43
+ end
44
+ end
45
+
46
+ required_vars.map do |v|
47
+ it "dies unless given ENV[#{v}]" do
48
+ ClimateControl.env[v] = nil
49
+ _, status = run_bin('backup')
50
+ expect(status).to_not be_success
51
+ end
52
+ end
53
+
54
+ it 'supplies help' do
55
+ out_err, status = run_bin('--help')
56
+ expect(out_err).to match(/Usage: datadog_backup/)
57
+ expect(status).to be_success
58
+ end
59
+ end