myer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/README.md +5 -0
- data/Rakefile +44 -0
- data/bin/myer +198 -0
- data/features/myer.feature +8 -0
- data/features/step_definitions/myer_steps.rb +6 -0
- data/features/support/env.rb +15 -0
- data/lib/myer.rb +25 -0
- data/lib/myer/admin_cli_controller.rb +70 -0
- data/lib/myer/api.rb +104 -0
- data/lib/myer/cli_controller.rb +204 -0
- data/lib/myer/config.rb +86 -0
- data/lib/myer/content.rb +92 -0
- data/lib/myer/crypto.rb +40 -0
- data/lib/myer/exceptions.rb +7 -0
- data/lib/myer/plot.rb +11 -0
- data/lib/myer/proc_net_parser.rb +11 -0
- data/lib/myer/test_cli_controller.rb +52 -0
- data/lib/myer/ticket.rb +3 -0
- data/lib/myer/ticket_store.rb +61 -0
- data/lib/myer/version.rb +3 -0
- data/myer.gemspec +26 -0
- data/myer.rdoc +5 -0
- data/scripts/plot-helper.py +32 -0
- data/spec/admin_cli_controller_spec.rb +128 -0
- data/spec/api_spec.rb +136 -0
- data/spec/cli_controller_spec.rb +368 -0
- data/spec/config_spec.rb +116 -0
- data/spec/content_spec.rb +103 -0
- data/spec/crypto_spec.rb +37 -0
- data/spec/data/myer-full.config +9 -0
- data/spec/data/myer-multiple.config +14 -0
- data/spec/data/myer.config +6 -0
- data/spec/data/plot-data.csv +31 -0
- data/spec/data/secret-ticket-12345678.json +1 -0
- data/spec/data/secret-ticket-987654321.json +1 -0
- data/spec/plot_spec.rb +9 -0
- data/spec/proc_net_parser_spec.rb +15 -0
- data/spec/shared_examples_for_config.rb +47 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/test_cli_controller_spec.rb +72 -0
- data/spec/ticket_store_spec.rb +86 -0
- data/test/default_test.rb +14 -0
- data/test/test_helper.rb +9 -0
- metadata +220 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
class TestCliController
|
2
|
+
attr_accessor :out
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@out = STDOUT
|
6
|
+
end
|
7
|
+
|
8
|
+
def local(executable)
|
9
|
+
Dir.mktmpdir do |dir|
|
10
|
+
pin = "xyz"
|
11
|
+
|
12
|
+
cmd = "#{executable} -pin=#{pin} -logfile=/dev/null #{dir}/data"
|
13
|
+
io = IO.popen(cmd)
|
14
|
+
|
15
|
+
sleep(1)
|
16
|
+
|
17
|
+
begin
|
18
|
+
full("localhost", pin)
|
19
|
+
ensure
|
20
|
+
Process.kill("INT", io.pid)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def full(server, pid)
|
26
|
+
admin_api = MySelf::Api.new
|
27
|
+
admin_api.server = server
|
28
|
+
|
29
|
+
admin_api.user, admin_api.password = admin_api.admin_register(pid)
|
30
|
+
|
31
|
+
token = admin_api.create_token
|
32
|
+
|
33
|
+
user_api = MySelf::Api.new
|
34
|
+
user_api.server = server
|
35
|
+
|
36
|
+
user_api.user, user_api.password = admin_api.register(token)
|
37
|
+
|
38
|
+
bucket = user_api.create_bucket
|
39
|
+
|
40
|
+
content = "octopus"
|
41
|
+
|
42
|
+
item = user_api.create_item(bucket, content)
|
43
|
+
|
44
|
+
items = user_api.get_items(bucket)
|
45
|
+
|
46
|
+
if items.size == 1 && items[0].id == item && items[0].content == content
|
47
|
+
@out.puts "Full acceptance test passed"
|
48
|
+
else
|
49
|
+
@out.puts "Full acceptance test failed"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/myer/ticket.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
class TicketStore
|
2
|
+
def initialize(ticket_dir)
|
3
|
+
@ticket_dir = ticket_dir
|
4
|
+
end
|
5
|
+
|
6
|
+
def ticket_file_name(bucket_id)
|
7
|
+
"secret-ticket-#{bucket_id}.json"
|
8
|
+
end
|
9
|
+
|
10
|
+
def ticket_path(ticket)
|
11
|
+
File.join(@ticket_dir, ticket_file_name(ticket.bucket_id))
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_ticket(bucket_id)
|
15
|
+
ticket = Ticket.new
|
16
|
+
ticket.bucket_id = bucket_id
|
17
|
+
begin
|
18
|
+
ticket_content = File.read(ticket_path(ticket))
|
19
|
+
rescue Errno::ENOENT
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
json = JSON.parse(ticket_content)
|
23
|
+
if json["bucket_id"] != bucket_id
|
24
|
+
raise "Invalid ticket #{ticket_path(ticket)}. File name doesn't match bucket id"
|
25
|
+
end
|
26
|
+
ticket.server = json["server"]
|
27
|
+
ticket.key = json["key"]
|
28
|
+
ticket.name = json["name"]
|
29
|
+
ticket
|
30
|
+
end
|
31
|
+
|
32
|
+
def load_ticket_from_file(ticket_path)
|
33
|
+
json = JSON.parse(File.read(ticket_path))
|
34
|
+
ticket = Ticket.new
|
35
|
+
ticket.server = json["server"]
|
36
|
+
ticket.bucket_id = json["bucket_id"]
|
37
|
+
ticket.key = json["key"]
|
38
|
+
ticket.name = json["name"]
|
39
|
+
ticket
|
40
|
+
end
|
41
|
+
|
42
|
+
def tickets_per_server
|
43
|
+
tickets = {}
|
44
|
+
Dir.glob("#{@ticket_dir}/secret-ticket-*.json").sort.each do |path|
|
45
|
+
ticket = load_ticket_from_file(path)
|
46
|
+
tickets[ticket.server] ||= []
|
47
|
+
tickets[ticket.server].push(ticket)
|
48
|
+
end
|
49
|
+
tickets
|
50
|
+
end
|
51
|
+
|
52
|
+
def save_ticket(ticket)
|
53
|
+
json = { "server" => ticket.server, "name" => ticket.name,
|
54
|
+
"bucket_id" => ticket.bucket_id,
|
55
|
+
"key" => ticket.key }
|
56
|
+
File.open(ticket_path(ticket), "w", 0600) do |f|
|
57
|
+
f.write(JSON.generate(json))
|
58
|
+
f.puts
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/myer/version.rb
ADDED
data/myer.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Ensure we require the local version and not one we might have installed already
|
2
|
+
require File.join([File.dirname(__FILE__),'lib','myer','version.rb'])
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
s.name = 'myer'
|
5
|
+
s.version = Myer::VERSION
|
6
|
+
s.author = 'Cornelius Schumacher'
|
7
|
+
s.email = 'schumacher@kde.org'
|
8
|
+
s.homepage = 'https://github.com/cornelius/myer'
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.summary = 'Command line client for Project MySelf'
|
11
|
+
s.license = 'MIT'
|
12
|
+
s.files = `git ls-files`.split("
|
13
|
+
")
|
14
|
+
s.require_paths << 'lib'
|
15
|
+
s.bindir = 'bin'
|
16
|
+
s.executables << 'myer'
|
17
|
+
s.add_development_dependency('rake')
|
18
|
+
s.add_development_dependency('rdoc')
|
19
|
+
s.add_development_dependency('aruba')
|
20
|
+
s.add_development_dependency('rspec')
|
21
|
+
s.add_development_dependency('webmock')
|
22
|
+
s.add_development_dependency('given_filesystem')
|
23
|
+
s.add_development_dependency('codeclimate-test-reporter')
|
24
|
+
s.add_runtime_dependency('gli','2.12.2')
|
25
|
+
s.add_runtime_dependency('xdg')
|
26
|
+
end
|
data/myer.rdoc
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/python
|
2
|
+
|
3
|
+
import sys
|
4
|
+
import numpy as np
|
5
|
+
import matplotlib.pyplot as plt
|
6
|
+
import matplotlib.dates as mdates
|
7
|
+
|
8
|
+
if len(sys.argv) != 2:
|
9
|
+
print "Usage: plot-data.py <csv-file>"
|
10
|
+
sys.exit(1)
|
11
|
+
|
12
|
+
csv_file = sys.argv[1]
|
13
|
+
|
14
|
+
days, values = np.loadtxt(csv_file, unpack=True, delimiter=",",
|
15
|
+
converters={ 0: mdates.strpdate2num('%Y-%m-%d')})
|
16
|
+
|
17
|
+
fmt = mdates.DateFormatter('%Y-%m-%d')
|
18
|
+
loc = mdates.WeekdayLocator(byweekday=mdates.MONDAY)
|
19
|
+
|
20
|
+
ax = plt.axes()
|
21
|
+
ax.xaxis.set_major_formatter(fmt)
|
22
|
+
ax.xaxis.set_major_locator(loc)
|
23
|
+
|
24
|
+
plt.bar(days, values, align="center", linewidth=0, width=0.6, color="green",
|
25
|
+
antialiased=True)
|
26
|
+
|
27
|
+
plt.grid(True)
|
28
|
+
|
29
|
+
fig = plt.figure(1)
|
30
|
+
fig.autofmt_xdate()
|
31
|
+
|
32
|
+
plt.show()
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require_relative "spec_helper.rb"
|
2
|
+
|
3
|
+
require "shared_examples_for_config"
|
4
|
+
|
5
|
+
include GivenFilesystemSpecHelpers
|
6
|
+
|
7
|
+
describe AdminCliController do
|
8
|
+
use_given_filesystem
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@controller = AdminCliController.new
|
12
|
+
end
|
13
|
+
|
14
|
+
it_behaves_like "config"
|
15
|
+
|
16
|
+
describe "#api" do
|
17
|
+
it "provides admin API" do
|
18
|
+
@controller.config_dir = given_directory do
|
19
|
+
given_file("myer.config", from: "myer-full.config")
|
20
|
+
end
|
21
|
+
@controller.read_config
|
22
|
+
api = @controller.api
|
23
|
+
|
24
|
+
expect(api.user).to eq "abc"
|
25
|
+
expect(api.password).to eq "def"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#register" do
|
30
|
+
it "registers admin client" do
|
31
|
+
@controller.config_dir = given_directory
|
32
|
+
|
33
|
+
expect_any_instance_of(MySelf::Api).to receive(:admin_register).with("1234")
|
34
|
+
.and_return(["181504088", "683271947"])
|
35
|
+
|
36
|
+
@controller.register "example.com", "1234"
|
37
|
+
|
38
|
+
expect(@controller.admin_id).to eq "181504088"
|
39
|
+
expect(@controller.admin_password).to eq "683271947"
|
40
|
+
|
41
|
+
expect(File.read(File.join(@controller.config_dir, "myer.config"))).to eq (<<EOT
|
42
|
+
---
|
43
|
+
default_server: example.com
|
44
|
+
servers:
|
45
|
+
example.com:
|
46
|
+
admin_id: '181504088'
|
47
|
+
admin_password: '683271947'
|
48
|
+
EOT
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#list_buckets" do
|
54
|
+
it "lists existing buckets" do
|
55
|
+
expect_any_instance_of(MySelf::Api).to receive(:admin_list_buckets)
|
56
|
+
.and_return(["12345678","309029630"])
|
57
|
+
|
58
|
+
@controller.config_dir = given_directory do
|
59
|
+
given_file("myer.config")
|
60
|
+
given_file("secret-ticket-12345678.json")
|
61
|
+
end
|
62
|
+
|
63
|
+
out = StringIO.new
|
64
|
+
@controller.out = out
|
65
|
+
|
66
|
+
@controller.list_buckets
|
67
|
+
|
68
|
+
expect(out.string).to eq(<<EOT
|
69
|
+
12345678: Test Data
|
70
|
+
309029630: <no ticket>
|
71
|
+
EOT
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#delete_bucket" do
|
77
|
+
it "deletes bucket" do
|
78
|
+
@controller.config_dir = given_directory do
|
79
|
+
given_file("myer.config")
|
80
|
+
end
|
81
|
+
|
82
|
+
bucket_id = "123"
|
83
|
+
|
84
|
+
expect_any_instance_of(MySelf::Api).to receive(:admin_delete_bucket)
|
85
|
+
.with(bucket_id)
|
86
|
+
|
87
|
+
@controller.delete_bucket(bucket_id)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#status" do
|
92
|
+
it "gives out status" do
|
93
|
+
@controller.config_dir = given_directory do
|
94
|
+
given_file("myer.config")
|
95
|
+
end
|
96
|
+
|
97
|
+
out = double
|
98
|
+
@controller.out = out
|
99
|
+
|
100
|
+
expect(out).to receive(:puts).with(/example.org/)
|
101
|
+
expect(out).to receive(:puts).with(/987654321/)
|
102
|
+
|
103
|
+
@controller.status
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "register_user" do
|
108
|
+
it "registers as user client" do
|
109
|
+
@controller.config_dir = given_directory do
|
110
|
+
given_file("myer.config")
|
111
|
+
end
|
112
|
+
|
113
|
+
token = "1800927539516"
|
114
|
+
expect_any_instance_of(MySelf::Api).to receive(:create_token)
|
115
|
+
.and_return(token)
|
116
|
+
expect_any_instance_of(MySelf::Api).to receive(:register).with(token)
|
117
|
+
.and_return(["123","456"])
|
118
|
+
|
119
|
+
expect(@controller.user_id).to be(nil)
|
120
|
+
expect(@controller.user_password).to be(nil)
|
121
|
+
|
122
|
+
@controller.register_user
|
123
|
+
|
124
|
+
expect(@controller.user_id).to eq "123"
|
125
|
+
expect(@controller.user_password).to eq "456"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/spec/api_spec.rb
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe MySelf::Api do
|
4
|
+
before(:each) do
|
5
|
+
@api = MySelf::Api.new
|
6
|
+
@api.server = "example.org"
|
7
|
+
@api.user = "abc"
|
8
|
+
@api.password = "def"
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#admin_register" do
|
12
|
+
it "registers admin client" do
|
13
|
+
pin = "4444"
|
14
|
+
expected_id = "12"
|
15
|
+
expected_password = "s3cr3t"
|
16
|
+
|
17
|
+
body = "{\"admin_id\":\"#{expected_id}\",\"password\":\"#{expected_password}\"}"
|
18
|
+
stub_request(:post, "http://example.org:4735/admin/register/#{pin}").
|
19
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
20
|
+
to_return(:status => 200, :body => body, :headers => {})
|
21
|
+
|
22
|
+
id, password = @api.admin_register(pin)
|
23
|
+
|
24
|
+
expect(id).to eq expected_id
|
25
|
+
expect(password).to eq expected_password
|
26
|
+
end
|
27
|
+
|
28
|
+
it "fails when admin client is already registered" do
|
29
|
+
stub_request(:post, "http://example.org:4735/admin/register/1234").
|
30
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
31
|
+
to_return(:status => 400, :body => 'Client is already registered', :headers => {})
|
32
|
+
|
33
|
+
expect {
|
34
|
+
@api.admin_register("1234")
|
35
|
+
}.to raise_error
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#admin_list_buckets" do
|
40
|
+
it "returns buckets" do
|
41
|
+
buckets = [ "a", "b" ]
|
42
|
+
|
43
|
+
body = "[" + buckets.map{ |b| "\"#{b}\"" }.join(",") + "]"
|
44
|
+
stub_request(:get, "http://abc:def@example.org:4735/admin/buckets").
|
45
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
46
|
+
to_return(:status => 200, :body => body, :headers => {})
|
47
|
+
|
48
|
+
expect(@api.admin_list_buckets).to eq buckets
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#admin_delete_bucket" do
|
53
|
+
it "deletes bucket" do
|
54
|
+
stub_request(:delete, "http://abc:def@example.org:4735/admin/buckets/123").
|
55
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
56
|
+
to_return(:status => 200, :body => "", :headers => {})
|
57
|
+
|
58
|
+
@api.admin_delete_bucket("123")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#create_token" do
|
63
|
+
it "returns token" do
|
64
|
+
token = "xxxxx"
|
65
|
+
|
66
|
+
body = "{\"token\":\"#{token}\"}"
|
67
|
+
stub_request(:post, "http://abc:def@example.org:4735/tokens").
|
68
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
69
|
+
to_return(:status => 200, :body => body, :headers => {})
|
70
|
+
|
71
|
+
expect(@api.create_token).to eq token
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#register" do
|
76
|
+
it "registers client" do
|
77
|
+
token = "x"
|
78
|
+
|
79
|
+
stub_request(:post, "http://example.org:4735/register/#{token}").
|
80
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
81
|
+
to_return(:status => 200, :body => '{"user_id":"157610723","user_password":"626078090"}', :headers => {})
|
82
|
+
|
83
|
+
user, password = @api.register(token)
|
84
|
+
|
85
|
+
expect(user).to eq "157610723"
|
86
|
+
expect(password).to eq "626078090"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#create_bucket" do
|
91
|
+
it "creates new bucket" do
|
92
|
+
stub_request(:post, "http://abc:def@example.org:4735/data").
|
93
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
94
|
+
to_return(:status => 200, :body => '{"bucket_id":"150479372"}', :headers => {})
|
95
|
+
|
96
|
+
expect(@api.create_bucket).to eq "150479372"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#create_item" do
|
101
|
+
it "creates item" do
|
102
|
+
bucket_id = "123"
|
103
|
+
content = "my data"
|
104
|
+
|
105
|
+
stub_request(:post, "http://abc:def@example.org:4735/data/#{bucket_id}").
|
106
|
+
with(:body => content, :headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
107
|
+
to_return(:status => 200, :body => '{"item_id":"504885608","parent_id":"772806166"}', :headers => {})
|
108
|
+
|
109
|
+
expect(@api.create_item(bucket_id, content)).to eq "504885608"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "#get_items" do
|
114
|
+
it "reads raw items" do
|
115
|
+
bucket_id = "987654321"
|
116
|
+
stub_request(:get, "http://abc:def@example.org:4735/data/#{bucket_id}").
|
117
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
118
|
+
to_return(:status => 200, :body => '[{"item_id":"263800370","parent_id":"271086077","content":"more data"},{"item_id":"271086077","parent_id":"","content":"my data"}]', :headers => {})
|
119
|
+
|
120
|
+
expected_items = [
|
121
|
+
OpenStruct.new(id: "271086077", content: "my data"),
|
122
|
+
OpenStruct.new(id: "263800370", content: "more data")
|
123
|
+
]
|
124
|
+
expect(@api.get_items(bucket_id)).to eq expected_items
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "#ping" do
|
129
|
+
it "pongs" do
|
130
|
+
stub_request(:get, "http://abc:def@example.org:4735/ping").
|
131
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
|
132
|
+
to_return(:status => 200, :body => "{\"ping\":\"pong\"}", :headers => {})
|
133
|
+
@api.ping
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|