kamerling 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -13
- data/Gemfile +0 -1
- data/Gemfile.lock +64 -64
- data/README.md +18 -1
- data/Rakefile +5 -3
- data/bin/kamerling +1 -1
- data/config/reek.yml +20 -3
- data/kamerling.gemspec +16 -13
- data/lib/kamerling.rb +2 -28
- data/lib/kamerling/addr.rb +17 -3
- data/lib/kamerling/client.rb +10 -11
- data/lib/kamerling/core_extensions/main.rb +14 -14
- data/lib/kamerling/dispatch.rb +13 -0
- data/lib/kamerling/handler.rb +16 -25
- data/lib/kamerling/http_api.rb +50 -34
- data/lib/kamerling/logging.rb +36 -16
- data/lib/kamerling/mapper.rb +33 -0
- data/lib/kamerling/message.rb +50 -37
- data/lib/kamerling/migrations/2_results_received_at.rb +7 -0
- data/lib/kamerling/migrations/3_dispatches.rb +17 -0
- data/lib/kamerling/migrations/4_registrations_registered_at.rb +7 -0
- data/lib/kamerling/migrations/5_clients_type.rb +7 -0
- data/lib/kamerling/net_dispatcher.rb +12 -7
- data/lib/kamerling/project.rb +7 -3
- data/lib/kamerling/receiver.rb +38 -10
- data/lib/kamerling/registrar.rb +45 -8
- data/lib/kamerling/registration.rb +9 -10
- data/lib/kamerling/repo.rb +33 -26
- data/lib/kamerling/repos.rb +52 -45
- data/lib/kamerling/result.rb +10 -11
- data/lib/kamerling/server/http.rb +28 -21
- data/lib/kamerling/server/sock.rb +32 -24
- data/lib/kamerling/server/tcp.rb +23 -15
- data/lib/kamerling/server/udp.rb +24 -16
- data/lib/kamerling/server_runner.rb +30 -41
- data/lib/kamerling/settings.rb +28 -0
- data/lib/kamerling/task.rb +7 -7
- data/lib/kamerling/task_dispatcher.rb +31 -22
- data/lib/kamerling/uuid.rb +13 -11
- data/lib/kamerling/uuid_entity.rb +23 -9
- data/lib/kamerling/value.rb +13 -0
- data/lib/kamerling/views/clients.slim +3 -1
- data/lib/kamerling/views/project.slim +8 -4
- data/lib/kamerling/views/projects.slim +7 -1
- data/spec/kamerling/addr_spec.rb +32 -22
- data/spec/kamerling/client_spec.rb +9 -5
- data/spec/kamerling/core_extensions/main_spec.rb +18 -13
- data/spec/kamerling/dispatch_spec.rb +16 -0
- data/spec/kamerling/handler_spec.rb +24 -34
- data/spec/kamerling/http_api_spec.rb +94 -73
- data/spec/kamerling/logging_spec.rb +93 -62
- data/spec/kamerling/mapper_spec.rb +151 -0
- data/spec/kamerling/message_spec.rb +73 -49
- data/spec/kamerling/net_dispatcher_spec.rb +22 -16
- data/spec/kamerling/receiver_spec.rb +29 -19
- data/spec/kamerling/registrar_spec.rb +43 -15
- data/spec/kamerling/registration_spec.rb +17 -0
- data/spec/kamerling/repo_spec.rb +63 -47
- data/spec/kamerling/repos_spec.rb +121 -109
- data/spec/kamerling/result_spec.rb +16 -0
- data/spec/kamerling/server/http_spec.rb +19 -14
- data/spec/kamerling/server/tcp_spec.rb +41 -35
- data/spec/kamerling/server/udp_spec.rb +40 -34
- data/spec/kamerling/server_runner_spec.rb +62 -53
- data/spec/kamerling/settings_spec.rb +36 -0
- data/spec/kamerling/task_dispatcher_spec.rb +38 -15
- data/spec/kamerling/task_spec.rb +9 -5
- data/spec/kamerling/uuid_entity_spec.rb +53 -25
- data/spec/kamerling/uuid_spec.rb +19 -16
- data/spec/kamerling/value_spec.rb +21 -0
- data/spec/spec_helper.rb +3 -6
- metadata +54 -8
- data/lib/kamerling/core_extensions.rb +0 -1
@@ -0,0 +1,151 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/kamerling/addr'
|
3
|
+
require_relative '../../lib/kamerling/client'
|
4
|
+
require_relative '../../lib/kamerling/dispatch'
|
5
|
+
require_relative '../../lib/kamerling/mapper'
|
6
|
+
require_relative '../../lib/kamerling/project'
|
7
|
+
require_relative '../../lib/kamerling/registration'
|
8
|
+
require_relative '../../lib/kamerling/result'
|
9
|
+
require_relative '../../lib/kamerling/task'
|
10
|
+
|
11
|
+
module Kamerling
|
12
|
+
describe Mapper do
|
13
|
+
let(:addr) { Addr['127.0.0.1', 1979, :TCP] }
|
14
|
+
let(:client) { Client.new(addr: addr, busy: true, type: :FPGA) }
|
15
|
+
let(:project) { Project.new(name: 'project') }
|
16
|
+
let(:task) { Task.new(data: 'data', done: true, project: project) }
|
17
|
+
|
18
|
+
describe '.from_h' do
|
19
|
+
let(:repos) do
|
20
|
+
{
|
21
|
+
Client => { client.uuid => client },
|
22
|
+
Project => { project.uuid => project },
|
23
|
+
Task => { task.uuid => task },
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'builds the proper Client from the Hash representation' do
|
28
|
+
hash = {
|
29
|
+
busy: true,
|
30
|
+
host: '127.0.0.1',
|
31
|
+
port: 1979,
|
32
|
+
prot: 'TCP',
|
33
|
+
type: 'FPGA',
|
34
|
+
uuid: client.uuid,
|
35
|
+
}
|
36
|
+
Mapper.from_h(Client, hash).to_h.must_equal client.to_h
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'builds the proper Dispatch from the Hash representation' do
|
40
|
+
dispatch = Dispatch.new(addr: addr, client: client, project: project,
|
41
|
+
task: task)
|
42
|
+
hash = {
|
43
|
+
client_uuid: client.uuid,
|
44
|
+
data: 'data',
|
45
|
+
dispatched_at: any(Time),
|
46
|
+
host: '127.0.0.1',
|
47
|
+
port: 1979,
|
48
|
+
project_uuid: project.uuid,
|
49
|
+
prot: 'TCP',
|
50
|
+
task_uuid: task.uuid,
|
51
|
+
uuid: dispatch.uuid,
|
52
|
+
}
|
53
|
+
mapped = Mapper.from_h(Dispatch, hash, repos: repos)
|
54
|
+
mapped.to_h.must_equal dispatch.to_h
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'builds the proper Project from the Hash representation' do
|
58
|
+
hash = { name: 'project', uuid: project.uuid }
|
59
|
+
Mapper.from_h(Project, hash).to_h.must_equal project.to_h
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'builds the proper Registration from the Hash representation' do
|
63
|
+
reg = Registration.new(addr: addr, client: client, project: project)
|
64
|
+
hash = {
|
65
|
+
client_uuid: client.uuid,
|
66
|
+
host: '127.0.0.1',
|
67
|
+
port: 1979,
|
68
|
+
project_uuid: project.uuid,
|
69
|
+
prot: 'TCP',
|
70
|
+
registered_at: any(Time),
|
71
|
+
uuid: reg.uuid,
|
72
|
+
}
|
73
|
+
Mapper.from_h(Registration, hash, repos: repos).to_h.must_equal reg.to_h
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'builds the proper Result from the Hash representation' do
|
77
|
+
result = Result.new(addr: addr, client: client, data: 'data',
|
78
|
+
task: task)
|
79
|
+
hash = {
|
80
|
+
client_uuid: client.uuid,
|
81
|
+
data: 'data',
|
82
|
+
host: '127.0.0.1',
|
83
|
+
port: 1979,
|
84
|
+
prot: 'TCP',
|
85
|
+
received_at: any(Time),
|
86
|
+
task_uuid: task.uuid,
|
87
|
+
uuid: result.uuid,
|
88
|
+
}
|
89
|
+
Mapper.from_h(Result, hash, repos: repos).to_h.must_equal result.to_h
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'builds the proper Task from the Hash representation' do
|
93
|
+
hash = {
|
94
|
+
data: 'data',
|
95
|
+
done: true,
|
96
|
+
project_uuid: project.uuid,
|
97
|
+
uuid: task.uuid,
|
98
|
+
}
|
99
|
+
Mapper.from_h(Task, hash, repos: repos).to_h.must_equal task.to_h
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '.to_h' do
|
104
|
+
it 'returns the proper Hash representation of a Client' do
|
105
|
+
Mapper.to_h(client).must_equal busy: true, host: '127.0.0.1',
|
106
|
+
port: 1979, prot: 'TCP',
|
107
|
+
type: 'FPGA', uuid: client.uuid
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'returns the proper Hash representation of a Dispatch' do
|
111
|
+
dispatched_at = Time.new(2014, 7, 6, 5, 4, 3)
|
112
|
+
dispatch = Dispatch.new(addr: addr, client: client,
|
113
|
+
dispatched_at: dispatched_at, project: project,
|
114
|
+
task: task)
|
115
|
+
Mapper.to_h(dispatch).must_equal client_uuid: client.uuid,
|
116
|
+
dispatched_at: dispatched_at,
|
117
|
+
host: '127.0.0.1',
|
118
|
+
port: 1979,
|
119
|
+
prot: 'TCP',
|
120
|
+
project_uuid: project.uuid,
|
121
|
+
task_uuid: task.uuid,
|
122
|
+
uuid: dispatch.uuid
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'returns the proper Hash representation of a Registration' do
|
126
|
+
registered_at = Time.new(2014, 7, 6, 5, 4, 3)
|
127
|
+
reg = Registration.new(addr: addr, client: client, project: project,
|
128
|
+
registered_at: registered_at)
|
129
|
+
Mapper.to_h(reg).must_equal client_uuid: client.uuid, host: '127.0.0.1',
|
130
|
+
port: 1979, prot: 'TCP',
|
131
|
+
project_uuid: project.uuid,
|
132
|
+
registered_at: registered_at, uuid: reg.uuid
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'returns the proper Hash representation of a Result' do
|
136
|
+
received_at = Time.new(2014, 7, 6, 5, 4, 3)
|
137
|
+
result = Result.new(addr: addr, client: client, data: 'res',
|
138
|
+
received_at: received_at, task: task)
|
139
|
+
Mapper.to_h(result).must_equal client_uuid: client.uuid, data: 'res',
|
140
|
+
host: '127.0.0.1', port: 1979,
|
141
|
+
prot: 'TCP', received_at: received_at,
|
142
|
+
task_uuid: task.uuid, uuid: result.uuid
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'returns the proper Hash representation of a Tag' do
|
146
|
+
Mapper.to_h(task).must_equal data: 'data', done: true,
|
147
|
+
project_uuid: project.uuid, uuid: task.uuid
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -1,70 +1,94 @@
|
|
1
1
|
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/kamerling/client'
|
3
|
+
require_relative '../../lib/kamerling/message'
|
4
|
+
require_relative '../../lib/kamerling/project'
|
5
|
+
require_relative '../../lib/kamerling/task'
|
6
|
+
require_relative '../../lib/kamerling/uuid'
|
2
7
|
|
3
|
-
module Kamerling
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
+
module Kamerling
|
9
|
+
describe Message do
|
10
|
+
let(:mess) do
|
11
|
+
Message.parse("DATA\0\0\0\0\0\0\0\0\0\0\0\0" \
|
12
|
+
'16B client UUID16B project UUID16B task UUIDsome payload')
|
13
|
+
end
|
8
14
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
describe '.build' do
|
16
|
+
it 'constructs a new message' do
|
17
|
+
client = Client.new
|
18
|
+
project = Project.new
|
19
|
+
task = Task.new
|
20
|
+
message = Message.build(client: client, payload: 'pay',
|
21
|
+
project: project, task: task, type: :DATA)
|
22
|
+
message.client_uuid.must_equal client.uuid
|
23
|
+
message.project_uuid.must_equal project.uuid
|
24
|
+
message.task_uuid.must_equal task.uuid
|
25
|
+
message.payload.must_equal 'pay'
|
26
|
+
message.type.must_equal :DATA
|
27
|
+
end
|
21
28
|
end
|
22
|
-
end
|
23
29
|
|
24
|
-
|
25
|
-
|
26
|
-
|
30
|
+
describe '.parse' do
|
31
|
+
it 'raises on unknown message types' do
|
32
|
+
-> { Message.parse('MESS age') }.must_raise Message::UnknownType
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'doesn’t raise on empty messages' do
|
36
|
+
Message.parse('')
|
37
|
+
end
|
27
38
|
end
|
28
39
|
|
29
|
-
|
30
|
-
|
40
|
+
describe '#client_type' do
|
41
|
+
it 'returns the client’s type' do
|
42
|
+
mess.client_type.must_equal :"\0\0\0\0"
|
43
|
+
fpga_mess = Message.parse("RGSTFPGA\0\0\0\0\0\0\0\0" \
|
44
|
+
'16B client UUID16B project UUID' \
|
45
|
+
'16B task UUID')
|
46
|
+
fpga_mess.client_type.must_equal :FPGA
|
47
|
+
end
|
31
48
|
end
|
32
|
-
end
|
33
49
|
|
34
|
-
|
35
|
-
|
36
|
-
|
50
|
+
describe '#client_uuid' do
|
51
|
+
it 'returns the client UUID' do
|
52
|
+
mess.client_uuid.must_equal '31364220-636c-6965-6e74-202055554944'
|
53
|
+
end
|
37
54
|
end
|
38
|
-
end
|
39
55
|
|
40
|
-
|
41
|
-
|
42
|
-
|
56
|
+
describe '#payload' do
|
57
|
+
it 'returns the result payload' do
|
58
|
+
mess.payload.must_equal 'some payload'
|
59
|
+
end
|
43
60
|
end
|
44
|
-
end
|
45
61
|
|
46
|
-
|
47
|
-
|
48
|
-
|
62
|
+
describe '#project_uuid' do
|
63
|
+
it 'returns the project UUID' do
|
64
|
+
mess.project_uuid.must_equal '31364220-7072-6f6a-6563-742055554944'
|
65
|
+
end
|
49
66
|
end
|
50
|
-
end
|
51
67
|
|
52
|
-
|
53
|
-
|
54
|
-
|
68
|
+
describe '#task_uuid' do
|
69
|
+
it 'returns the task UUID' do
|
70
|
+
mess.task_uuid.must_equal '31364220-7461-736b-2020-202055554944'
|
71
|
+
end
|
55
72
|
end
|
56
|
-
end
|
57
73
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
'
|
74
|
+
describe '#to_hex' do
|
75
|
+
it 'returns a hex representation of the message' do
|
76
|
+
assert mess.to_hex.start_with?('44 41 54 41')
|
77
|
+
assert mess.to_hex.end_with?('70 61 79 6c 6f 61 64')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#to_s' do
|
82
|
+
it 'returns the raw bytes' do
|
83
|
+
mess.to_s.must_equal "#{mess.type}\0\0\0\0\0\0\0\0\0\0\0\0" \
|
84
|
+
'16B client UUID16B project UUID16B task UUIDsome payload'
|
85
|
+
end
|
62
86
|
end
|
63
|
-
end
|
64
87
|
|
65
|
-
|
66
|
-
|
67
|
-
|
88
|
+
describe '#type' do
|
89
|
+
it 'returns the message type' do
|
90
|
+
mess.type.must_match(/\A[A-Z]{4}\z/)
|
91
|
+
end
|
68
92
|
end
|
69
93
|
end
|
70
|
-
end
|
94
|
+
end
|
@@ -1,21 +1,27 @@
|
|
1
|
+
require 'socket'
|
1
2
|
require_relative '../spec_helper'
|
3
|
+
require_relative '../../lib/kamerling/addr'
|
4
|
+
require_relative '../../lib/kamerling/message'
|
5
|
+
require_relative '../../lib/kamerling/net_dispatcher'
|
2
6
|
|
3
|
-
module Kamerling
|
4
|
-
describe
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
module Kamerling
|
8
|
+
describe NetDispatcher do
|
9
|
+
describe '#dispatch' do
|
10
|
+
it 'dispatches messages to TCP clients' do
|
11
|
+
server = TCPServer.open(0)
|
12
|
+
thread = Thread.new { server.accept.read }
|
13
|
+
addr = Addr[server.addr[3], server.addr[1], :TCP]
|
14
|
+
NetDispatcher.dispatch addr, Message.parse('PING')
|
15
|
+
thread.value.must_equal 'PING'
|
16
|
+
end
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
it 'dispatches messages to UDP clients' do
|
19
|
+
server = UDPSocket.new.tap { |s| s.bind '127.0.0.1', 0 }
|
20
|
+
thread = Thread.new { server.recvfrom(2**16).first }
|
21
|
+
addr = Addr[server.addr[3], server.addr[1], :UDP]
|
22
|
+
NetDispatcher.dispatch addr, Message.parse('PING')
|
23
|
+
thread.value.must_equal 'PING'
|
24
|
+
end
|
19
25
|
end
|
20
26
|
end
|
21
|
-
end
|
27
|
+
end
|
@@ -1,23 +1,33 @@
|
|
1
1
|
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/kamerling/addr'
|
3
|
+
require_relative '../../lib/kamerling/client'
|
4
|
+
require_relative '../../lib/kamerling/message'
|
5
|
+
require_relative '../../lib/kamerling/receiver'
|
6
|
+
require_relative '../../lib/kamerling/repo'
|
7
|
+
require_relative '../../lib/kamerling/repos'
|
8
|
+
require_relative '../../lib/kamerling/result'
|
9
|
+
require_relative '../../lib/kamerling/task'
|
2
10
|
|
3
|
-
module Kamerling
|
4
|
-
describe
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
module Kamerling
|
12
|
+
describe Receiver do
|
13
|
+
describe '.receive' do
|
14
|
+
it 'saves the result and updates client and task' do
|
15
|
+
addr = Addr.new
|
16
|
+
client = Client.new(busy: true)
|
17
|
+
task = Task.new(done: false)
|
18
|
+
repos = fake(:repos, as: :class)
|
19
|
+
stub(repos).<<(any_args) { repos }
|
20
|
+
stub(repos).[](Client) { fake(:repo, :[] => client) }
|
21
|
+
stub(repos).[](Task) { fake(:repo, :[] => task) }
|
22
|
+
message = Message.build(client: client, payload: 'data',
|
23
|
+
project: Project.new, task: task, type: :RSLT)
|
24
|
+
Receiver.receive addr: addr, message: message, repos: repos
|
25
|
+
refute client.busy
|
26
|
+
assert task.done
|
27
|
+
repos.must_have_received :<<, [client]
|
28
|
+
repos.must_have_received :<<, [any(Result)]
|
29
|
+
repos.must_have_received :<<, [task]
|
30
|
+
end
|
21
31
|
end
|
22
32
|
end
|
23
|
-
end
|
33
|
+
end
|
@@ -1,20 +1,48 @@
|
|
1
1
|
require_relative '../spec_helper'
|
2
|
+
require_relative '../../lib/kamerling/addr'
|
3
|
+
require_relative '../../lib/kamerling/client'
|
4
|
+
require_relative '../../lib/kamerling/message'
|
5
|
+
require_relative '../../lib/kamerling/project'
|
6
|
+
require_relative '../../lib/kamerling/registration'
|
7
|
+
require_relative '../../lib/kamerling/registrar'
|
8
|
+
require_relative '../../lib/kamerling/repo'
|
2
9
|
|
3
|
-
module Kamerling
|
4
|
-
describe
|
5
|
-
|
10
|
+
module Kamerling
|
11
|
+
describe Registrar do
|
12
|
+
describe '.register' do
|
13
|
+
let(:addr) { Addr.new }
|
14
|
+
let(:client) { Client.new }
|
15
|
+
let(:project) { Project.new }
|
6
16
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
}
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
let(:mess) do
|
18
|
+
Message.build(client: client, payload: 'data', project: project,
|
19
|
+
task: Task.new, type: :RGST)
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:repos) { fake(:repos, as: :class) }
|
23
|
+
|
24
|
+
before do
|
25
|
+
stub(repos).[](Client) { fake(:repo, :[] => client) }
|
26
|
+
stub(repos).[](Project) { fake(:repo, :[] => project) }
|
27
|
+
stub(repos).[](Registration) { fake(:repo) }
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'registers that the given client can do the given project' do
|
31
|
+
Registrar.register addr: addr, message: mess, repos: repos
|
32
|
+
repos.must_have_received :<<, [any(Registration)]
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'updates the clien’t addr' do
|
36
|
+
Registrar.register addr: addr, message: mess, repos: repos
|
37
|
+
repos.must_have_received :<<, [client]
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'doesn’t blow up when a new client tries to register' do
|
41
|
+
empty_repo = fake(:repo, :[] => -> { fail Repo::NotFound })
|
42
|
+
stub(repos).[](Client) { empty_repo }
|
43
|
+
Registrar.register addr: addr, message: mess, repos: repos
|
44
|
+
repos.must_have_received :<<, [client]
|
45
|
+
end
|
18
46
|
end
|
19
47
|
end
|
20
|
-
end
|
48
|
+
end
|