datadog_backup 0.9.0

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