Commit b8e46e81 by John Doe

working on folder edits

parent 4612cc91
......@@ -24,3 +24,4 @@ vendor/bundle
spec/cassettes
vagrant_boxes/*.log
vagrant_boxes/.vagrant
coverage
\ No newline at end of file
......@@ -62,6 +62,10 @@ group :development do
gem 'guard-rubocop'
end
group :test do
gem 'simplecov', :require => false
end
group :development do
# Access an IRB console on exception pages or by using <%= console %> in views
gem 'web-console', '~> 2.0'
......@@ -69,4 +73,3 @@ group :development do
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
end
......@@ -81,6 +81,7 @@ GEM
database_cleaner (1.5.3)
debug_inspector (0.0.2)
diff-lcs (1.2.5)
docile (1.1.5)
erubis (2.7.0)
execjs (2.7.0)
factory_girl (4.7.0)
......@@ -238,6 +239,11 @@ GEM
json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0)
shellany (0.0.1)
simplecov (0.12.0)
docile (~> 1.1.0)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
slop (3.6.0)
spring (1.7.2)
spring-commands-rspec (1.0.4)
......@@ -303,6 +309,7 @@ DEPENDENCIES
rubocop
sass-rails (~> 5.0)
sdoc (~> 0.4.0)
simplecov
spring
spring-commands-rspec
sqlite3
......
......@@ -36,21 +36,50 @@ class DbAdapter
end
end
def set_folder_metadata(db_folder)
params = { path: "#{db_folder.path}/info",
data: __build_folder_metadata(db_folder) }.to_json
response = self.class.post("#{@url}/stream/update_metadata",
body: params,
headers: { 'Content-Type' => 'application/json' })
if response.code != 200
Rails.logger.warn (
"#{@url}: update_metadata(#{db_folder.path})"+
" => #{response.code}:#{response.body}"
)
return { error: true, msg: "error updating #{db_folder.path} metadata" }
end
{ error: false, msg: 'success' }
end
# convert folder attributes to __config_key json
def __build_folder_metadata(db_folder)
attribs = db_folder.attributes
.slice('name', 'description', 'hidden')
.to_json
{ config_key__: attribs }.to_json
end
# retrieve metadata for a particular stream
def __get_metadata(path)
dump = self.class.get("#{@url}/stream/get_metadata?path=#{path}")
metadata = JSON.parse(dump.parsed_response['config_key__'] || '{}')
# Add plain-text metadata keys (retrofit for *info streams which keep
# attributes in seperate metadata tags
metadata.merge!(dump.parsed_response)
# find legacy parameters in raw metadata
metadata = dump.parsed_response.except('config_key__')
# parse values from config_key entry if it exists
config_key = JSON.parse(dump.parsed_response['config_key__'] || '{}')
# merge legacy data with config_key values
metadata.merge!(config_key)
# make sure nothing bad got in (eg extraneous metadata keys)
__sanitize_metadata(metadata)
end
# make sure all the keys are valid parameters
# this function does not know the difference between folders and streams
# this *should* be ok as long as nobody tinkers with the config_key__ entries
def __sanitize_metadata(metadata)
metadata.slice!('delete_locked', 'description', 'hidden', 'name',
'streams')
if(metadata['streams'] != nil)
metadata.slice!('delete_locked', 'description', 'hidden',
'name', 'name_abbrev', 'streams')
unless metadata['streams'].nil?
# sanitize 'streams' (elements) parameters
element_attrs = DbElement.attribute_names.map(&:to_sym)
metadata['streams'].map! do |element|
......
......@@ -7,10 +7,14 @@ class DbFoldersController < ApplicationController
render json: folder, shallow: false
end
#TODO: add db attribute to folders and streams
#TODO: add timespan and disk usage stats to folders
#TODO: create info stream on folders on edit
def update
folder = DbFolder.find(params[:id])
folder.update!(folder_params)
render json: folder
adapter = DbAdapter.new(folder.db.url)
service = EditFolder.new(adapter)
render json: service.run(folder, params)
end
private
......
......@@ -12,6 +12,8 @@ class DbFolder < ActiveRecord::Base
has_many :db_streams,
dependent: :destroy
validates_presence_of :name
def self.defined_attributes
[:name, :description, :hidden]
end
......
......@@ -9,25 +9,25 @@ class EditFolder
@db_adapter = db_adapter
end
def run(db_stream, **attribs)
def run(db_folder, **attribs)
# only accept valid attributes
attribs.slice!([:name, :description])
attribs.slice!(:name, :description, :hidden)
# assign the new attributes and check if the
# result is valid (eg stream's can't have the same name)
db_stream.assign_attributes(attribs)
unless db_stream.valid?
add_error(db_stream.errors)
# result is valid (eg folder's can't have the same name)
db_folder.assign_attributes(attribs)
unless db_folder.valid?
add_error(db_folder.errors)
return self
end
# local model checks out, update the remote NilmDB
@db_adapter.update_metadata(db_stream.path, attribs)
status = @db_adapter.set_folder_metadata(db_folder)
# if there was an error don't save the model
if db_adapter.status == ERROR
add_error(db_adapter.error_msg)
if status[:error]
add_error(status[:msg])
return self
end
# everything went well, save the model
db_stream.save!
db_folder.save!
self
end
end
......@@ -3,10 +3,10 @@
require 'rails_helper'
describe DbAdapter do
it 'retrieves basic schema', :vcr do
# use the vagrant box loaded with example database
db = double(url: 'http://localhost:8080/nilmdb')
adapter = DbAdapter.new(db.url)
let (:url) {'http://localhost:8080/nilmdb'}
it 'retrieves basic schema', :vcr do
adapter = DbAdapter.new(url)
adapter.schema.each do |entry|
expect(entry).to include(:path, :attributes)
expect(entry[:attributes]).to(
......@@ -15,5 +15,21 @@ describe DbAdapter do
)
end
end
describe 'set_folder_metadata' do
it 'updates config_key in metadata', :vcr do
adapter = DbAdapter.new(url)
folder = DbFolder.new(path: '/tutorial',
name: 'test', description: 'new')
result = adapter.set_folder_metadata(folder)
expect(result[:error]).to be false
end
it 'returns error on server failure', :vcr do
adapter = DbAdapter.new(url)
folder = DbFolder.new(path: '/badpath')
result = adapter.set_folder_metadata(folder)
expect(result[:error]).to be true
expect(result[:msg]).to match(/badpath/)
end
end
end
......@@ -38,4 +38,12 @@ RSpec.describe 'DbFolder' do
expect(new_stream.db_folder).to eq(db_folder)
end
end
describe 'validation' do
let(:db_folder) { FactoryGirl.create(:db_folder) }
it 'forbids an empty name' do
db_folder.name = ''
expect(db_folder.valid?).to be false
end
end
end
......@@ -3,15 +3,43 @@
require 'rails_helper'
describe 'EditFolder service' do
let(:mock_adapter) {}
let(:service) { EditFolder.new(mock_adapter) }
let(:db_adapter) { instance_double(DbAdapter) }
let(:folder) { DbFolder.new(path: '/folder/path', name: 'old') }
let(:service) { EditFolder.new(db_adapter) }
# db adapter return values
let(:success) { { error: false, msg: '' } }
let(:error) { { error: true, msg: 'server error' } }
it 'changes folder attributes' do
folder = DbFolder.new(name: 'old')
service.run(folder, name: 'new')
expect(mock_adapter).to be called once
attribs = { id: 0, invalid_attrib: 'ignore',
name: 'new', description: 'updated' }
allow(folder).to receive(:save!)
allow(db_adapter).to receive(:set_folder_metadata).and_return(success)
# run the service, it should call the adapter and save the folder
service.run(folder, attribs)
expect(db_adapter).to have_received(:set_folder_metadata).with(folder)
expect(folder.name).to eq('new')
expect(folder.description).to eq('updated')
expect(folder).to have_received(:save!)
end
it 'does not change folder on a server error'
it 'checks to make sure new attributes are valid' do
attribs = { name: '' } # cannot have empty name
allow(db_adapter).to receive(:set_folder_metadata).and_return(success)
# run the service, it shouldn't call the database adapter
service.run(folder, attribs)
expect(service.errors?).to be true
expect(db_adapter).to_not have_received(:set_folder_metadata)
end
it 'does not change folder on a server error' do
attribs = { name: 'new' }
allow(db_adapter).to receive(:set_folder_metadata).and_return(error)
allow(folder).to receive(:save!)
# run the service, it shouldn't save the folder object
service.run(folder, attribs)
expect(service.errors?).to be true
expect(folder).to_not have_received(:save!)
end
end
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'InsertFile' do
describe 'insert_file' do
RSpec.describe 'InsertStream' do
describe 'insert_stream' do
# mock the DbService and DbBuilder
let(:db_service) { double(create_file: true) }
let(:db_service) { double(create_stream: true) }
let(:db_builder) { double(build_path: '/test/file') }
# a file to insert
let(:new_file) { FactoryGirl.build_stubbed(:db_file) }
# a stream to insert
let(:new_stream) { FactoryGirl.build_stubbed(:db_stream) }
# a folder to insert it in
let(:parent_folder) { FactoryGirl.build_stubbed(:db_folder) }
it 'adds the given file to the folder' do
file_inserter = InsertFile.new(db_service: db_service,
it 'adds the given stream to the folder' do
stream_inserter = InsertStream.new(db_service: db_service,
db_builder: db_builder)
file_inserter.insert_file(folder: parent_folder, file: new_file)
expect(new_file.db_folder).to eq(parent_folder)
stream_inserter.insert_stream(folder: parent_folder, stream: new_stream)
expect(new_stream.db_folder).to eq(parent_folder)
end
it 'does not add the file if the db_service fails'
end
end
......@@ -17,6 +17,8 @@
# users commonly want.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
require 'simplecov'
SimpleCov.start
require 'webmock/rspec'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment