mc_dump 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OTYxNjg3MjBmMDI2N2M4NTQwNzY2MWQ0YzlhZDJlNTIxZmRkY2NjNA==
5
+ data.tar.gz: !binary |-
6
+ YzcyODBhODJmMjk0NTMyZWZjYTQ5MzQ3NzdkZTdkM2QzZTIxNWVjMQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NmI0Y2RlNjA3MTk2ZDdmOTVkMTQ5MWVkZDZkZTA5YTY1MDdmYzY0MTFlMDJi
10
+ MTI4NjVlMTRlNjlkYjk1MTczNzM1NTAzMjE5N2I0YTlmMDNhYzliYTU5ODA5
11
+ YzI4YzM2ZGQ0NzE2NzU5YzQ4MGQwYzc0OGE4MzZiZWU2OTBkYTY=
12
+ data.tar.gz: !binary |-
13
+ ZTRmMWUzYWIxNTk3NWJjZGJkZjc5ODE1YzVmYWEwNzBiNjA1OGU3YTVkNGE5
14
+ NGM5OGFmMDY4NDM5NGJmMmM5NzkzNTg5YTYxZjJkOTVmN2NkMjhmMjdjN2Rj
15
+ Y2Y4MjE3MDZmYWRlMmUxMWJmNTBmNzc4MzRhZjE1NDkxMGM5MmU=
@@ -0,0 +1,29 @@
1
+ module McDump
2
+ module Memcached
3
+
4
+ class Item
5
+
6
+ def self.parse(dump, items_id)
7
+ dump.scan(/^ITEM (.+?) \[(\d+) b; (\d+) s\]$/).map do |item_data|
8
+ cache_key, size_in_bytes, expires_string = item_data
9
+ self.new(
10
+ items_id: items_id,
11
+ cache_key: cache_key,
12
+ expiration_time: Time.at(expires_string.to_i),
13
+ size_in_bytes: size_in_bytes.to_i
14
+ )
15
+ end
16
+ end
17
+
18
+ def initialize(args)
19
+ @data = args
20
+ end
21
+
22
+ def to_h
23
+ @data.clone
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ module McDump
2
+ module Memcached
3
+
4
+ class Server
5
+
6
+ def initialize(connection_args)
7
+ @connection_args = connection_args
8
+ end
9
+
10
+ def items
11
+ McDump::Telnet::Session.open(@connection_args) do |session|
12
+ item_stats = McDump::Memcached::Stat.parse(session.stats)
13
+ item_stats.map { |stat| stat.items(session) }.flatten
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ module McDump
2
+ module Memcached
3
+
4
+ class Stat
5
+
6
+ def self.parse(dump)
7
+ dump.scan(/STAT items:(\d+):number (\d+)/).map do |data|
8
+ self.new(items_id: data[0], number: data[1])
9
+ end
10
+ end
11
+
12
+ def initialize(args)
13
+ @items_id = args[:items_id]
14
+ @number = args[:number]
15
+ end
16
+
17
+ def items(telnet_session)
18
+ McDump::Memcached::Item.parse(telnet_session.items(@items_id, @number), @items_id)
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ module McDump
2
+ module Rake
3
+
4
+ class Task < ::Rake::TaskLib
5
+
6
+ def initialize(name, connection_args)
7
+ desc "Dumps contents of a memcached instance, supports arguments: host, port, timeout_in_seconds"
8
+ task(name) do
9
+ McDump.server({
10
+ host: ENV["host"],
11
+ port: ENV["port"],
12
+ timeout_in_seconds: ENV["timeout_in_seconds"]
13
+ }.merge(connection_args))
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module McDump
2
+
3
+ class Report
4
+
5
+ def initialize(items)
6
+ @items = items
7
+ end
8
+
9
+ def dump(io=$stdout)
10
+ column_size_metadata = determine_column_size_metadata
11
+ column_names = column_size_metadata.keys
12
+ line_format = "|#{column_names.map { |name| " %#{column_size_metadata[name]}s " }.join("|")}|"
13
+ io.puts line_format % column_names
14
+ @items.each { |item| io.puts line_format % item.to_h.values_at(*column_names) }
15
+ end
16
+
17
+ private
18
+
19
+ def determine_column_size_metadata
20
+ @items.reduce({}) do |size_metadata, item|
21
+ item.to_h.each do |data_key, data_value|
22
+ size_metadata[data_key] ||= data_key.to_s.length
23
+ size_metadata[data_key] = [ data_value.to_s.length, size_metadata[data_key] ].max
24
+ end
25
+ size_metadata
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,25 @@
1
+ module McDump
2
+ module Telnet
3
+
4
+ class Connection
5
+
6
+ def initialize(args)
7
+ @telnet = Net::Telnet::new(
8
+ "Host" => args[:host],
9
+ "Port" => args[:port],
10
+ "Timeout" => args[:timeout_in_seconds] || 5
11
+ )
12
+ end
13
+
14
+ def execute(string)
15
+ @telnet.cmd("String" => string, "Match" => /^END/)
16
+ end
17
+
18
+ def close
19
+ @telnet.close
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ module McDump
2
+ module Telnet
3
+
4
+ class Session
5
+
6
+ def self.open(connection_args, &block)
7
+ session = self.new(connection_args)
8
+ block.call(session).tap { session.close }
9
+ end
10
+
11
+ def initialize(connection_args)
12
+ @connection = McDump::Telnet::Connection.new(connection_args)
13
+ end
14
+
15
+ def stats
16
+ @connection.execute("stats items")
17
+ end
18
+
19
+ def items(id, number)
20
+ @connection.execute("stats cachedump #{id} #{number}")
21
+ end
22
+
23
+ def close
24
+ @connection.close
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module McDump
2
+ VERSION = "0.0.0".freeze
3
+ end
data/lib/mc_dump.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'net/telnet'
2
+
3
+ require_relative 'mc_dump/telnet/connection'
4
+ require_relative 'mc_dump/telnet/session'
5
+ require_relative 'mc_dump/memcached/item'
6
+ require_relative 'mc_dump/memcached/stat'
7
+ require_relative 'mc_dump/memcached/server'
8
+ require_relative 'mc_dump/report'
9
+
10
+ module McDump
11
+
12
+ def self.server(connection_args)
13
+ server = McDump::Memcached::Server.new(connection_args)
14
+ McDump::Report.new(server.items).dump
15
+ end
16
+
17
+ end
@@ -0,0 +1,111 @@
1
+ describe McDump::Memcached::Item do
2
+
3
+ let(:items_id) { "8" }
4
+ let(:cache_key) { SecureRandom.uuid }
5
+ let(:expiration_time) { "1447214865" }
6
+ let(:size_in_bytes) { 321 }
7
+
8
+ let(:args) do
9
+ {
10
+ items_id: items_id,
11
+ cache_key: cache_key,
12
+ expiration_time: expiration_time,
13
+ size_in_bytes: size_in_bytes
14
+ }
15
+ end
16
+
17
+ let(:item) { described_class.new(args) }
18
+
19
+ describe "::parse" do
20
+
21
+ subject { described_class.parse(dump, items_id) }
22
+
23
+ context "when the dump contains many lines" do
24
+
25
+ let(:dump) do
26
+ <<-DUMP
27
+ ITEM namespace:fc7c3121-30c9-478c-9662-99f8b9df8931 [407 b; 1447214865 s]
28
+ ITEM namespace:e81bbb97-d679-4cea-80c2-787950256083 [392 b; 1447214866 s]
29
+ ITEM namespace:f5ed8536-1265-486a-afbf-73a26828a0ce [413 b; 1447214867 s]
30
+ DUMP
31
+ end
32
+
33
+ it "creates an item for each line containing the line cache keys" do
34
+ expected_cache_keys = %w{
35
+ namespace:fc7c3121-30c9-478c-9662-99f8b9df8931
36
+ namespace:e81bbb97-d679-4cea-80c2-787950256083
37
+ namespace:f5ed8536-1265-486a-afbf-73a26828a0ce
38
+ }
39
+ expected_cache_keys.each do |expected_cache_key|
40
+ expect(described_class).to receive(:new).with(hash_including(cache_key: expected_cache_key))
41
+ end
42
+
43
+ subject
44
+ end
45
+
46
+ it "creates an item for each line containing the line expiration times converted to Time" do
47
+ expected_expiration_times = %w{ 1447214865 1447214866 1447214867 }
48
+ expected_expiration_times.each do |expected_expiration_time|
49
+ expectation_as_time = Time.at(expected_expiration_time.to_i)
50
+ expect(described_class).to receive(:new).with(hash_including(expiration_time: expectation_as_time))
51
+ end
52
+
53
+ subject
54
+ end
55
+
56
+ it "creates an item for each line containing the line sizes in bytes" do
57
+ expected_sizes_in_bytes = [ 407, 392, 413 ]
58
+ expected_sizes_in_bytes.each do |expected_size_in_bytes|
59
+ expect(described_class).to receive(:new).with(hash_including(size_in_bytes: expected_size_in_bytes))
60
+ end
61
+
62
+ subject
63
+ end
64
+
65
+ it "creates an item for each line containing the provided items ID" do
66
+ expect(described_class).to receive(:new).with(hash_including(items_id: items_id)).exactly(3).times
67
+
68
+ subject
69
+ end
70
+
71
+ it "returns the created items" do
72
+ items = (1..3).map { instance_double(described_class) }
73
+ allow(described_class).to receive(:new).and_return(*items)
74
+
75
+ expect(subject).to eql(items)
76
+ end
77
+
78
+ end
79
+
80
+ context "when the dump is empty" do
81
+
82
+ let(:dump) { "" }
83
+
84
+ it "returns an empty array" do
85
+ expect(subject).to eql([])
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
92
+ describe "#to_h" do
93
+
94
+ subject { item.to_h }
95
+
96
+ it "returns a hash containing the provided arguments" do
97
+ expect(subject).to eql(args)
98
+ end
99
+
100
+ it "returns a copy of the provided arguments" do
101
+ original_cache_key = cache_key
102
+
103
+ hash = subject
104
+ args[:cache_key] = "modified cache key"
105
+
106
+ expect(hash[:cache_key]).to eql(original_cache_key)
107
+ end
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,52 @@
1
+ describe McDump::Memcached::Server do
2
+
3
+ let(:connection_args) { { host: "some.host", port: 12345 } }
4
+
5
+ let(:server) { described_class.new(connection_args) }
6
+
7
+ describe "#items" do
8
+
9
+ let(:stats_dump) { "some stats dump" }
10
+ let(:items) { (1..3).map { (1..3).map { instance_double(McDump::Memcached::Item) } } }
11
+ let(:stats) { (1..3).map { instance_double(McDump::Memcached::Stat) } }
12
+ let(:telnet_session) { instance_double(McDump::Telnet::Session, stats: stats_dump) }
13
+
14
+ subject { server.items }
15
+
16
+ before(:example) do
17
+ allow(McDump::Telnet::Session).to receive(:open).and_yield(telnet_session)
18
+ allow(McDump::Memcached::Stat).to receive(:parse).and_return(stats)
19
+ stats.zip(items) { |stat, items| allow(stat).to receive(:items).and_return(items) }
20
+ end
21
+
22
+ it "opens a telnet session using the provided connection arguments" do
23
+ expect(McDump::Telnet::Session).to receive(:open).with(connection_args)
24
+
25
+ subject
26
+ end
27
+
28
+ it "retrieves the stats via the Memcached telnet session" do
29
+ expect(telnet_session).to receive(:stats)
30
+
31
+ subject
32
+ end
33
+
34
+ it "parses the stats" do
35
+ expect(McDump::Memcached::Stat).to receive(:parse).with(stats_dump)
36
+
37
+ subject
38
+ end
39
+
40
+ it "retrieves the items for each stat" do
41
+ stats.each { |stat| expect(stat).to receive(:items).with(telnet_session) }
42
+
43
+ subject
44
+ end
45
+
46
+ it "returns all the items" do
47
+ expect(subject).to eql(items.flatten)
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,118 @@
1
+ describe McDump::Memcached::Stat do
2
+
3
+ let(:items_id) { 8 }
4
+ let(:number) { 21 }
5
+
6
+ let(:stat) { described_class.new(items_id: items_id, number: number) }
7
+
8
+ describe "::parse" do
9
+
10
+ subject { described_class.parse(dump) }
11
+
12
+ context "when the dump contains many items" do
13
+
14
+ let(:dump) do
15
+ <<-DUMP
16
+ STAT items:9:number 19
17
+ STAT items:9:age 876543
18
+ STAT items:9:evicted 0
19
+ STAT items:9:evicted_nonzero 0
20
+ STAT items:9:evicted_time 0
21
+ STAT items:9:outofmemory 0
22
+ STAT items:9:tailrepairs 0
23
+ STAT items:9:reclaimed 3
24
+ STAT items:9:expired_unfetched 2
25
+ STAT items:9:evicted_unfetched 0
26
+ STAT items:9:crawler_reclaimed 0
27
+ STAT items:9:crawler_items_checked 0
28
+ STAT items:9:lrutail_reflocked 0
29
+ STAT items:10:number 20
30
+ STAT items:10:age 123456
31
+ STAT items:10:evicted 0
32
+ STAT items:10:evicted_nonzero 0
33
+ STAT items:10:evicted_time 0
34
+ STAT items:10:outofmemory 0
35
+ STAT items:10:tailrepairs 0
36
+ STAT items:10:reclaimed 6
37
+ STAT items:10:expired_unfetched 8
38
+ STAT items:10:evicted_unfetched 0
39
+ STAT items:10:crawler_reclaimed 0
40
+ STAT items:10:crawler_items_checked 0
41
+ STAT items:10:lrutail_reflocked 0
42
+ STAT items:11:number 21
43
+ STAT items:11:age 975319
44
+ STAT items:11:evicted 0
45
+ STAT items:11:evicted_nonzero 0
46
+ STAT items:11:evicted_time 0
47
+ STAT items:11:outofmemory 0
48
+ STAT items:11:tailrepairs 0
49
+ STAT items:11:reclaimed 1
50
+ STAT items:11:expired_unfetched 10
51
+ STAT items:11:evicted_unfetched 0
52
+ STAT items:11:crawler_reclaimed 0
53
+ STAT items:11:crawler_items_checked 0
54
+ STAT items:11:lrutail_reflocked 0
55
+ DUMP
56
+ end
57
+
58
+ it "creates a stat for each item entry containing the number of entries in the cache" do
59
+ stats_arg_expectations = [
60
+ { items_id: "9", number: "19" }, { items_id: "10", number: "20" }, { items_id: "11", number: "21" }
61
+ ]
62
+ stats_arg_expectations.each { |expectation| expect(described_class).to receive(:new).with(expectation) }
63
+
64
+ subject
65
+ end
66
+
67
+ it "returns the stats" do
68
+ stats = (1..3).map { instance_double(described_class) }
69
+ allow(described_class).to receive(:new).and_return(*stats)
70
+
71
+ expect(subject).to eql(stats)
72
+ end
73
+
74
+ end
75
+
76
+ context "when the dump is empty" do
77
+
78
+ let(:dump) { "" }
79
+
80
+ it "returns an empty array" do
81
+ expect(subject).to eql([])
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ describe "#items" do
89
+
90
+ let(:items_dump) { "some items data" }
91
+ let(:telnet_session) { instance_double(McDump::Telnet::Session, items: items_dump) }
92
+
93
+ subject { stat.items(telnet_session) }
94
+
95
+ before(:example) { allow(telnet_session).to receive(:items).and_return(items_dump) }
96
+
97
+ it "determines the items in the memcached instance via the telnet session" do
98
+ expect(telnet_session).to receive(:items).with(items_id, number)
99
+
100
+ subject
101
+ end
102
+
103
+ it "parses the items returned via telnet" do
104
+ expect(McDump::Memcached::Item).to receive(:parse).with(items_dump, items_id)
105
+
106
+ subject
107
+ end
108
+
109
+ it "returns the parsed items" do
110
+ items = (1..3).map { instance_double(McDump::Memcached::Item) }
111
+ allow(McDump::Memcached::Item).to receive(:parse).and_return(items)
112
+
113
+ expect(subject).to eql(items)
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,73 @@
1
+ describe McDump::Rake::Task do
2
+
3
+ describe "constructor" do
4
+
5
+ let(:name) { :some_dump_task }
6
+ let(:host) { "some.host" }
7
+ let(:port) { "12345" }
8
+ let(:timeout_in_seconds) { "10" }
9
+ let(:connection_args) { {} }
10
+
11
+ subject { described_class.new(name, connection_args) }
12
+
13
+ after(:example) { ::Rake::Task[name].clear }
14
+
15
+ it "creates a rake task with the provided name" do
16
+ subject
17
+
18
+ expect(::Rake::Task.task_defined?(name)).to be(true)
19
+ end
20
+
21
+ describe "the created rake task" do
22
+
23
+ subject do
24
+ described_class.new(name, connection_args)
25
+
26
+ ::Rake::Task[name].execute
27
+ end
28
+
29
+ context "when connection arguments are provided" do
30
+
31
+ let(:connection_args) { { host: host, port: port, timeout_in_seconds: timeout_in_seconds } }
32
+
33
+ it "dumps a server identified by the provided connection arguments" do
34
+ expect(McDump).to receive(:server).with(connection_args)
35
+
36
+ subject
37
+ end
38
+
39
+ end
40
+
41
+ context "when no connection arguments are provided" do
42
+
43
+ let(:connection_args) { {} }
44
+
45
+ before(:example) do
46
+ @original_env_host = ENV["host"]
47
+ @original_env_port = ENV["port"]
48
+ @original_env_timeout_in_seconds = ENV["timeout_in_seconds"]
49
+
50
+ ENV["host"] = host
51
+ ENV["port"] = port
52
+ ENV["timeout_in_seconds"] = timeout_in_seconds
53
+ end
54
+
55
+ after(:example) do
56
+ ENV["host"] = @original_env_host
57
+ ENV["port"] = @original_env_port
58
+ ENV["timeout_in_seconds"] = @original_env_timeout_in_seconds
59
+ end
60
+
61
+ it "dumps a server identified by environment variables host, port and timeout_in_seconds" do
62
+ expect(McDump).to receive(:server).with(host: host, port: port, timeout_in_seconds: timeout_in_seconds)
63
+
64
+ subject
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ end
@@ -0,0 +1,61 @@
1
+ describe McDump::Report do
2
+
3
+ let(:report) { described_class.new(items) }
4
+
5
+ describe "#dump" do
6
+
7
+ let(:io) { StringIO.new }
8
+ let(:output) { io.string }
9
+
10
+ subject { report.dump(io) }
11
+
12
+ context "when multiple items are provided" do
13
+
14
+ let(:base_time) { Time.new(2015, 11, 17, 12, 0, 0, "+10:00") }
15
+
16
+ let(:items) do
17
+ (1..3).map do |i|
18
+ McDump::Memcached::Item.new(
19
+ items_id: "#{i}",
20
+ cache_key: "some long cache key #{i}",
21
+ expiration_time: base_time + i,
22
+ size_in_bytes: i * 1024)
23
+ end
24
+ end
25
+
26
+ it "outputs a header row containing each column header spaced to display values" do
27
+ expected_header_row = "| items_id | cache_key | expiration_time | size_in_bytes |"
28
+
29
+ subject
30
+
31
+ expect(output).to start_with(expected_header_row)
32
+ end
33
+
34
+ it "outputs a data row for each item" do
35
+ expected_data_rows =
36
+ "| 1 | some long cache key 1 | 2015-11-17 12:00:01 +1000 | 1024 |\n" +
37
+ "| 2 | some long cache key 2 | 2015-11-17 12:00:02 +1000 | 2048 |\n" +
38
+ "| 3 | some long cache key 3 | 2015-11-17 12:00:03 +1000 | 3072 |"
39
+
40
+ subject
41
+
42
+ expect(output).to include(expected_data_rows)
43
+ end
44
+
45
+ end
46
+
47
+ context "when no items are provided" do
48
+
49
+ let(:items) { [] }
50
+
51
+ it "outputs an empty header row" do
52
+ subject
53
+
54
+ expect(output).to eql("||\n")
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,88 @@
1
+ describe McDump::Telnet::Connection do
2
+
3
+ let(:host) { "some.host" }
4
+ let(:port) { 12345 }
5
+ let(:additional_args) { {} }
6
+ let(:args) { { host: host, port: port }.merge(additional_args) }
7
+ let(:telnet) { instance_double(Net::Telnet) }
8
+
9
+ let(:connection) { described_class.new(args) }
10
+
11
+ before(:example) { allow(Net::Telnet).to receive(:new).and_return(telnet) }
12
+
13
+ describe "constructor" do
14
+
15
+ subject { connection }
16
+
17
+ it "creates a telnet instance with the provided host and port" do
18
+ expect(Net::Telnet).to receive(:new).with(hash_including("Host" => host, "Port" => port))
19
+
20
+ subject
21
+ end
22
+
23
+ context "when a connection timeout is provided" do
24
+
25
+ let(:timeout_in_seconds) { 8 }
26
+ let(:additional_args) { { timeout_in_seconds: timeout_in_seconds } }
27
+
28
+ it "creates a telnet instance with the provided timeout in seconds" do
29
+ expect(Net::Telnet).to receive(:new).with(hash_including("Timeout" => timeout_in_seconds))
30
+
31
+ subject
32
+ end
33
+
34
+ end
35
+
36
+ context "when a connection timeout is not provided" do
37
+
38
+ let(:additional_args) { {} }
39
+
40
+ it "defaults the timeout to 5 seconds" do
41
+ expect(Net::Telnet).to receive(:new).with(hash_including("Timeout" => 5))
42
+
43
+ subject
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+
50
+ describe "#execute" do
51
+
52
+ let(:command) { "some command" }
53
+
54
+ subject { connection.execute(command) }
55
+
56
+ it "sends the provided command string to the underlying telnet instance" do
57
+ expect(telnet).to receive(:cmd).with(hash_including("String" => command))
58
+
59
+ subject
60
+ end
61
+
62
+ it "concludes awaiting output when END is observed in the stream" do
63
+ expect(telnet).to receive(:cmd).with(hash_including("Match" => /^END/))
64
+
65
+ subject
66
+ end
67
+
68
+ it "returns the result of the command" do
69
+ allow(telnet).to receive(:cmd).and_return("some command result")
70
+
71
+ expect(subject).to eql("some command result")
72
+ end
73
+
74
+ end
75
+
76
+ describe "#close" do
77
+
78
+ subject { connection.close }
79
+
80
+ it "closes the underlying telnet instance" do
81
+ expect(telnet).to receive(:close)
82
+
83
+ subject
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,109 @@
1
+ describe McDump::Telnet::Session do
2
+
3
+ let(:connection_args) { { host: "some.host", port: 12345 } }
4
+ let(:connection) { instance_double(McDump::Telnet::Connection) }
5
+
6
+ let(:session) { described_class.new(connection_args) }
7
+
8
+ before(:example) { allow(McDump::Telnet::Connection).to receive(:new).and_return(connection) }
9
+
10
+ describe "::open" do
11
+
12
+ let(:open_block_result) { "some open block result"}
13
+ let(:open_block) { lambda { |session| open_block_result } }
14
+ let(:session) { instance_double(described_class, close: nil) }
15
+
16
+ subject { described_class.open(connection_args, &open_block) }
17
+
18
+ before(:example) { allow(described_class).to receive(:new).and_return(session) }
19
+
20
+ it "creates a session with the provided connection settings" do
21
+ expect(described_class).to receive(:new).with(connection_args)
22
+
23
+ subject
24
+ end
25
+
26
+ it "invokes the provided block with the created session" do
27
+ expect(open_block).to receive(:call).with(session)
28
+
29
+ subject
30
+ end
31
+
32
+ it "closes the created session" do
33
+ expect(session).to receive(:close)
34
+
35
+ subject
36
+ end
37
+
38
+ it "returns the result of the block" do
39
+ expect(subject).to eql(open_block_result)
40
+ end
41
+
42
+ end
43
+
44
+ describe "constructor" do
45
+
46
+ subject { session }
47
+
48
+ it "opens a connection using the provided connection settings" do
49
+ expect(McDump::Telnet::Connection).to receive(:new).with(connection_args)
50
+
51
+ subject
52
+ end
53
+
54
+ end
55
+
56
+ describe "#stats" do
57
+
58
+ subject { session.stats }
59
+
60
+ it "executes a command on the connection to retrieve the stats for items" do
61
+ expect(connection).to receive(:execute).with("stats items")
62
+
63
+ subject
64
+ end
65
+
66
+ it "returns the commands response" do
67
+ response = (1..3).map { |i| "STAT line #{i}" }
68
+ allow(connection).to receive(:execute).and_return(response)
69
+
70
+ expect(subject).to eql(response)
71
+ end
72
+
73
+ end
74
+
75
+ describe "#items" do
76
+
77
+ let(:id) { 12 }
78
+ let(:number) { 987 }
79
+
80
+ subject { session.items(id, number) }
81
+
82
+ it "executes a command on the connection showing the number of items matching the id" do
83
+ expect(connection).to receive(:execute).with("stats cachedump #{id} #{number}")
84
+
85
+ subject
86
+ end
87
+
88
+ it "returns the commands response" do
89
+ response = (1..3).map { |i| "ITEM line #{i}" }
90
+ allow(connection).to receive(:execute).and_return(response)
91
+
92
+ expect(subject).to eql(response)
93
+ end
94
+
95
+ end
96
+
97
+ describe "#close" do
98
+
99
+ subject { session.close }
100
+
101
+ it "closes the telnet connection that was made when the session was created" do
102
+ expect(connection).to receive(:close)
103
+
104
+ subject
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -0,0 +1,43 @@
1
+ describe McDump do
2
+
3
+ describe "::server" do
4
+
5
+ let(:connection_args) { { host: "some.host", port: 12345 } }
6
+ let(:items) { (1..3).map { instance_double(McDump::Memcached::Item) } }
7
+ let(:server) { instance_double(McDump::Memcached::Server, items: items) }
8
+ let(:report) { instance_double(McDump::Report, dump: nil) }
9
+
10
+ subject { described_class.server(connection_args) }
11
+
12
+ before(:example) do
13
+ allow(McDump::Memcached::Server).to receive(:new).and_return(server)
14
+ allow(McDump::Report).to receive(:new).and_return(report)
15
+ end
16
+
17
+ it "creates a server" do
18
+ expect(McDump::Memcached::Server).to receive(:new).with(connection_args)
19
+
20
+ subject
21
+ end
22
+
23
+ it "retrieves all items from the server" do
24
+ expect(server).to receive(:items)
25
+
26
+ subject
27
+ end
28
+
29
+ it "creates a report containing the items" do
30
+ expect(McDump::Report).to receive(:new).with(items)
31
+
32
+ subject
33
+ end
34
+
35
+ it "dumps the contents of the report" do
36
+ expect(report).to receive(:dump)
37
+
38
+ subject
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,18 @@
1
+ require 'bundler'
2
+ Bundler.require(:development)
3
+
4
+ CodeClimate::TestReporter.start
5
+
6
+ SimpleCov.start do
7
+ coverage_dir "tmp/coverage"
8
+
9
+ add_filter "/spec/"
10
+
11
+ minimum_coverage 100
12
+ refuse_coverage_drop
13
+ end if ENV["coverage"]
14
+
15
+ require 'rake/tasklib'
16
+
17
+ require_relative '../lib/mc_dump'
18
+ require_relative '../lib/mc_dump/rake/task'
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mc_dump
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Ueckerman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '10.4'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '10.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: travis-lint
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: metric_fu
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '4.12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '4.12'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: coderay
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '0.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '0.10'
97
+ - !ruby/object:Gem::Dependency
98
+ name: codeclimate-test-reporter
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '0.4'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '0.4'
111
+ description: Dumps key values pairs within a memcached instance. Useful for verification
112
+ of cached content.
113
+ email: matthew.ueckerman@myob.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ./lib/mc_dump.rb
119
+ - ./lib/mc_dump/memcached/item.rb
120
+ - ./lib/mc_dump/memcached/server.rb
121
+ - ./lib/mc_dump/memcached/stat.rb
122
+ - ./lib/mc_dump/rake/task.rb
123
+ - ./lib/mc_dump/report.rb
124
+ - ./lib/mc_dump/telnet/connection.rb
125
+ - ./lib/mc_dump/telnet/session.rb
126
+ - ./lib/mc_dump/version.rb
127
+ - ./spec/lib/mc_dump/memcached/item_spec.rb
128
+ - ./spec/lib/mc_dump/memcached/server_spec.rb
129
+ - ./spec/lib/mc_dump/memcached/stat_spec.rb
130
+ - ./spec/lib/mc_dump/rake/task_spec.rb
131
+ - ./spec/lib/mc_dump/report_spec.rb
132
+ - ./spec/lib/mc_dump/telnet/connection_spec.rb
133
+ - ./spec/lib/mc_dump/telnet/session_spec.rb
134
+ - ./spec/lib/mc_dump_spec.rb
135
+ - ./spec/spec_helper.rb
136
+ homepage: http://github.com/MYOB-Technology/mc_dump
137
+ licenses:
138
+ - MIT
139
+ metadata: {}
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ! '>='
147
+ - !ruby/object:Gem::Version
148
+ version: 1.9.3
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ! '>='
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 2.4.8
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: Dumps the contents of a memcached instance
160
+ test_files:
161
+ - ./spec/lib/mc_dump/memcached/item_spec.rb
162
+ - ./spec/lib/mc_dump/memcached/server_spec.rb
163
+ - ./spec/lib/mc_dump/memcached/stat_spec.rb
164
+ - ./spec/lib/mc_dump/rake/task_spec.rb
165
+ - ./spec/lib/mc_dump/report_spec.rb
166
+ - ./spec/lib/mc_dump/telnet/connection_spec.rb
167
+ - ./spec/lib/mc_dump/telnet/session_spec.rb
168
+ - ./spec/lib/mc_dump_spec.rb
169
+ - ./spec/spec_helper.rb