Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
wattsworth
/
lumen-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
de5f3b52
authored
Apr 18, 2018
by
John Doe
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
added joule modules
parent
14a6cfba
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
259 additions
and
21 deletions
app/controllers/joule_modules_controller.rb
app/models/db.rb
app/models/joule_module.rb
app/models/nilm.rb
app/services/joule_modules/update_joule_modules.rb
app/views/joule_modules/show.json.jbuilder
config/application.rb
config/routes.rb
db/migrate/20180224021655_create_joule_modules.rb
db/schema.rb
spec/controllers/joule_modules_controller.spec.rb
spec/controllers/joule_modules_controller_spec.rb
spec/factories/joule_adapter_helpers.rb
spec/factories/joule_modules.rb
spec/models/joule_module_spec.rb
spec/models/nilm_spec.rb
spec/services/joule_modules/update_joule_modules_spec.rb
app/controllers/joule_modules_controller.rb
View file @
de5f3b52
class
JouleModulesControllerController
<
ApplicationController
require
'uri'
class
JouleModulesController
<
ApplicationController
before_action
:authenticate_user!
,
only:
[
:show
]
before_action
:authorize_viewer
,
only:
[
:show
]
# GET /joule_modules/<nilm_id>.json
def
show
if
(
params
[
:refresh
])
adapter
=
JouleAdapter
.
new
(
@nilm
.
url
)
@service
=
UpdateJouleModules
.
new
(
@nilm
)
@service
.
run
(
adapter
.
module_info
)
else
@service
=
StubService
.
new
end
@joule_modules
=
@nilm
.
joule_modules
# create the unique URL for module proxy traffic
@url_template
=
"http://%s.modules.wattsworth.local"
render
status:
@service
.
success?
?
:
ok
:
:unprocessable_entity
end
private
def
authorize_viewer
@nilm
=
Nilm
.
find
(
params
[
:id
])
head
:unauthorized
unless
current_user
.
views_nilm?
(
@nilm
)
end
end
app/models/db.rb
View file @
de5f3b52
...
...
@@ -9,7 +9,7 @@ class Db < ApplicationRecord
class_name:
'DbFolder'
,
dependent: :destroy
belongs_to
:nilm
has_many
:db_streams
#flat map of all streams in database
#---Validations
validates
:max_points_per_plot
,
numericality:
{
only_integer:
true
}
...
...
app/models/joule_module.rb
View file @
de5f3b52
class
JouleModule
<
ApplicationRecord
belongs_to
:nilm
has_many
:joule_pipes
has_many
:joule_pipes
,
dependent: :destroy
def
self
.
json_keys
[
:name
,
:description
,
:web_interface
,
:exec_cmd
,
:status
,
:pid
]
end
end
app/models/nilm.rb
View file @
de5f3b52
...
...
@@ -10,7 +10,7 @@ class Nilm < ApplicationRecord
has_many
:user_groups
,
through: :permissions
has_many
:data_views_nilms
has_many
:data_views
,
through: :data_views_nilms
has_many
:joule_modules
,
dependent: :destroy
#---Validations-----
validates
:name
,
presence:
true
,
uniqueness:
true
validates
:url
,
presence:
true
,
uniqueness:
true
...
...
app/services/joule_modules/update_joule_modules.rb
View file @
de5f3b52
...
...
@@ -4,11 +4,51 @@
class
UpdateJouleModules
include
ServiceStatus
def
initialize
()
def
initialize
(
nilm
)
super
()
@nilm
=
nilm
end
def
run
()
def
run
(
module_info
)
#module_info as returned by JouleAdapter
if
module_info
.
nil?
add_error
(
"unable to retrieve module information"
)
return
self
end
#remove the previous modules
@nilm
.
joule_modules
.
destroy_all
module_info
.
each
do
|
info
|
@nilm
.
joule_modules
<<
_build_module
(
info
)
end
set_notice
(
"refreshed modules"
)
self
end
def
_build_module
(
info
)
# create JouleModule and associated pipes from
# hash returned by the JouleAdapter.module_info
params
=
info
.
extract!
(
*
JouleModule
.
json_keys
)
m
=
JouleModule
.
new
(
params
)
# link inputs to database streams
info
[
:input_paths
].
each
do
|
name
,
path
|
m
.
joule_pipes
<<
JoulePipe
.
new
(
direction:
'input'
,
name:
name
,
db_stream:
_retrieve_stream
(
path
))
end
info
[
:output_paths
].
each
do
|
name
,
path
|
m
.
joule_pipes
<<
JoulePipe
.
new
(
direction:
'output'
,
name:
name
,
db_stream:
_retrieve_stream
(
path
))
end
return
m
end
def
_retrieve_stream
(
path
)
dbStream
=
@nilm
.
db
.
db_streams
.
find_by_path
(
path
)
if
dbStream
.
nil?
add_warning
(
"[
#{
path
}
] not in database"
)
end
dbStream
end
end
app/views/joule_modules/show.json.jbuilder
0 → 100644
View file @
de5f3b52
json.data do
json.array! @joule_modules do |m|
json.extract! m, *JouleModule.json_keys
json.url @url_template % [m.id]
end
end
json.partial! "helpers/messages", service: @service
config/application.rb
View file @
de5f3b52
...
...
@@ -32,7 +32,7 @@ module ControlPanel
# Skip views, helpers and assets when generating a new resource.
config
.
api_only
=
true
# Add folders under the services and adapters directory
%w(data nilm db db_folder db_stream permission user_group user data_view)
.
each
do
|
service
|
%w(data nilm db db_folder db_stream permission user_group user data_view
joule_modules
)
.
each
do
|
service
|
config
.
autoload_paths
<<
Rails
.
root
.
join
(
"app/services/
#{
service
}
"
)
end
config
.
autoload_paths
<<
Rails
.
root
.
join
(
"app/adapters"
)
...
...
config/routes.rb
View file @
de5f3b52
...
...
@@ -10,6 +10,7 @@ Rails.application.routes.draw do
get
'home'
#retrieve a user's home data view
end
end
resources
:joule_modules
,
only:
[
:show
]
resources
:dbs
,
only:
[
:show
,
:update
]
resources
:db_folders
,
only:
[
:show
,
:update
]
resources
:db_streams
,
only:
[
:index
,
:update
]
do
...
...
db/migrate/20180224021655_create_joule_modules.rb
View file @
de5f3b52
...
...
@@ -8,11 +8,14 @@ class CreateJouleModules < ActiveRecord::Migration[5.1]
t
.
string
:status
t
.
integer
:pid
t
.
string
:joule_id
t
.
belongs_to
:nilm
,
index:
true
t
.
timestamps
end
create_table
:joule_pipes
do
|
t
|
t
.
belongs_to
:joule_pipe
,
index:
true
t
.
belongs_to
:joule_module
,
index:
true
t
.
belongs_to
:db_stream
,
index:
true
t
.
string
:name
t
.
string
:direction
t
.
timestamps
end
...
...
db/schema.rb
View file @
de5f3b52
...
...
@@ -112,17 +112,22 @@ ActiveRecord::Schema.define(version: 20180224021655) do
t
.
string
"status"
t
.
integer
"pid"
t
.
string
"joule_id"
t
.
integer
"nilm_id"
t
.
datetime
"created_at"
,
null:
false
t
.
datetime
"updated_at"
,
null:
false
t
.
index
[
"nilm_id"
],
name:
"index_joule_modules_on_nilm_id"
end
create_table
"joule_pipes"
,
force: :cascade
do
|
t
|
t
.
integer
"joule_pipe_id"
t
.
integer
"joule_module_id"
t
.
integer
"db_stream_id"
t
.
string
"name"
t
.
string
"direction"
t
.
datetime
"created_at"
,
null:
false
t
.
datetime
"updated_at"
,
null:
false
t
.
index
[
"db_stream_id"
],
name:
"index_joule_pipes_on_db_stream_id"
t
.
index
[
"joule_module_id"
],
name:
"index_joule_pipes_on_joule_module_id"
t
.
index
[
"joule_pipe_id"
],
name:
"index_joule_pipes_on_joule_pipe_id"
end
...
...
spec/controllers/joule_modules_controller.spec.rb
deleted
100644 → 0
View file @
14a6cfba
require
'rails_helper'
RSpec
.
describe
JouleModulesControllerController
,
type: :controller
do
end
spec/controllers/joule_modules_controller_spec.rb
0 → 100644
View file @
de5f3b52
# frozen_string_literal: true
require
'rails_helper'
RSpec
.
describe
JouleModulesController
,
type: :request
do
let
(
:john
)
{
create
(
:user
,
first_name:
'John'
)
}
let
(
:steve
)
{
create
(
:user
,
first_name:
'Steve'
)
}
let
(
:john_nilm
)
{
create
(
:nilm
,
name:
"John's NILM"
,
admins:
[
john
])
}
let
(
:lab_nilm
)
{
create
(
:nilm
,
name:
'Lab NILM'
,
owners:
[
john
])
}
let
(
:pete_nilm
)
{
create
(
:nilm
,
name:
"Pete's NILM"
,
viewers:
[
john
])}
# index action does not exist
describe
'GET show'
do
context
'with any permissions'
do
it
'returns the modules as json'
do
# john has some permission on all 3 nilms
@auth_headers
=
john
.
create_new_auth_token
[
pete_nilm
,
lab_nilm
,
john_nilm
].
each
do
|
nilm
|
get
"/joule_modules/
#{
nilm
.
id
}
.json"
,
headers:
@auth_headers
expect
(
response
.
status
).
to
eq
(
200
)
expect
(
response
.
header
[
'Content-Type'
]).
to
include
(
'application/json'
)
end
end
it
'refreshes modules when requested'
do
@mock_adapter
=
double
(
JouleAdapter
)
allow
(
JouleAdapter
).
to
receive
(
:new
).
and_return
(
@mock_adapter
)
expect
(
@mock_adapter
).
to
receive
(
:module_info
).
and_return
([])
@auth_headers
=
john
.
create_new_auth_token
get
"/joule_modules/
#{
john_nilm
.
id
}
.json?refresh=1"
,
headers:
@auth_headers
expect
(
response
.
status
).
to
eq
(
200
)
expect
(
response
.
header
[
'Content-Type'
]).
to
include
(
'application/json'
)
end
it
'injects the proxy URL parameter into the module json'
do
test_module
=
create
(
:joule_module
,
name:
'test'
,
description:
'sample'
)
john_nilm
.
joule_modules
<<
test_module
get
"/joule_modules/
#{
john_nilm
.
id
}
.json"
,
headers:
john
.
create_new_auth_token
body
=
JSON
.
parse
(
response
.
body
)
expect
(
body
[
'data'
][
0
][
'name'
]).
to
eq
(
test_module
.
name
)
expect
(
body
[
'data'
][
0
][
'url'
]).
to
start_with
(
"http://
#{
test_module
.
id
}
.modules"
)
end
end
context
'without permissions'
do
it
'returns unauthorized'
do
# steve does NOT have permissions on john_nilm
@auth_headers
=
steve
.
create_new_auth_token
get
"/joule_modules/
#{
john_nilm
.
id
}
.json"
,
headers:
@auth_headers
expect
(
response
.
status
).
to
eq
(
401
)
end
end
context
'without sign-in'
do
it
'returns unauthorized'
do
# no headers: nobody is signed in, deny all
get
"/joule_modules/
#{
john_nilm
.
id
}
.json"
expect
(
response
.
status
).
to
eq
(
401
)
end
end
end
end
spec/factories/joule_adapter_helpers.rb
0 → 100644
View file @
de5f3b52
# frozen_string_literal: true
# Mock class to test clients
class
MockJouleAdapter
attr_reader
:module_info
def
initialize
@module_info
=
[]
end
def
add_module
(
name
,
inputs
=
{},
outputs
=
{})
@module_info
<<
{
"name"
:
name
,
"description"
:
"mock module"
,
"web_interface"
:
true
,
"exec_cmd"
:
"/path/to/cmd"
,
"args"
:
[
"--message"
,
"argval"
],
"input_paths"
:
inputs
,
"output_paths"
:
outputs
,
"status"
:
"running"
,
"pid"
:
26749
,
"id"
:
3
,
"socket"
:
"/tmp/wattsworth.joule.2"
}
end
end
spec/factories/joule_modules.rb
View file @
de5f3b52
FactoryGirl
.
define
do
factory
:joule_module
do
name
{
Faker
::
Lorem
.
words
(
3
).
join
(
' '
)
}
description
{
Faker
::
Lorem
.
sentence
}
exec_cmd
'/path/to/cmd'
web_interface
false
status
'running'
joule_id
Faker
::
Number
.
number
(
3
).
to_i
end
end
spec/models/joule_module_spec.rb
View file @
de5f3b52
...
...
@@ -15,17 +15,14 @@ RSpec.describe JouleModule, type: :model do
it
'removes pipes when destroyed'
do
@joule_module
=
JouleModule
.
create
@joule_module
.
joule_pipes
<<
JoulePipe
.
create
(
db_stream:
DbStream
.
create
,
db_stream:
create
(
:db_stream
)
,
direction:
'output'
)
expect
(
JouleModule
.
find_by_id
(
@joule_module
.
id
).
pipes
.
count
).
to
equal
1
expect
(
JouleModule
.
find_by_id
(
@joule_module
.
id
).
joule_
pipes
.
count
).
to
equal
1
@joule_module
.
destroy
expect
(
JouleModule
.
count
).
to
equal
0
# deletes associated pipes
expect
(
JoulePipe
.
count
).
to
equal
0
# does not delete the streams
expect
(
DbStream
.
count
).
to
equal
2
end
expect
(
DbStream
.
count
).
to
equal
1
end
end
spec/models/nilm_spec.rb
View file @
de5f3b52
...
...
@@ -8,6 +8,8 @@ RSpec.describe 'Nilm' do
specify
{
expect
(
nilm
).
to
respond_to
(
:description
)
}
specify
{
expect
(
nilm
).
to
respond_to
(
:url
)
}
specify
{
expect
(
nilm
).
to
respond_to
(
:db
)
}
specify
{
expect
(
nilm
).
to
respond_to
(
:joule_modules
)
}
end
it
'removes associated db when destroyed'
do
...
...
spec/services/joule_modules/update_joule_modules_spec.rb
0 → 100644
View file @
de5f3b52
# frozen_string_literal: true
require
'rails_helper'
describe
'UpdateJouleModules'
do
it
'replaces existing modules with new ones'
do
nilm
=
create
(
:nilm
)
nilm
.
joule_modules
<<
create
(
:joule_module
,
name:
'prev1'
)
nilm
.
joule_modules
<<
create
(
:joule_module
,
name:
'prev2'
)
adapter
=
MockJouleAdapter
.
new
adapter
.
add_module
(
"new1"
,
inputs
=
{
i1:
'/path/1'
},
outputs
=
{
o1:
'/path/2'
})
adapter
.
add_module
(
"new2"
,
inputs
=
{
i1:
'/path/3'
,
i2:
'/path/4'
},
outputs
=
{
o1:
'/path/5'
,
o2:
'/path/5'
})
service
=
UpdateJouleModules
.
new
(
nilm
)
service
.
run
(
adapter
.
module_info
)
expect
(
service
.
success?
).
to
be
true
# new modules are in the database
expect
(
nilm
.
joule_modules
.
find_by_name
(
'new1'
)).
to
be_present
expect
(
nilm
.
joule_modules
.
find_by_name
(
'new2'
)).
to
be_present
# old ones are gone
expect
(
JouleModule
.
count
).
to
eq
2
# pipes are updated as well
n1
=
nilm
.
joule_modules
.
find_by_name
(
'new1'
)
expect
(
n1
.
joule_pipes
.
count
).
to
eq
2
n2
=
nilm
.
joule_modules
.
find_by_name
(
'new2'
)
expect
(
n2
.
joule_pipes
.
count
).
to
eq
4
# old pipes are gone
expect
(
JoulePipe
.
count
).
to
eq
6
end
it
'produces a warning if a stream is not in the database'
do
nilm
=
create
(
:nilm
)
adapter
=
MockJouleAdapter
.
new
adapter
.
add_module
(
"module"
,
outputs
=
{
output:
'/missing/path'
})
service
=
UpdateJouleModules
.
new
(
nilm
)
service
.
run
(
adapter
.
module_info
)
expect
(
service
.
warnings?
).
to
be
true
end
it
'links db_stream to the pipe if the stream is in the database'
do
nilm
=
create
(
:nilm
)
nilm
.
db
.
db_streams
<<
create
(
:db_stream
,
path:
'/matched/path1'
)
nilm
.
db
.
db_streams
<<
create
(
:db_stream
,
path:
'/matched/path2'
)
adapter
=
MockJouleAdapter
.
new
adapter
.
add_module
(
"module"
,
inputs
=
{
input:
'/matched/path1'
},
outputs
=
{
output:
'/matched/path2'
})
service
=
UpdateJouleModules
.
new
(
nilm
)
service
.
run
(
adapter
.
module_info
)
expect
(
service
.
warnings?
).
to
be
false
end
it
'returns error if Joule server is unavailable'
do
nilm
=
Nilm
.
create
(
name:
'test'
,
url:
'invalid'
)
mock_service
=
instance_double
(
UpdateDb
,
run:
StubService
.
new
)
allow
(
UpdateDb
).
to
receive
(
:new
)
.
and_return
(
mock_service
)
service
=
UpdateNilm
.
new
()
service
.
run
(
nilm
)
expect
(
service
.
success?
).
to
be
false
expect
(
mock_service
).
to_not
have_received
(
:run
)
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment