kamerling 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -13
  3. data/Gemfile +0 -1
  4. data/Gemfile.lock +64 -64
  5. data/README.md +18 -1
  6. data/Rakefile +5 -3
  7. data/bin/kamerling +1 -1
  8. data/config/reek.yml +20 -3
  9. data/kamerling.gemspec +16 -13
  10. data/lib/kamerling.rb +2 -28
  11. data/lib/kamerling/addr.rb +17 -3
  12. data/lib/kamerling/client.rb +10 -11
  13. data/lib/kamerling/core_extensions/main.rb +14 -14
  14. data/lib/kamerling/dispatch.rb +13 -0
  15. data/lib/kamerling/handler.rb +16 -25
  16. data/lib/kamerling/http_api.rb +50 -34
  17. data/lib/kamerling/logging.rb +36 -16
  18. data/lib/kamerling/mapper.rb +33 -0
  19. data/lib/kamerling/message.rb +50 -37
  20. data/lib/kamerling/migrations/2_results_received_at.rb +7 -0
  21. data/lib/kamerling/migrations/3_dispatches.rb +17 -0
  22. data/lib/kamerling/migrations/4_registrations_registered_at.rb +7 -0
  23. data/lib/kamerling/migrations/5_clients_type.rb +7 -0
  24. data/lib/kamerling/net_dispatcher.rb +12 -7
  25. data/lib/kamerling/project.rb +7 -3
  26. data/lib/kamerling/receiver.rb +38 -10
  27. data/lib/kamerling/registrar.rb +45 -8
  28. data/lib/kamerling/registration.rb +9 -10
  29. data/lib/kamerling/repo.rb +33 -26
  30. data/lib/kamerling/repos.rb +52 -45
  31. data/lib/kamerling/result.rb +10 -11
  32. data/lib/kamerling/server/http.rb +28 -21
  33. data/lib/kamerling/server/sock.rb +32 -24
  34. data/lib/kamerling/server/tcp.rb +23 -15
  35. data/lib/kamerling/server/udp.rb +24 -16
  36. data/lib/kamerling/server_runner.rb +30 -41
  37. data/lib/kamerling/settings.rb +28 -0
  38. data/lib/kamerling/task.rb +7 -7
  39. data/lib/kamerling/task_dispatcher.rb +31 -22
  40. data/lib/kamerling/uuid.rb +13 -11
  41. data/lib/kamerling/uuid_entity.rb +23 -9
  42. data/lib/kamerling/value.rb +13 -0
  43. data/lib/kamerling/views/clients.slim +3 -1
  44. data/lib/kamerling/views/project.slim +8 -4
  45. data/lib/kamerling/views/projects.slim +7 -1
  46. data/spec/kamerling/addr_spec.rb +32 -22
  47. data/spec/kamerling/client_spec.rb +9 -5
  48. data/spec/kamerling/core_extensions/main_spec.rb +18 -13
  49. data/spec/kamerling/dispatch_spec.rb +16 -0
  50. data/spec/kamerling/handler_spec.rb +24 -34
  51. data/spec/kamerling/http_api_spec.rb +94 -73
  52. data/spec/kamerling/logging_spec.rb +93 -62
  53. data/spec/kamerling/mapper_spec.rb +151 -0
  54. data/spec/kamerling/message_spec.rb +73 -49
  55. data/spec/kamerling/net_dispatcher_spec.rb +22 -16
  56. data/spec/kamerling/receiver_spec.rb +29 -19
  57. data/spec/kamerling/registrar_spec.rb +43 -15
  58. data/spec/kamerling/registration_spec.rb +17 -0
  59. data/spec/kamerling/repo_spec.rb +63 -47
  60. data/spec/kamerling/repos_spec.rb +121 -109
  61. data/spec/kamerling/result_spec.rb +16 -0
  62. data/spec/kamerling/server/http_spec.rb +19 -14
  63. data/spec/kamerling/server/tcp_spec.rb +41 -35
  64. data/spec/kamerling/server/udp_spec.rb +40 -34
  65. data/spec/kamerling/server_runner_spec.rb +62 -53
  66. data/spec/kamerling/settings_spec.rb +36 -0
  67. data/spec/kamerling/task_dispatcher_spec.rb +38 -15
  68. data/spec/kamerling/task_spec.rb +9 -5
  69. data/spec/kamerling/uuid_entity_spec.rb +53 -25
  70. data/spec/kamerling/uuid_spec.rb +19 -16
  71. data/spec/kamerling/value_spec.rb +21 -0
  72. data/spec/spec_helper.rb +3 -6
  73. metadata +54 -8
  74. data/lib/kamerling/core_extensions.rb +0 -1
@@ -0,0 +1,17 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/kamerling/registration'
3
+
4
+ module Kamerling
5
+ describe Registration do
6
+ describe '#registered_at' do
7
+ it 'defaults to the current time' do
8
+ registered_at = Registration.new.registered_at
9
+ assert registered_at.between?(Time.now - 1, Time.now + 1)
10
+ end
11
+
12
+ it 'defaults to the time of Registration’s creation' do
13
+ Registration.new.registered_at.wont_equal Registration.new.registered_at
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,60 +1,76 @@
1
+ require 'sequel'
1
2
  require_relative '../spec_helper'
3
+ require_relative '../../lib/kamerling/mapper'
4
+ require_relative '../../lib/kamerling/project'
5
+ require_relative '../../lib/kamerling/repo'
6
+ require_relative '../../lib/kamerling/uuid'
7
+ require_relative '../../lib/kamerling/uuid_entity'
2
8
 
3
- module Kamerling describe Repo do
4
- Tune = Class.new(UUIDEntity) { attribute :genre, Symbol }
9
+ module Kamerling
10
+ describe Repo do
11
+ Tune = Class.new(UUIDEntity) { attrs genre: Symbol }
5
12
 
6
- describe '#<<' do
7
- it 'passes the Hash version of an object to the source' do
8
- tune = Tune.new genre: :chap_hop
9
- source = fake Sequel::Dataset
10
- mock(source) << { genre: :chap_hop, uuid: tune.uuid }
11
- Repo.new(Tune, source) << tune
12
- end
13
+ describe '#<<' do
14
+ it 'passes the Hash version of an object to the source via a mapper' do
15
+ tune = Tune.new(genre: :chap_hop)
16
+ source = fake(Sequel::Dataset)
17
+ Repo.new(Tune, source) << tune
18
+ source.must_have_received :<<, [tune.to_h]
19
+ end
13
20
 
14
- it 'updates the source’s version if it exists there' do
15
- dataset = fake Sequel::Dataset
16
- source = fake Sequel::Dataset
17
- tune = Tune.new genre: :chap_hop
18
- stub(source).<<(tune.to_h) { fail Sequel::UniqueConstraintViolation }
19
- stub(source).where(uuid: tune.uuid) { dataset }
20
- Repo.new(Tune, source) << tune
21
- dataset.must_have_received :update, [tune.to_h]
21
+ it 'updates the source’s version if it exists there' do
22
+ dataset = fake(Sequel::Dataset)
23
+ source = fake(Sequel::Dataset)
24
+ tune = Tune.new(genre: :chap_hop)
25
+ stub(source).<<(tune.to_h) { fail Sequel::UniqueConstraintViolation }
26
+ stub(source).where(uuid: tune.uuid) { dataset }
27
+ Repo.new(Tune, source) << tune
28
+ dataset.must_have_received :update, [tune.to_h]
29
+ end
22
30
  end
23
- end
24
31
 
25
- describe '#[]' do
26
- it 'hydrates the object found in the repo' do
27
- uuid = UUID.new
28
- source = { { uuid: uuid } => { genre: :chap_hop, uuid: uuid } }
29
- Repo.new(Tune, source)[uuid]
30
- .must_equal Tune.new genre: :chap_hop, uuid: uuid
31
- end
32
+ describe '#[]' do
33
+ it 'hydrates the object found in the repo via a mapper' do
34
+ tune = Tune.new(genre: :chap_hop)
35
+ hash = { genre: :chap_hop, uuid: tune.uuid }
36
+ source = { { uuid: tune.uuid } => hash }
37
+ mapper = fake(:mapper, as: :class)
38
+ stub(mapper).from_h(Tune, hash) { tune }
39
+ retrieved = Repo.new(Tune, source, mapper: mapper)[tune.uuid]
40
+ retrieved.to_h.must_equal tune.to_h
41
+ end
32
42
 
33
- it 'raises NotFound if the object is not found in the repo' do
34
- -> { Repo.new(Tune, {})[UUID.new] }.must_raise Repo::NotFound
43
+ it 'raises NotFound if the object is not found in the repo' do
44
+ -> { Repo.new(Tune, {})[UUID.new] }.must_raise Repo::NotFound
45
+ end
35
46
  end
36
- end
37
47
 
38
- describe '#all' do
39
- it 'returns all objects' do
40
- tune = Tune.new genre: :chap_hop, uuid: UUID.new
41
- source = fake Sequel::Dataset,
42
- all: [{ genre: :chap_hop, uuid: tune.uuid }]
43
- Repo.new(Tune, source).all.must_equal [tune]
48
+ describe '#all' do
49
+ it 'returns all objects via a mapper' do
50
+ tune = Tune.new(genre: :chap_hop)
51
+ source = fake(Sequel::Dataset, all: [genre: :chap_hop, uuid: tune.uuid])
52
+ mapper = fake(:mapper, as: :class, from_h: tune)
53
+ Repo.new(Tune, source, mapper: mapper).all.must_equal [tune]
54
+ end
44
55
  end
45
- end
46
56
 
47
- describe '#related_to' do
48
- it 'returns objects related to the given object' do
49
- tunes = [Tune.new(genre: :ragga), Tune.new(genre: :reggae)]
50
- project = fake :project, uuid: UUID.new
51
- results = [
52
- { genre: :ragga, uuid: tunes.first.uuid },
53
- { genre: :reggae, uuid: tunes.last.uuid },
54
- ]
55
- source = fake Sequel::Dataset
56
- stub(source).where(project_uuid: project.uuid) { results }
57
- Repo.new(Tune, source).related_to(project).must_equal tunes
57
+ describe '#related_to' do
58
+ it 'returns objects related to the given object via a mapper' do
59
+ ragga = Tune.new(genre: :ragga)
60
+ reggae = Tune.new(genre: :reggae)
61
+ project = Project.new
62
+ results = [
63
+ { genre: :ragga, uuid: ragga.uuid },
64
+ { genre: :reggae, uuid: reggae.uuid },
65
+ ]
66
+ source = fake(Sequel::Dataset)
67
+ stub(source).where(project_uuid: project.uuid) { results }
68
+ mapper = fake(:mapper, as: :class)
69
+ stub(mapper).from_h(Tune, genre: :ragga, uuid: ragga.uuid) { ragga }
70
+ stub(mapper).from_h(Tune, genre: :reggae, uuid: reggae.uuid) { reggae }
71
+ repo = Repo.new(Tune, source, mapper: mapper)
72
+ repo.related_to(project).must_equal [ragga, reggae]
73
+ end
58
74
  end
59
75
  end
60
- end end
76
+ end
@@ -1,136 +1,148 @@
1
+ require 'sequel'
1
2
  require_relative '../spec_helper'
3
+ require_relative '../../lib/kamerling/addr'
4
+ require_relative '../../lib/kamerling/client'
5
+ require_relative '../../lib/kamerling/project'
6
+ require_relative '../../lib/kamerling/registration'
7
+ require_relative '../../lib/kamerling/repo'
8
+ require_relative '../../lib/kamerling/repos'
9
+ require_relative '../../lib/kamerling/result'
10
+ require_relative '../../lib/kamerling/task'
11
+ require_relative '../../lib/kamerling/uuid'
2
12
 
3
- module Kamerling describe Repos do
4
- describe '.<<' do
5
- it 'shuffles the object into the right repo' do
6
- Repos.repos = { Object => repo = fake(:repo) }
7
- Repos.<< object = Object.new
8
- repo.must_have_received :<<, [object]
9
- end
13
+ module Kamerling
14
+ describe Repos do
15
+ describe '.<<' do
16
+ it 'shuffles the object into the right repo' do
17
+ Repos.repos = { Object => repo = fake(:repo) }
18
+ Repos.<< object = Object.new
19
+ repo.must_have_received :<<, [object]
20
+ end
10
21
 
11
- it 'can be chained' do
12
- str_repo, sym_repo = fake(:repo), fake(:repo)
13
- Repos.repos = { String => str_repo, Symbol => sym_repo }
14
- Repos << 'str' << :sym
15
- str_repo.must_have_received :<<, ['str']
16
- sym_repo.must_have_received :<<, [:sym]
22
+ it 'can be chained' do
23
+ str_repo, sym_repo = fake(:repo), fake(:repo)
24
+ Repos.repos = { String => str_repo, Symbol => sym_repo }
25
+ Repos << 'str' << :sym
26
+ str_repo.must_have_received :<<, ['str']
27
+ sym_repo.must_have_received :<<, [:sym]
28
+ end
17
29
  end
18
- end
19
30
 
20
- describe '.[]' do
21
- it 'allows querying for repository objects' do
22
- client = fake :client, uuid: UUID.new
23
- Repos.repos = { Client => {} }
24
- Repos[Client][client.uuid].must_be_nil
25
- Repos.repos = { Client => { client.uuid => client } }
26
- Repos[Client][client.uuid].must_equal client
31
+ describe '.[]' do
32
+ it 'allows querying for repository objects' do
33
+ client = Client.new
34
+ Repos.repos = { Client => {} }
35
+ Repos[Client][client.uuid].must_be_nil
36
+ Repos.repos = { Client => { client.uuid => client } }
37
+ Repos[Client][client.uuid].must_equal client
38
+ end
27
39
  end
28
- end
29
40
 
30
- describe '.clients' do
31
- it 'returns all clients' do
32
- Repos.repos = { Client => fake(:repo, all: all_clients = fake) }
33
- Repos.clients.must_equal all_clients
41
+ describe '.clients' do
42
+ it 'returns all clients' do
43
+ Repos.repos = { Client => fake(:repo, all: all_clients = fake) }
44
+ Repos.clients.must_equal all_clients
45
+ end
34
46
  end
35
- end
36
47
 
37
- describe '.clients_for' do
38
- it 'returns all clients for the given project' do
39
- clients = [fake(:client), fake(:client)]
40
- project = fake :project
41
- regs = clients.map { |client| fake :registration, client: client }
42
- reg_repo = fake :repo
43
- stub(reg_repo).related_to(project) { regs }
44
- Repos.repos = { Registration => reg_repo }
45
- Repos.clients_for(project).must_equal clients
48
+ describe '.clients_for' do
49
+ it 'returns all clients for the given project' do
50
+ clients = [Client.new, Client.new]
51
+ project = Project.new
52
+ regs = clients.map { |client| Registration.new(client: client) }
53
+ reg_repo = fake(:repo)
54
+ stub(reg_repo).related_to(project) { regs }
55
+ Repos.repos = { Registration => reg_repo }
56
+ Repos.clients_for(project).must_equal clients
57
+ end
46
58
  end
47
- end
48
59
 
49
- describe '.db=' do
50
- it 'auto-migrates the passed db' do
51
- db = Sequel.sqlite
52
- warn_off { db.tables.wont_include :schema_info }
53
- Repos.db = db
54
- warn_off { db.tables.must_include :schema_info }
60
+ describe '.db=' do
61
+ it 'auto-migrates the passed db' do
62
+ db = Sequel.sqlite
63
+ warn_off { db.tables.wont_include :schema_info }
64
+ Repos.db = db
65
+ warn_off { db.tables.must_include :schema_info }
66
+ end
55
67
  end
56
- end
57
68
 
58
- describe '.free_clients_for' do
59
- it 'returns free clients for the given project' do
60
- busy_client = fake :client, busy: true
61
- free_client = fake :client, busy: false
62
- busy_reg = fake :registration, client: busy_client
63
- free_reg = fake :registration, client: free_client
64
- project = fake :project
65
- repo = fake :repo
66
- stub(repo).related_to(project) { [busy_reg, free_reg] }
67
- Repos.repos = { Registration => repo }
68
- Repos.free_clients_for(project).must_equal [free_client]
69
+ describe '.free_clients_for' do
70
+ it 'returns free clients for the given project' do
71
+ busy_client = Client.new(busy: true)
72
+ free_client = Client.new(busy: false)
73
+ busy_reg = Registration.new(client: busy_client)
74
+ free_reg = Registration.new(client: free_client)
75
+ project = Project.new
76
+ repo = fake(:repo)
77
+ stub(repo).related_to(project) { [busy_reg, free_reg] }
78
+ Repos.repos = { Registration => repo }
79
+ Repos.free_clients_for(project).must_equal [free_client]
80
+ end
69
81
  end
70
- end
71
82
 
72
- describe '.next_task_for' do
73
- it 'returns the next task for the given project' do
74
- project = fake :project
75
- done_task = fake :task, done: true
76
- new_task = fake :task, done: false
77
- repo = fake :repo
78
- stub(repo).related_to(project) { [done_task, new_task] }
79
- Repos.repos = { Task => repo }
80
- Repos.next_task_for(project).must_equal new_task
83
+ describe '.next_task_for' do
84
+ it 'returns the next task for the given project' do
85
+ project = Project.new
86
+ done_task = Task.new(done: true)
87
+ new_task = Task.new(done: false)
88
+ repo = fake(:repo)
89
+ stub(repo).related_to(project) { [done_task, new_task] }
90
+ Repos.repos = { Task => repo }
91
+ Repos.next_task_for(project).must_equal new_task
92
+ end
81
93
  end
82
- end
83
94
 
84
- describe '.project' do
85
- it 'returns the project with the given UUID' do
86
- gimps = fake :project, uuid: UUID.new
87
- Repos.repos = { Project => { gimps.uuid => gimps } }
88
- Repos.project(gimps.uuid).must_equal gimps
95
+ describe '.project' do
96
+ it 'returns the project with the given UUID' do
97
+ gimps = Project.new
98
+ Repos.repos = { Project => { gimps.uuid => gimps } }
99
+ Repos.project(gimps.uuid).must_equal gimps
100
+ end
89
101
  end
90
- end
91
102
 
92
- describe '.projects' do
93
- it 'returns all projects' do
94
- Repos.repos = { Project => fake(:repo, all: all_projects = fake) }
95
- Repos.projects.must_equal all_projects
103
+ describe '.projects' do
104
+ it 'returns all projects' do
105
+ Repos.repos = { Project => fake(:repo, all: all_projects = fake) }
106
+ Repos.projects.must_equal all_projects
107
+ end
96
108
  end
97
- end
98
109
 
99
- describe '.tasks_for' do
100
- it 'returns all tasks for the given project' do
101
- project = fake :project
102
- tasks = [fake(:task), fake(:task)]
103
- task_repo = fake :repo
104
- stub(task_repo).related_to(project) { tasks }
105
- Repos.repos = { Task => task_repo }
106
- Repos.tasks_for(project).must_equal tasks
110
+ describe '.tasks_for' do
111
+ it 'returns all tasks for the given project' do
112
+ project = Project.new
113
+ tasks = [Task.new, Task.new]
114
+ task_repo = fake(:repo)
115
+ stub(task_repo).related_to(project) { tasks }
116
+ Repos.repos = { Task => task_repo }
117
+ Repos.tasks_for(project).must_equal tasks
118
+ end
107
119
  end
108
- end
109
120
 
110
- describe 'when working on actual database' do
111
- before { Repos.db = Sequel.sqlite }
121
+ describe 'when working on actual database' do
122
+ before { Repos.db = Sequel.sqlite }
112
123
 
113
- it 'makes sure objects can be stored and retrieved' do
114
- addr = Addr['127.0.0.1', 1981, :TCP]
115
- client = Client.new addr: addr, uuid: UUID.new
116
- project = Project.new name: 'project name', uuid: UUID.new
117
- task = Task.new data: 'data', project: project, uuid: UUID.new
118
- reg = Registration.new addr: addr, client: client, project: project
119
- res = Result.new addr: addr, client: client, data: 'da', task: task
120
- Repos << client << project << task << reg << res
121
- Repos[Client][client.uuid].must_equal client
122
- Repos[Project][project.uuid].must_equal project
123
- Repos[Registration][reg.uuid].must_equal reg
124
- Repos[Result][res.uuid].must_equal res
125
- Repos[Task][task.uuid].must_equal task
126
- end
124
+ it 'makes sure objects can be stored and retrieved' do
125
+ addr = Addr['127.0.0.1', 1981, :TCP]
126
+ client = Client.new(addr: addr)
127
+ project = Project.new(name: 'project name', uuid: UUID.new)
128
+ task = Task.new(data: 'data', project: project, uuid: UUID.new)
129
+ reg = Registration.new(addr: addr, client: client, project: project)
130
+ res = Result.new(addr: addr, client: client, data: 'da', task: task)
131
+ Repos << client << project << task << reg << res
132
+ Repos[Client][client.uuid].must_equal client
133
+ Repos[Project][project.uuid].must_equal project
134
+ Repos[Registration][reg.uuid].must_equal reg
135
+ Repos[Result][res.uuid].must_equal res
136
+ Repos[Task][task.uuid].must_equal task
137
+ end
127
138
 
128
- it 'makes sure objects can be updated' do
129
- client = Client.new addr: Addr['127.0.0.1', 1979, :TCP], uuid: UUID.new
130
- Repos << client
131
- client.addr.port = 1981
132
- Repos << client
133
- Repos[Client][client.uuid].addr.port.must_equal 1981
139
+ it 'makes sure objects can be updated' do
140
+ client = Client.new(addr: Addr['127.0.0.1', 1979, :TCP])
141
+ Repos << client
142
+ client.busy = true
143
+ Repos << client
144
+ assert Repos[Client][client.uuid].busy
145
+ end
134
146
  end
135
147
  end
136
- end end
148
+ end
@@ -0,0 +1,16 @@
1
+ require_relative '../spec_helper'
2
+ require_relative '../../lib/kamerling/result'
3
+
4
+ module Kamerling
5
+ describe Result do
6
+ describe '#received_at' do
7
+ it 'defaults to the current time' do
8
+ assert Result.new.received_at.between?(Time.now - 1, Time.now + 1)
9
+ end
10
+
11
+ it 'defaults to the time of Result’s creation' do
12
+ Result.new.received_at.wont_equal Result.new.received_at
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,22 +1,27 @@
1
+ require 'net/http'
2
+ require 'uri'
1
3
  require_relative '../../spec_helper'
4
+ require_relative '../../../lib/kamerling/server/http'
2
5
 
3
- module Kamerling describe Server::HTTP do
4
- let(:addr) { Addr['localhost', 2009, :TCP] }
6
+ module Kamerling
7
+ describe Server::HTTP do
8
+ let(:addr) { Addr['localhost', 2009, :TCP] }
5
9
 
6
- describe '#addr' do
7
- it 'returns the server’s host + port as a TCP addr' do
8
- Server::HTTP.new(addr: addr).addr.must_equal addr
10
+ describe '#addr' do
11
+ it 'returns the server’s host + port as a TCP addr' do
12
+ Server::HTTP.new(addr: addr).addr.must_equal addr
13
+ end
9
14
  end
10
- end
11
15
 
12
- describe '#start, #stop' do
13
- it 'starts/stops a HTTP server on the given host and port' do
14
- capture_io do
15
- server = Server::HTTP.new(addr: addr).start
16
- uri = URI.parse 'http://localhost:2009'
17
- Net::HTTP.get_response(uri).must_be_kind_of Net::HTTPSuccess
18
- server.stop
16
+ describe '#start, #stop' do
17
+ it 'starts/stops a HTTP server on the given host and port' do
18
+ capture_io do
19
+ server = Server::HTTP.new(addr: addr).start
20
+ uri = URI.parse('http://localhost:2009')
21
+ Net::HTTP.get_response(uri).must_be_kind_of Net::HTTPSuccess
22
+ server.stop
23
+ end
19
24
  end
20
25
  end
21
26
  end
22
- end end
27
+ end