kamerling 0.0.2 → 0.0.3

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