myer 0.0.1

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