myer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +9 -0
  5. data/Gemfile +2 -0
  6. data/LICENSE +21 -0
  7. data/README.md +5 -0
  8. data/Rakefile +44 -0
  9. data/bin/myer +198 -0
  10. data/features/myer.feature +8 -0
  11. data/features/step_definitions/myer_steps.rb +6 -0
  12. data/features/support/env.rb +15 -0
  13. data/lib/myer.rb +25 -0
  14. data/lib/myer/admin_cli_controller.rb +70 -0
  15. data/lib/myer/api.rb +104 -0
  16. data/lib/myer/cli_controller.rb +204 -0
  17. data/lib/myer/config.rb +86 -0
  18. data/lib/myer/content.rb +92 -0
  19. data/lib/myer/crypto.rb +40 -0
  20. data/lib/myer/exceptions.rb +7 -0
  21. data/lib/myer/plot.rb +11 -0
  22. data/lib/myer/proc_net_parser.rb +11 -0
  23. data/lib/myer/test_cli_controller.rb +52 -0
  24. data/lib/myer/ticket.rb +3 -0
  25. data/lib/myer/ticket_store.rb +61 -0
  26. data/lib/myer/version.rb +3 -0
  27. data/myer.gemspec +26 -0
  28. data/myer.rdoc +5 -0
  29. data/scripts/plot-helper.py +32 -0
  30. data/spec/admin_cli_controller_spec.rb +128 -0
  31. data/spec/api_spec.rb +136 -0
  32. data/spec/cli_controller_spec.rb +368 -0
  33. data/spec/config_spec.rb +116 -0
  34. data/spec/content_spec.rb +103 -0
  35. data/spec/crypto_spec.rb +37 -0
  36. data/spec/data/myer-full.config +9 -0
  37. data/spec/data/myer-multiple.config +14 -0
  38. data/spec/data/myer.config +6 -0
  39. data/spec/data/plot-data.csv +31 -0
  40. data/spec/data/secret-ticket-12345678.json +1 -0
  41. data/spec/data/secret-ticket-987654321.json +1 -0
  42. data/spec/plot_spec.rb +9 -0
  43. data/spec/proc_net_parser_spec.rb +15 -0
  44. data/spec/shared_examples_for_config.rb +47 -0
  45. data/spec/spec_helper.rb +14 -0
  46. data/spec/test_cli_controller_spec.rb +72 -0
  47. data/spec/ticket_store_spec.rb +86 -0
  48. data/test/default_test.rb +14 -0
  49. data/test/test_helper.rb +9 -0
  50. 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
@@ -0,0 +1,3 @@
1
+ class Ticket
2
+ attr_accessor :server, :name, :bucket_id, :key
3
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module Myer
2
+ VERSION = '0.0.1'
3
+ end
@@ -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
@@ -0,0 +1,5 @@
1
+ = myer
2
+
3
+ Generate this with
4
+ myer rdoc
5
+ After you have described your command line interface
@@ -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
@@ -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