ruby_nos 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.
@@ -0,0 +1,47 @@
1
+ require "spec_helper"
2
+
3
+ describe "RubyNos::Message" do
4
+
5
+ describe "create_message" do
6
+ let(:params) {{:from => "Alice", :to => "Bob"}}
7
+ let(:message) {Message.new(params)}
8
+ it "creates a message with all the specified fields" do
9
+ expect(message.from).to eq("Alice")
10
+ expect(message.to).to eq("Bob")
11
+ end
12
+
13
+ context "using the keys of the message" do
14
+ let(:message) {Message.new(v: "1.0", fr: "someone")}
15
+ it "allows to put the value in the correct attribute" do
16
+ expect(message.version).to eq("1.0")
17
+ expect(message.from).to eq("someone")
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "#serialize" do
23
+ let(:message) {Message.new}
24
+ it "returns the serialized message with the keys that have a value" do
25
+ expect(message.serialize.keys).to eq([:v, :hp, :ts, :rx, :sg])
26
+ end
27
+
28
+ it "adds a signature to each message" do
29
+ expect_any_instance_of(SignatureGenerator).to receive(:generate_signature)
30
+ message.serialize
31
+ end
32
+
33
+ it "adds a timestamp to each message" do
34
+ expect(Formatter).to receive(:timestamp)
35
+ message.serialize
36
+ end
37
+
38
+ context "with all the fields" do
39
+ let(:params) {{:from => "Alice", :to => "Bob", :type => "PRS", :data => {a: "something"}}}
40
+ let(:message) {Message.new(params)}
41
+
42
+ it "returns the serialized message with all the keys" do
43
+ expect(message.serialize.keys).to eq([:v, :ty, :fr, :to, :hp, :ts, :rx, :dt, :sg])
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,104 @@
1
+ require "spec_helper"
2
+ require "json"
3
+
4
+ describe RubyNos::Processor do
5
+ subject{Processor.new(agent)}
6
+ let(:agent) {Agent.new(:uuid => agent_uuid)}
7
+ let(:json_message) {message.to_json}
8
+ let(:udp_socket) {double("UDPSocket", :receptor_address => [12345, "localhost"])}
9
+ let(:cloud) {double("Cloud", :uuid => cloud_uuid, list: list)}
10
+ let(:list) {double("list")}
11
+ let(:agent_uuid) {SecureRandom.uuid}
12
+ let(:cloud_uuid) {SecureRandom.uuid}
13
+ let(:received_agent_uuid) {agent_uuid.gsub("-", "")}
14
+ let(:another_agent_uuid) {SecureRandom.uuid}
15
+ let(:another_agent_uuid_received) {another_agent_uuid.gsub("-", "")}
16
+ let(:received_cloud_uuid) {cloud_uuid.gsub("-", "")}
17
+ let(:basic_message_to_agent) {{from: "AGT:#{another_agent_uuid_received}", to: "AGT:#{received_agent_uuid}", timestamp: "something"}}
18
+ let(:basic_message_to_cloud) {{from: "AGT:#{another_agent_uuid_received}", to: "CLD:#{received_cloud_uuid}", timestamp: "something"}}
19
+ let(:cloud_info) {{agent_uuid: another_agent_uuid, info: nil, timestamp: "something"}}
20
+
21
+ before(:each) do
22
+ allow_any_instance_of(UDPSender).to receive(:send).and_return(nil)
23
+ agent.udp_rx = udp_socket
24
+ agent.cloud = cloud
25
+ end
26
+
27
+ describe "#process_message" do
28
+ let(:message){Message.new({type: "PIN"}.merge(basic_message_to_agent)).serialize}
29
+ it "checks the signature of the messages" do
30
+ expect_any_instance_of(SignatureGenerator).to receive(:valid_signature?)
31
+ subject.process_message(json_message)
32
+ end
33
+
34
+ context "PING message arrives" do
35
+ let(:message){Message.new({type: "PIN"}.merge(basic_message_to_agent)).serialize}
36
+ it "it sends a PON" do
37
+ expect(cloud).to receive(:update).with(cloud_info)
38
+ expect(agent).to receive(:send_message).with({:type => "PON"})
39
+ subject.process_message(json_message)
40
+ end
41
+ end
42
+
43
+ context "PONG messages arrives" do
44
+ let(:message){Message.new({type: "PON"}.merge(basic_message_to_cloud)).serialize}
45
+ it "it updates the cloud list" do
46
+ expect(cloud).to receive(:update).with(cloud_info)
47
+ subject.process_message(json_message)
48
+ end
49
+ end
50
+
51
+ context "Discovery message arrives" do
52
+ let(:message){Message.new({type: "DSC"}.merge(basic_message_to_cloud)).serialize}
53
+ it "it updates the cloud if the user is not on the list and sends a PRS" do
54
+ expect(list).to receive(:is_on_the_list?).with(another_agent_uuid)
55
+ expect(cloud).to receive(:update).with(cloud_info)
56
+ expect(agent).to receive(:send_message).with({:type => "PRS"})
57
+ subject.process_message(json_message)
58
+ end
59
+ end
60
+
61
+ context "#Presence message arrives" do
62
+ let(:message) {Message.new({type: "PRS", data: {:ap => "example_app"}}.merge(basic_message_to_cloud)).serialize}
63
+ let(:cloud_info_with_endpoints) {{agent_uuid: another_agent_uuid, info: {:ap => "example_app"}, timestamp: "something"}}
64
+ it "store the information of the agent and update the list" do
65
+ expect(cloud).to receive(:update).with(cloud_info_with_endpoints)
66
+ subject.process_message(json_message)
67
+ end
68
+
69
+ context "#present equals false" do
70
+ let(:message) {Message.new({type: "PRS", data: {:ap => "example_app", :present => 0}}.merge(basic_message_to_cloud)).serialize}
71
+ it "eliminates the agent from the cloud if present field is equal to false" do
72
+ expect(list).to receive(:eliminate).with(another_agent_uuid)
73
+ subject.process_message(json_message)
74
+ end
75
+ end
76
+ end
77
+
78
+ context "#Enquiry message arrives" do
79
+ let(:message) {Message.new({type: "ENQ"}.merge(basic_message_to_cloud)).serialize}
80
+ it "returns a QNE message" do
81
+ expect(cloud).to receive(:update).with(cloud_info)
82
+ expect(agent).to receive(:send_message).with({:type => "QNE"})
83
+ subject.process_message(json_message)
84
+ end
85
+ end
86
+
87
+ context "#Answer to an enquiry message arrives" do
88
+ let(:rest_api) {RestApi.new}
89
+ let(:endpoint_params) {{path: "/example", type: "PUBLIC", port: 5000, host: "localhost"}}
90
+ let(:message) {Message.new({type: "QNE", data: rest_api.to_hash}.merge(basic_message_to_cloud)).serialize}
91
+ let(:remote_agent) {double("remote_agent")}
92
+
93
+ before(:each) do
94
+ rest_api.add_endpoint(endpoint_params)
95
+ end
96
+
97
+ it "stores the information of the api in the remote agent" do
98
+ expect(RemoteAgent).to receive(:new).with(uuid: another_agent_uuid, timestamp: "something", rest_api: an_instance_of(RestApi)).and_return(remote_agent)
99
+ expect(cloud).to receive(:update).with(remote_agent)
100
+ subject.process_message(json_message)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+
3
+ describe "#RubyNos::RemoteAgent" do
4
+ subject{RemoteAgent.new}
5
+
6
+ describe "#add_endpoint" do
7
+ it "adds and endpoint to the list of endpoints for the remote agent" do
8
+ subject.add_endpoint({type: "UDP"})
9
+ expect(subject.endpoints.count).to eq(1)
10
+ end
11
+ end
12
+
13
+ describe "#endpoints collection" do
14
+ it "shows the endpoints as an array of hashes" do
15
+ subject.add_endpoint({type: "UDP"})
16
+ expect(subject.endpoints_collection.first.keys).to eq([:pa, :po, :st, :ty, :xp, :ho])
17
+ end
18
+ end
19
+
20
+ context "#comparing agents" do
21
+ let(:another_agent){RemoteAgent.new({timestamp: 2, endpoints: [Endpoint.new({type: "HTTP"})], rest_api: RestApi.new})}
22
+
23
+ before do
24
+ subject.endpoints = [Endpoint.new({type: "UDP"})]
25
+ subject.rest_api = RestApi.new
26
+ subject.timestamp = 1
27
+ end
28
+
29
+ describe "#same_timestamp?" do
30
+ it "compares the timestamp with another agent" do
31
+ expect(subject.same_timestamp?(subject)).to eq(true)
32
+ expect(subject.same_timestamp?(another_agent)).to eq(false)
33
+ end
34
+ end
35
+
36
+ describe "#same_endpoints?" do
37
+ it "compares the timestamp with another agent" do
38
+ expect(subject.same_endpoints?(subject)).to eq(true)
39
+ expect(subject.same_endpoints?(another_agent)).to eq(false)
40
+ end
41
+ end
42
+
43
+ context "#check API" do
44
+ before(:each) do
45
+ subject.rest_api.add_endpoint({type: "PUBLIC"})
46
+ another_agent.rest_api.add_endpoint({type: "HEALTHCHECK"})
47
+ end
48
+
49
+ describe "#same_api?" do
50
+ it "compares the timestamp with another agent" do
51
+ expect(subject.same_api?(subject)).to eq(true)
52
+ expect(subject.same_api?(another_agent)).to eq(false)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ describe "#RubyNos::RestApi" do
4
+ subject{RestApi.new}
5
+
6
+ describe "#add_endpoint" do
7
+ it "creates a new Endpoint and add it to the list of endpoints" do
8
+ subject.add_endpoint(path: "/this_path", type: "PUBLIC", port: 3000)
9
+ expect(subject.endpoints.count).to eq(1)
10
+ end
11
+ end
12
+
13
+ describe "#to_hash" do
14
+ it "returns the name of the microservices and the list of endpoints on a hash" do
15
+ expect(subject.to_hash.keys).to eq([:name, :apis])
16
+ end
17
+
18
+ it "returns the list of endpoints in an array" do
19
+ subject.add_endpoint(path: "/this_path", type: "PUBLIC", port: 3000)
20
+ expect(subject.to_hash[:apis].first[:pa]).to eq("/this_path")
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe "RubyNos#SignGenerator" do
4
+ subject{SignatureGenerator.new}
5
+ let(:message) {"Example message"}
6
+
7
+ before do
8
+ subject.key = "key"
9
+ end
10
+
11
+ describe "#generate_signature" do
12
+ it "generates a signature for a message" do
13
+ expect(subject.generate_signature(message).size).to eq(40)
14
+ end
15
+ end
16
+
17
+ describe "#valid_signature?" do
18
+ it "returns true if the signature is correct" do
19
+ digest = OpenSSL::Digest.new('sha1')
20
+ signature = OpenSSL::HMAC.hexdigest(digest, subject.key, message)
21
+ expect(subject.valid_signature?(message, signature)).to eq(true)
22
+ end
23
+
24
+ it "returns false if the signature is incorrect" do
25
+ expect(subject.valid_signature?(message, "example")).to eq(false)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ require "spec_helper"
2
+
3
+ describe RubyNos::UDPReceptor do
4
+
5
+ subject{UDPReceptor.new}
6
+
7
+ describe "#receive" do
8
+ let(:socket_tx) {UDPSocket.open}
9
+ let(:message) {"Example message"}
10
+ let(:host) {"230.31.32.33"}
11
+ let(:port) {3784}
12
+ let(:processor) {double("processor")}
13
+
14
+ before(:each) do
15
+ socket_tx.setsockopt(:IPPROTO_IP, :IP_MULTICAST_TTL, 1)
16
+ end
17
+
18
+ after(:each) do
19
+ subject.socket.close
20
+ socket_tx.close
21
+ end
22
+
23
+ it "receives messages listening to multicast address" do
24
+ allow(processor).to receive(:process_message)
25
+ expect(processor).to receive(:process_message).and_raise("Boom")
26
+ thread = subject.listen(processor)
27
+ socket_tx.send(message, 0, host, port)
28
+ expect{thread.join}.to raise_error("Boom")
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+ require 'ipaddr'
3
+ require 'json'
4
+
5
+ describe RubyNos::UDPSender do
6
+
7
+ subject{UDPSender.new}
8
+
9
+ describe "#send" do
10
+ let(:message) {{message: Message.new.serialize}}
11
+
12
+ context "multicast address by default" do
13
+ let(:host) {"230.31.32.33"}
14
+ let(:bind_addr) {"0.0.0.0"}
15
+ let(:port) {3784}
16
+ let(:socketrx) {UDPSocket.new}
17
+
18
+ before(:each) do
19
+ membership = IPAddr.new(host).hton + IPAddr.new(bind_addr).hton
20
+ socketrx.setsockopt(:IPPROTO_IP, :IP_ADD_MEMBERSHIP, membership)
21
+ socketrx.bind(bind_addr, port)
22
+ end
23
+
24
+ after(:each) do
25
+ socketrx.close
26
+ end
27
+
28
+ it "sends to group address by default" do
29
+ subject.send(message)
30
+ expect(socketrx.recvfrom(512).first). to eq(message[:message].to_json)
31
+ sleep 0.2
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+ require 'pry'
4
+ require "codeclimate-test-reporter"
5
+
6
+ ENV['RACK_ENV'] = 'test'
7
+
8
+ begin
9
+ Bundler.setup(:default, :development)
10
+ rescue Bundler::BundlerError => e
11
+ $stderr.puts e.message
12
+ $stderr.puts "Run `bundle install` to install missing gems"
13
+ exit e.status_code
14
+ end
15
+
16
+ $LOAD_PATH << File.join(File.dirname(__FILE__),'..')
17
+ CodeClimate::TestReporter.start if !!ENV['CODECLIMATE_REPO_TOKEN']
18
+ require 'config/environment'
19
+ include RubyNos
20
+
21
+ RSpec.configure do |config|
22
+ config.color = true
23
+ config.tty = true
24
+ config.formatter = :documentation # :documentation, :progress, :html, :textmate
25
+ end
26
+
27
+
28
+
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_nos
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Workshare's dev team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.4'
41
+ description: A gem to provide microservices autodiscovery to Ruby microservices.
42
+ email:
43
+ - _Development@workshare.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .travis.yml
50
+ - Gemfile
51
+ - Gemfile.lock
52
+ - LICENSE
53
+ - README.md
54
+ - Rakefile
55
+ - config/environment.rb
56
+ - lib/initializable.rb
57
+ - lib/ruby_nos.rb
58
+ - lib/ruby_nos/agent.rb
59
+ - lib/ruby_nos/aliasing.rb
60
+ - lib/ruby_nos/cloud.rb
61
+ - lib/ruby_nos/endpoint.rb
62
+ - lib/ruby_nos/formatter.rb
63
+ - lib/ruby_nos/list.rb
64
+ - lib/ruby_nos/message.rb
65
+ - lib/ruby_nos/processor.rb
66
+ - lib/ruby_nos/remote_agent.rb
67
+ - lib/ruby_nos/rest_api.rb
68
+ - lib/ruby_nos/signature_generator.rb
69
+ - lib/ruby_nos/udp_receptor.rb
70
+ - lib/ruby_nos/udp_sender.rb
71
+ - lib/ruby_nos/version.rb
72
+ - log/.gitkeep
73
+ - ruby_nos.gemspec
74
+ - spec/ruby_nos.spec.rb
75
+ - spec/ruby_nos/agent_spec.rb
76
+ - spec/ruby_nos/cloud_spec.rb
77
+ - spec/ruby_nos/endpoint_spec.rb
78
+ - spec/ruby_nos/formatter_spec.rb
79
+ - spec/ruby_nos/list_spec.rb
80
+ - spec/ruby_nos/message_spec.rb
81
+ - spec/ruby_nos/processor_spec.rb
82
+ - spec/ruby_nos/remote_agent_spec.rb
83
+ - spec/ruby_nos/rest_api_spec.rb
84
+ - spec/ruby_nos/signature_generator_spec.rb
85
+ - spec/ruby_nos/udp_receptor_spec.rb
86
+ - spec/ruby_nos/udp_sender_spec.rb
87
+ - spec/spec_helper.rb
88
+ homepage: https://github.com/worshare/ruby-nos
89
+ licenses:
90
+ - Copyright
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ! '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubyforge_project:
108
+ rubygems_version: 2.2.2
109
+ signing_key:
110
+ specification_version: 4
111
+ summary: A gem to provide microservices autodiscovery to Ruby microservices. This
112
+ gem allows a microservice to publish its existence on a cloud, store other microservices
113
+ information and public its API.
114
+ test_files:
115
+ - spec/ruby_nos.spec.rb
116
+ - spec/ruby_nos/agent_spec.rb
117
+ - spec/ruby_nos/cloud_spec.rb
118
+ - spec/ruby_nos/endpoint_spec.rb
119
+ - spec/ruby_nos/formatter_spec.rb
120
+ - spec/ruby_nos/list_spec.rb
121
+ - spec/ruby_nos/message_spec.rb
122
+ - spec/ruby_nos/processor_spec.rb
123
+ - spec/ruby_nos/remote_agent_spec.rb
124
+ - spec/ruby_nos/rest_api_spec.rb
125
+ - spec/ruby_nos/signature_generator_spec.rb
126
+ - spec/ruby_nos/udp_receptor_spec.rb
127
+ - spec/ruby_nos/udp_sender_spec.rb
128
+ - spec/spec_helper.rb
129
+ has_rdoc: