wavefront-client 3.2.0 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.travis.yml +1 -0
- data/README-cli.md +108 -1
- data/bin/wavefront +49 -11
- data/lib/wavefront/batch_writer.rb +247 -0
- data/lib/wavefront/cli/alerts.rb +50 -27
- data/lib/wavefront/cli/batch_write.rb +227 -0
- data/lib/wavefront/cli/events.rb +1 -1
- data/lib/wavefront/cli/ts.rb +2 -2
- data/lib/wavefront/cli/write.rb +89 -0
- data/lib/wavefront/cli.rb +19 -13
- data/lib/wavefront/client/version.rb +1 -1
- data/lib/wavefront/constants.rb +3 -0
- data/lib/wavefront/events.rb +39 -18
- data/lib/wavefront/exception.rb +8 -1
- data/lib/wavefront/mixins.rb +9 -2
- data/lib/wavefront/writer.rb +7 -2
- data/spec/spec_helper.rb +52 -1
- data/spec/wavefront/batch_writer_spec.rb +523 -0
- data/spec/wavefront/cli/alerts_spec.rb +153 -0
- data/spec/wavefront/cli/batch_write_spec.rb +251 -0
- data/spec/wavefront/cli/events_spec.rb +43 -0
- data/spec/wavefront/cli/resources/alert.human.erb +14 -0
- data/spec/wavefront/cli/resources/alert.human2 +14 -0
- data/spec/wavefront/cli/resources/alert.json +38 -0
- data/spec/wavefront/cli/resources/alert.raw +1 -0
- data/spec/wavefront/cli/resources/alert.ruby +1 -0
- data/spec/wavefront/cli/resources/write.parabola +49 -0
- data/spec/wavefront/cli/write_spec.rb +112 -0
- data/spec/wavefront/cli_spec.rb +68 -0
- data/spec/wavefront/events_spec.rb +111 -0
- data/spec/wavefront/mixins_spec.rb +16 -1
- data/spec/wavefront/writer_spec.rb +0 -7
- data/wavefront-client.gemspec +1 -1
- metadata +35 -6
@@ -0,0 +1,14 @@
|
|
1
|
+
name Test Alert
|
2
|
+
created 2016-07-29 16:54:22 +0100
|
3
|
+
severity WARN
|
4
|
+
condition ts("dev.cli.test_metric") > 0
|
5
|
+
displayExpression ts("dev.cli.test_metric")
|
6
|
+
minutes 5
|
7
|
+
resolveAfterMinutes
|
8
|
+
updated 2016-07-29 16:55:35 +0100
|
9
|
+
alertStates CHECKING
|
10
|
+
metricsUsed
|
11
|
+
hostsUsed
|
12
|
+
additionalInformation This alert has been made up to feed into the test
|
13
|
+
framework for the Ruby CLI. It is not real. Even this
|
14
|
+
text is just placeholder text.
|
@@ -0,0 +1,38 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"customerTagsWithCounts": {
|
4
|
+
"test": 1
|
5
|
+
},
|
6
|
+
"userTagsWithCounts": {
|
7
|
+
},
|
8
|
+
"created": 1469807662271,
|
9
|
+
"name": "Test Alert",
|
10
|
+
"conditionQBEnabled": false,
|
11
|
+
"displayExpressionQBEnabled": false,
|
12
|
+
"condition": "ts(\"dev.cli.test_metric\") > 0",
|
13
|
+
"displayExpression": "ts(\"dev.cli.test_metric\")",
|
14
|
+
"minutes": 5,
|
15
|
+
"target": "someone@example.com",
|
16
|
+
"failingHostLabelPairs": [
|
17
|
+
|
18
|
+
],
|
19
|
+
"updated": 1469807735018,
|
20
|
+
"severity": "WARN",
|
21
|
+
"additionalInformation": "This alert has been made up to feed into the test framework for the Ruby CLI. It is not real. Even this text is just placeholder text.",
|
22
|
+
"activeMaintenanceWindows": [
|
23
|
+
|
24
|
+
],
|
25
|
+
"inMaintenanceHostLabelPairs": [
|
26
|
+
|
27
|
+
],
|
28
|
+
"prefiringHostLabelPairs": [
|
29
|
+
|
30
|
+
],
|
31
|
+
"alertStates": [
|
32
|
+
"CHECKING"
|
33
|
+
],
|
34
|
+
"inTrash": false,
|
35
|
+
"numMetricsUsed": 0,
|
36
|
+
"numHostsUsed": 0
|
37
|
+
}
|
38
|
+
]
|
@@ -0,0 +1 @@
|
|
1
|
+
[{"customerTagsWithCounts":{"test":1},"userTagsWithCounts":{},"created":1469807662271,"name":"Test Alert","conditionQBEnabled":false,"displayExpressionQBEnabled":false,"condition":"ts(\"dev.cli.test_metric\") > 0","displayExpression":"ts(\"dev.cli.test_metric\")","minutes":5,"target":"someone@example.com","failingHostLabelPairs":[],"updated":1469807735018,"severity":"WARN","additionalInformation":"This alert has been made up to feed into the test framework for the Ruby CLI. It is not real. Even this text is just placeholder text.","activeMaintenanceWindows":[],"inMaintenanceHostLabelPairs":[],"prefiringHostLabelPairs":[],"alertStates":["CHECKING"],"inTrash":false,"numMetricsUsed":0,"numHostsUsed":0}]
|
@@ -0,0 +1 @@
|
|
1
|
+
"[{\"customerTagsWithCounts\":{\"test\":1},\"userTagsWithCounts\":{},\"created\":1469807662271,\"name\":\"Test Alert\",\"conditionQBEnabled\":false,\"displayExpressionQBEnabled\":false,\"condition\":\"ts(\\\"dev.cli.test_metric\\\") > 0\",\"displayExpression\":\"ts(\\\"dev.cli.test_metric\\\")\",\"minutes\":5,\"target\":\"someone@example.com\",\"failingHostLabelPairs\":[],\"updated\":1469807735018,\"severity\":\"WARN\",\"additionalInformation\":\"This alert has been made up to feed into the test framework for the Ruby CLI. It is not real. Even this text is just placeholder text.\",\"activeMaintenanceWindows\":[],\"inMaintenanceHostLabelPairs\":[],\"prefiringHostLabelPairs\":[],\"alertStates\":[\"CHECKING\"],\"inTrash\":false,\"numMetricsUsed\":0,\"numHostsUsed\":0}]"
|
@@ -0,0 +1,49 @@
|
|
1
|
+
1470075208 6760
|
2
|
+
1470075209 6290
|
3
|
+
1470075210 5840
|
4
|
+
1470075211 5410
|
5
|
+
1470075212 5000
|
6
|
+
1470075213 4610
|
7
|
+
1470075214 4240
|
8
|
+
1470075215 3890
|
9
|
+
1470075216 3560
|
10
|
+
1470075217 3250
|
11
|
+
1470075218 2960
|
12
|
+
1470075219 2690
|
13
|
+
1470075220 2440
|
14
|
+
1470075221 2210
|
15
|
+
1470075222 2000
|
16
|
+
1470075223 1810
|
17
|
+
1470075224 1640
|
18
|
+
1470075225 1490
|
19
|
+
1470075226 1360
|
20
|
+
1470075227 1250
|
21
|
+
1470075228 1160
|
22
|
+
1470075229 1090
|
23
|
+
1470075230 1040
|
24
|
+
1470075231 1010
|
25
|
+
1470075232 1000
|
26
|
+
1470075233 1010
|
27
|
+
1470075234 1040
|
28
|
+
1470075235 1090
|
29
|
+
1470075236 1160
|
30
|
+
1470075237 1250
|
31
|
+
1470075238 1360
|
32
|
+
1470075239 1490
|
33
|
+
1470075240 1640
|
34
|
+
1470075241 1810
|
35
|
+
1470075242 2000
|
36
|
+
1470075243 2210
|
37
|
+
1470075244 2440
|
38
|
+
1470075245 2690
|
39
|
+
1470075246 2960
|
40
|
+
1470075247 3250
|
41
|
+
1470075248 3560
|
42
|
+
1470075249 3890
|
43
|
+
1470075250 4240
|
44
|
+
1470075251 4610
|
45
|
+
1470075252 5000
|
46
|
+
1470075253 5410
|
47
|
+
1470075254 5840
|
48
|
+
1470075255 6290
|
49
|
+
1470075256 6760
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
opts = {}
|
5
|
+
args = 'write'
|
6
|
+
k = Wavefront::Cli::Write.new(opts, args)
|
7
|
+
|
8
|
+
describe '#write_metric' do
|
9
|
+
it 'writes a point to a socket' do
|
10
|
+
socket = Mocket.new
|
11
|
+
allow(TCPSocket).to receive(:new).and_return(socket)
|
12
|
+
now = Time.now
|
13
|
+
expect(socket).to receive(:puts).with(
|
14
|
+
"1234 test.metric #{now.to_i} host=testhost")
|
15
|
+
k.write_metric('test.metric', '1234', {
|
16
|
+
timestamp: now, host_name: 'testhost'})
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'writes a point with tags to a socket' do
|
20
|
+
socket = Mocket.new
|
21
|
+
allow(TCPSocket).to receive(:new).and_return(socket)
|
22
|
+
now = Time.now
|
23
|
+
expect(socket).to receive(:puts).with(
|
24
|
+
"5678 test.metric2 #{now.to_i} host=testhost t1=\"v1\" t2=\"v2\"")
|
25
|
+
k.write_metric('test.metric2', '5678', {
|
26
|
+
timestamp: now, host_name: 'testhost', point_tags:
|
27
|
+
{t1: 'v1', t2: 'v2'}})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#valid_host?' do
|
32
|
+
|
33
|
+
it 'accepts valid hostnames' do
|
34
|
+
expect(k.valid_host?('valid-host')).to be_truthy
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'rejects invalid hostnames' do
|
38
|
+
expect(k.valid_host?('!nval!d_HOST')).to be_falsey
|
39
|
+
expect(k.valid_host?('a' * 1025)).to be_falsey
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#valid_value?' do
|
45
|
+
|
46
|
+
it 'accepts real numbers' do
|
47
|
+
expect(k.valid_value?(123)).to be true
|
48
|
+
expect(k.valid_value?(-123)).to be true
|
49
|
+
expect(k.valid_value?(1.23)).to be true
|
50
|
+
expect(k.valid_value?(1.5e07)).to be true
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'accepts integer-type strings' do
|
54
|
+
expect(k.valid_value?('123')).to be true
|
55
|
+
expect(k.valid_value?('-123')).to be true
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'accepts exponential-type strings' do
|
59
|
+
expect(k.valid_value?('1.23e06')).to be true
|
60
|
+
expect(k.valid_value?('-1.23e06')).to be true
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'rejects random strings' do
|
64
|
+
%w(abc 1.2.3 1.2e2e3 6e).each do |str|
|
65
|
+
expect{k.valid_value?(str)}.to raise_exception(
|
66
|
+
Wavefront::Exception::InvalidMetricValue)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#valid_metric?' do
|
72
|
+
it 'accepts some valid metrics' do
|
73
|
+
expect(k.valid_metric?('valid.metric.path')).to be true
|
74
|
+
expect(k.valid_metric?('valid.metric-path')).to be true
|
75
|
+
expect(k.valid_metric?('valid.metric_path')).to be true
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'rejects non-strings' do
|
79
|
+
[123, {k: 'v'}, []].each do |el|
|
80
|
+
expect{k.valid_metric?(el)}.to raise_exception(
|
81
|
+
Wavefront::Exception::InvalidMetricName)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'rejects too-long paths' do
|
86
|
+
expect{k.valid_metric?('aaaa.' * 300 )}.to raise_exception(
|
87
|
+
Wavefront::Exception::InvalidMetricName)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'rejects single-element paths' do
|
91
|
+
expect{k.valid_metric?('metric')}.to raise_exception(
|
92
|
+
Wavefront::Exception::InvalidMetricName)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'rejects invalid characters' do
|
96
|
+
expect{k.valid_metric?('!nval!d.metric')}.to raise_exception(
|
97
|
+
Wavefront::Exception::InvalidMetricName)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#prep_tags' do
|
102
|
+
it 'handles invalid input' do
|
103
|
+
expect(k.prep_tags('string')).to eq([])
|
104
|
+
expect(k.prep_tags({key: 'val'})).to eq([])
|
105
|
+
expect(k.prep_tags(['badtag1', 'badtag2'])).to eq([])
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'handles sample valid input' do
|
109
|
+
expect(k.prep_tags(['key1=val1', 'key2=val2'])).to eq(
|
110
|
+
[['key1', 'val1'], ['key2', 'val2']])
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2015 Wavefront Inc.
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
14
|
+
|
15
|
+
=end
|
16
|
+
|
17
|
+
require 'spec_helper'
|
18
|
+
require 'pathname'
|
19
|
+
require 'tempfile'
|
20
|
+
|
21
|
+
# A sample config file with two profiles.
|
22
|
+
#
|
23
|
+
pf_src = %Q(
|
24
|
+
[default]
|
25
|
+
token = 12345678-abcd-1234-abcd-123456789012
|
26
|
+
endpoint = metrics.wavefront.com
|
27
|
+
format = human
|
28
|
+
proxy = wavefront.localnet
|
29
|
+
|
30
|
+
[other]
|
31
|
+
token = abcdefab-0123-abcd-0123-abcdefabcdef
|
32
|
+
endpoint = test.wavefront.com
|
33
|
+
format = human
|
34
|
+
)
|
35
|
+
|
36
|
+
describe Wavefront::Cli do
|
37
|
+
|
38
|
+
profile = Tempfile.new('wf_test_profile')
|
39
|
+
cf = profile.path
|
40
|
+
profile.write(pf_src)
|
41
|
+
profile.close
|
42
|
+
|
43
|
+
it 'does not complain when there is no config file' do
|
44
|
+
k = Wavefront::Cli.new({config: '/no/file', profile: 'default'}, false)
|
45
|
+
expect(k.load_profile).to be_kind_of(NilClass)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'loads the specified profile' do
|
49
|
+
k = Wavefront::Cli.new({config: cf, profile: 'other'}, false)
|
50
|
+
pf = k.load_profile
|
51
|
+
expect(pf).not_to include('proxy')
|
52
|
+
expect(pf[:token]).to eq('abcdefab-0123-abcd-0123-abcdefabcdef')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'loads the default when no profile is specified' do
|
56
|
+
k = Wavefront::Cli.new({config: cf}, false)
|
57
|
+
pf = k.load_profile
|
58
|
+
expect(pf[:proxy]).to eq('wavefront.localnet')
|
59
|
+
expect(pf[:token]).to eq('12345678-abcd-1234-abcd-123456789012')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'prefers command-line options to config file values' do
|
63
|
+
k = Wavefront::Cli.new({config: cf, format: 'graphite'}, false)
|
64
|
+
pf = k.load_profile
|
65
|
+
expect(pf[:format]).to eq('graphite')
|
66
|
+
expect(pf[:token]).to eq('12345678-abcd-1234-abcd-123456789012')
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
=begin
|
2
|
+
Copyright 2016 Wavefront Inc.
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
14
|
+
|
15
|
+
=end
|
16
|
+
|
17
|
+
require 'spec_helper'
|
18
|
+
|
19
|
+
describe Wavefront::Events do
|
20
|
+
|
21
|
+
describe "#initialize" do
|
22
|
+
it 'puts the token in a suitable header' do
|
23
|
+
k = Wavefront::Events.new(TEST_TOKEN)
|
24
|
+
expect(k.headers).to eq({ :'X-AUTH-TOKEN' => TEST_TOKEN })
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#create_uri' do
|
29
|
+
it 'generates a correct URI if host and path are supplied' do
|
30
|
+
k = Wavefront::Events.new(TEST_TOKEN)
|
31
|
+
res = k.create_uri({
|
32
|
+
host: 'test.wavefront.com', path: '/alternate/api/'
|
33
|
+
})
|
34
|
+
|
35
|
+
expect(res).to be_kind_of(URI)
|
36
|
+
expect(res.port).to be(443)
|
37
|
+
expect(res.host).to eq('test.wavefront.com')
|
38
|
+
expect(res.path).to eq('/alternate/api/')
|
39
|
+
expect(res.query).to be(nil)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'generates a correct URI if no host or path are supplied' do
|
43
|
+
k = Wavefront::Events.new(TEST_TOKEN)
|
44
|
+
res = k.create_uri
|
45
|
+
|
46
|
+
expect(res).to be_kind_of(URI)
|
47
|
+
expect(res.port).to be(443)
|
48
|
+
expect(res.host).to eq('metrics.wavefront.com')
|
49
|
+
expect(res.path).to eq('/api/events/')
|
50
|
+
expect(res.query).to be(nil)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#close_uri' do
|
55
|
+
it 'generates a correct URI if host and path are supplied' do
|
56
|
+
k = Wavefront::Events.new(TEST_TOKEN)
|
57
|
+
res = k.close_uri({
|
58
|
+
host: 'test.wavefront.com', path: '/alternate/api/'
|
59
|
+
})
|
60
|
+
|
61
|
+
expect(res).to be_kind_of(URI)
|
62
|
+
expect(res.port).to be(443)
|
63
|
+
expect(res.host).to eq('test.wavefront.com')
|
64
|
+
expect(res.path).to eq('/alternate/api/close')
|
65
|
+
expect(res.query).to be(nil)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'generates a correct URI if no host or path are supplied' do
|
69
|
+
k = Wavefront::Events.new(TEST_TOKEN)
|
70
|
+
res = k.close_uri
|
71
|
+
|
72
|
+
expect(res).to be_kind_of(URI)
|
73
|
+
expect(res.port).to be(443)
|
74
|
+
expect(res.host).to eq('metrics.wavefront.com')
|
75
|
+
expect(res.path).to eq('/api/events/close')
|
76
|
+
expect(res.query).to be(nil)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#create_qs' do
|
81
|
+
payload = { key1: 'val1', key2: 'val2' }
|
82
|
+
|
83
|
+
it 'generates a query string with no hosts' do
|
84
|
+
k = Wavefront::Events.new(TEST_TOKEN)
|
85
|
+
expect(k.create_qs(payload)).to eq('key1=val1&key2=val2')
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'generates a query string with single host as a string' do
|
89
|
+
payload[:h] = ['host1']
|
90
|
+
k = Wavefront::Events.new(TEST_TOKEN)
|
91
|
+
expect(k.create_qs(payload)).to eq('key1=val1&key2=val2&h=host1')
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'generates a query string with multiple hosts' do
|
95
|
+
payload[:h] = ['host1', 'host2', 'host3']
|
96
|
+
k = Wavefront::Events.new(TEST_TOKEN)
|
97
|
+
expect(k.create_qs(payload)).to eq(
|
98
|
+
'key1=val1&key2=val2&h=host1&h=host2&h=host3')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#hash_to_qs' do
|
103
|
+
it 'makes a proper query string' do
|
104
|
+
k = Wavefront::Events.new(TEST_TOKEN)
|
105
|
+
expect(k.hash_to_qs({
|
106
|
+
key1: 'val1',
|
107
|
+
key2: 'value 2'
|
108
|
+
})).to eq('key1=val1&key2=value%202')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
=begin
|
1
|
+
=begin
|
2
2
|
Copyright 2015 Wavefront Inc.
|
3
3
|
Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
you may not use this file except in compliance with the License.
|
@@ -26,4 +26,19 @@ describe Wavefront::Mixins do
|
|
26
26
|
expect(interpolate_schema(wavefront_schema, HOST, 1)).to eq("a.#{HOST}.b.c.d.e")
|
27
27
|
expect(interpolate_schema(wavefront_schema, HOST, 2)).to eq("a.b.#{HOST}.c.d.e")
|
28
28
|
end
|
29
|
+
|
30
|
+
it 'provides a method to parse times' do
|
31
|
+
expect(parse_time(1469711187)).to eq(1469711187)
|
32
|
+
expect(parse_time('1469711187')).to eq(1469711187)
|
33
|
+
expect(parse_time('2016-07-28 14:25:36 +0100')).to eq(1469712336)
|
34
|
+
expect(parse_time('2016-07-28')).to eq(1469664000)
|
35
|
+
expect(parse_time(Time.now)).to be_kind_of(Integer)
|
36
|
+
expect{parse_time('nonsense')}.to raise_exception(RuntimeError,
|
37
|
+
"cannot parse timestamp 'nonsense'.")
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'provides a method to convert epoch times to milliseconds' do
|
41
|
+
expect(time_to_ms(1469711187)).to eq(1469711187000)
|
42
|
+
expect(time_to_ms('1469711187')).to be(false)
|
43
|
+
end
|
29
44
|
end
|
@@ -15,15 +15,8 @@ See the License for the specific language governing permissions and
|
|
15
15
|
=end
|
16
16
|
|
17
17
|
require 'spec_helper'
|
18
|
-
require 'pathname'
|
19
18
|
require 'socket'
|
20
19
|
|
21
|
-
class Mocket
|
22
|
-
def puts(str)
|
23
|
-
return true
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
20
|
describe Wavefront::Writer do
|
28
21
|
|
29
22
|
it 'has some defaults' do
|