Commit 1d1f99a6 by source_reader

added unittests for annotations

parent a36a75d5
module Joule
class Adapter
attr_accessor :backend
def initialize(url, key)
@backend = Backend.new(url, key)
......@@ -58,21 +59,36 @@ module Joule
@backend.module_post_interface(joule_module, req)
end
# === ANNOTATIONS ===
def create_annotation(annotation)
# returns an Annotation object
@backend.create_annotation(annotation)
end
def get_annotations(db_stream)
resp = @backend.get_annotations(db_stream.joule_id)
annotations = resp[:result]
annotations.each do |annotation|
annotation[:db_stream_id] = db_stream.id
# returns an array of Annotation objects
annotation_json = @backend.get_annotations(db_stream.joule_id)
annotations = []
annotation_json.each do |json|
annotation = Annotation.new
annotation.id = json["id"]
annotation.title = json["title"]
annotation.content = json["content"]
annotation.start_time = json["start"]
annotation.end_time = json["end"]
# ignore joule stream_id parameter
# use the db_stream model instead
annotation.db_stream = db_stream
annotations.push(annotation)
end
annotations
end
def delete_annotation(annotation_id)
resp = @backend.delete_annotation(annotation_id)
# returns nil
@backend.delete_annotation(annotation_id)
end
# === END ANNOTATIONS ===
def node_type
'joule'
......
......@@ -174,6 +174,7 @@ module Joule
{ error: false, msg: 'success' }
end
# === ANNOTATION METHODS ===
def create_annotation(annotation)
data = {
'stream_id': annotation.db_stream.joule_id,
......@@ -182,19 +183,15 @@ module Joule
'start': annotation.start_time,
'end': annotation.end_time}
begin
response = self.class.post("#{@url}/annotation.json",
resp = self.class.post("#{@url}/annotation.json",
headers: { 'Content-Type' => 'application/json' },
body: data.to_json)
raise "error creating annotations #{resp.body}" unless resp.success?
rescue
return { error: true, msg: 'cannot contact Joule server' }
end
unless response.success?
puts "#########"
puts response.body
return { error: true, msg: "error creating annotation" }
raise "connection error"
end
annotation.id = response.parsed_response["id"]
{ error: false, msg: 'success' }
annotation.id = resp.parsed_response["id"]
annotation
end
def get_annotations(stream_id)
......@@ -202,13 +199,11 @@ module Joule
options = { query: query}
begin
resp = self.class.get("#{@url}/annotations.json", options)
return {success: false, result: resp.body} unless resp.success?
raise "error loading annotations #{resp.body}" unless resp.success?
rescue
return {success: false, result: "connection error"}
raise "connection error"
end
annotations = resp.parsed_response
{success: true, result: annotations}
resp.parsed_response
end
def delete_annotation(annotation_id)
......@@ -217,10 +212,12 @@ module Joule
begin
resp = self.class.delete("#{@url}/annotation.json",
options)
return {success: false, result: resp.body} unless resp.success?
raise "error deleting annotation #{resp.body}" unless resp.success?
rescue
return {success: false, result: "connection error"}
raise "connection error"
end
end
# === END ANNOTATION METHODS ===
end
end
......@@ -7,44 +7,51 @@ class AnnotationsController < ApplicationController
# GET /stream/:stream_id/annotations.json
def index
annotations = @node_adapter.get_annotations(@db_stream)
@service = StubService.new
render json: annotations, status: @service.success? ? :ok : :unprocessable_entity
begin
@annotations = @node_adapter.get_annotations(@db_stream)
rescue RuntimeError => e
@service.add_error("Cannot retrieve annotations [#{e}]")
render 'helpers/empty_response', status: :unprocessable_entity
end
end
# POST /annotations.json
def create
@annotation = Annotation.new
@annotation.title = params[:title]
@annotation.content = params[:content]
@annotation.db_stream = @db_stream
@annotation.start_time = params[:start]
@annotation.end_time = params[:end]
status = @node_adapter.create_annotation(@annotation)
@service = StubService.new
render :show, status: @service.success? ? :ok : :unprocessable_entity
end
annotation = Annotation.new
annotation.title = params[:title]
annotation.content = params[:content]
annotation.db_stream = @db_stream
annotation.start_time = params[:start].to_i
unless params[:end].nil?
annotation.end_time = params[:end].to_i
end
# PATCH/PUT /annotations/1.json
def update
@service = EditAnnotation.new(@node_adapter)
@service.run(params[:id], annotation_params)
render status: @service.success? ? :ok : :unprocessable_entity
@service = StubService.new
begin
@node_adapter.create_annotation(annotation)
rescue RuntimeError => e
@service.add_error("Cannot create annotation [#{e}]")
render 'helpers/empty_response', status: :unprocessable_entity and return
end
@annotations = [annotation]
render :index
end
# DELETE /annotations/1.json
def destroy
status = @node_adapter.delete_annotation(params[:id])
@service = StubService.new
render 'helpers/empty_response', status: :ok
begin
@node_adapter.delete_annotation(params[:id].to_i)
rescue RuntimeError => e
@service.add_error("Cannot delete annotation [#{e}]")
render 'helpers/empty_response', status: :unprocessable_entity and return
end
render 'helpers/empty_response'
end
private
def annotation_params
params.permit(:title, :content, :start, :end, :db_stream_id)
end
def set_stream
@db_stream = DbStream.find(params[:db_stream_id])
@db = @db_stream.db
......
......@@ -6,4 +6,8 @@ class Annotation
attr_accessor :start_time
attr_accessor :end_time
attr_accessor :db_stream
def self.json_keys
[:id, :title, :content]
end
end
\ No newline at end of file
# frozen_string_literal: true
class CreateAnnotation
include ServiceStatus
attr_reader :nilm
def initialize(node_adapter)
super()
@node_adapter = node_adapter
end
def run(db_stream, annotation)
status = @node_adapter.create_annotation(@annotation)
# if there was an error don't save the model
if status[:error]
add_error(status[:msg])
return self
end
add_warnings(msgs.errors + msgs.warnings)
add_notice('Created annotation')
self
end
end
json.data do
json.array!(@annotations) do |annotation|
json.extract! annotation, *Annotation.json_keys
json.start annotation.start_time
json.end annotation.end_time
json.db_stream_id annotation.db_stream.id
end
end
json.partial! "helpers/messages", service: @service
\ No newline at end of file
json.data do
json.id @annotation.id
json.title @annotation.title
json.content @annotation.content
json.start @annotation.start_time
json.end @annotation.end_time
json.db_stream_id @db_stream.id
end
json.partial! "helpers/messages", service: @service
\ No newline at end of file
# frozen_string_literal: true
require 'rails_helper'
describe Joule::Adapter do
it 'creates annotations' do
annotation = Annotation.new
annotation.title = "test"
adapter = Joule::Adapter.new("url", "key")
mock_backend = instance_double(Joule::Backend)
adapter.backend = mock_backend
expect(mock_backend).to receive(:create_annotation) { annotation }
resp = adapter.create_annotation(annotation)
expect(resp).to eq annotation
end
it 'gets annotations' do
adapter = Joule::Adapter.new("url", "key")
mock_backend = instance_double(Joule::Backend)
adapter.backend = mock_backend
raw = File.read(File.dirname(__FILE__)+"/annotations.json")
json = JSON.parse(raw)
expect(mock_backend).to receive(:get_annotations) { json }
stream = FactoryBot.create(:db_stream, name: 'test_stream')
annotations = adapter.get_annotations(stream)
expect(annotations.length).to eq 6
annotations.each do | annotation |
expect(annotation.db_stream).to be stream
end
end
it 'deletes annotations' do
adapter = Joule::Adapter.new("url", "key")
mock_backend = instance_double(Joule::Backend)
adapter.backend = mock_backend
expect(mock_backend).to receive(:delete_annotation)
resp = adapter.delete_annotation(3)
end
end
\ No newline at end of file
[
{
"id": 3,
"title": "Instant",
"content": "instant temperature",
"start": 1561752347819968,
"stream_id": 2646,
"end": null
},
{
"id": 22,
"title": "hot!!!",
"content": "",
"start": 1561861116610000,
"stream_id": 2646,
"end": 1561862838572000
},
{
"id": 23,
"title": "something else",
"content": "this is something new",
"start": 1561863245618000,
"stream_id": 2646,
"end": 1561863575876000
},
{
"id": 26,
"title": "gim",
"content": "",
"start": 1561860893040785,
"stream_id": 2646,
"end": null
},
{
"id": 28,
"title": "event hotter",
"content": "too hot!",
"start": 1561753681898272,
"stream_id": 2646,
"end": null
},
{
"id": 29,
"title": "wide range",
"content": null,
"start": 1561839624945000,
"stream_id": 2646,
"end": 1561930090469000
}
]
\ No newline at end of file
......@@ -44,4 +44,47 @@ describe Joule::Backend do
expect(resp[:result][:data].count).to be > 0
expect(resp[:result][:data].count).to be < 200
end
describe "Annotations" do
let(:url) { "https://172.34.31.8:8088"}
let(:key) { "cR0JqqTM8bizW73MY1IAHCPJUTwDmOdunhYK9b2VQ98"}
describe "get_annotations" do
it 'loads annotations', :vcr do
backend = Joule::Backend.new(url, key)
annotations = backend.get_annotations(2646)
# should have 6 annotations, first one is an event
expect(annotations[0]["end"]).to be nil
expect(annotations.length).to eq 6
end
it 'handles errors', :vcr do
backend = Joule::Backend.new(url, key)
# server was stopped for this request
expect{backend.get_annotations(101)}.to raise_error(RuntimeError)
end
end
describe "delete_annotation" do
it 'deletes annotations', :vcr do
backend = Joule::Backend.new(url, key)
annotations = backend.get_annotations(2646)
num_annotations = annotations.length
backend.delete_annotation(28)
annotations = backend.get_annotations(2646)
new_num_annotations = annotations.length
expect(new_num_annotations).to equal num_annotations-1
end
end
describe "create_annotation" do
it 'creates annotations', :vcr do
backend = Joule::Backend.new(url, key)
stream = FactoryBot.create(:db_stream, name: 'test_stream')
stream.joule_id = 2646
annotation = FactoryBot.build(:annotation, db_stream: stream)
backend.create_annotation(annotation)
expect(annotation.id).to_not be nil
end
end
end
end
......@@ -2,7 +2,7 @@
{
"name": "Module3",
"description": "a filter",
"has_interface": true,
"is_app": true,
"inputs": {
"input1": "/folder_1/stream_1_1",
"input2": "/folder_1/stream_1_2"
......@@ -20,7 +20,7 @@
{
"name": "Module2",
"description": "a reader",
"has_interface": false,
"is_app": false,
"inputs": {},
"outputs": {
"output": "/folder_1/stream_1_2"
......@@ -35,7 +35,7 @@
{
"name": "Module1",
"description": "a reader",
"has_interface": true,
"is_app": true,
"inputs": {},
"outputs": {
"output": "/folder_1/stream_1_1"
......@@ -50,7 +50,7 @@
{
"name": "Module4",
"description": "a filter",
"has_interface": false,
"is_app": false,
"inputs": {
"input1": "/folder_1/stream_1_1",
"input2": "/folder_2/stream_2_1"
......
---
http_interactions:
- request:
method: post
uri: https://172.34.31.8:8088/annotation.json
body:
encoding: UTF-8
string: '{"stream_id":2646,"title":"aut ullam tempore","content":"Accusamus
qui quam optio.","start":1161,"end":3182}'
headers:
X-Api-Key:
- cR0JqqTM8bizW73MY1IAHCPJUTwDmOdunhYK9b2VQ98
Content-Type:
- application/json
response:
status:
code: 200
message: OK
headers:
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '127'
Date:
- Thu, 04 Jul 2019 01:01:23 GMT
Server:
- Python/3.6 aiohttp/3.5.4
body:
encoding: UTF-8
string: '{"id": 30, "title": "aut ullam tempore", "content": "Accusamus qui
quam optio.", "start": 1161, "stream_id": 2646, "end": 3182}'
http_version:
recorded_at: Thu, 04 Jul 2019 01:01:23 GMT
recorded_with: VCR 4.0.0
---
http_interactions:
- request:
method: get
uri: https://172.34.31.8:8088/annotations.json?stream_id=2646
body:
encoding: US-ASCII
string: ''
headers:
X-Api-Key:
- cR0JqqTM8bizW73MY1IAHCPJUTwDmOdunhYK9b2VQ98
response:
status:
code: 200
message: OK
headers:
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '457'
Date:
- Thu, 04 Jul 2019 01:01:23 GMT
Server:
- Python/3.6 aiohttp/3.5.4
body:
encoding: UTF-8
string: '[{"id": 22, "title": "hot!!!", "content": "", "start": 1561861116610000,
"stream_id": 2646, "end": 1561862838572000}, {"id": 26, "title": "gim", "content":
"", "start": 1561860893040785, "stream_id": 2646, "end": null}, {"id": 28,
"title": "tpp jhpt", "content": "too hot!", "start": 1561753681898272, "stream_id":
2646, "end": null}, {"id": 29, "title": "wide range", "content": null, "start":
1561839624945000, "stream_id": 2646, "end": 1561930090469000}]'
http_version:
recorded_at: Thu, 04 Jul 2019 01:01:23 GMT
- request:
method: delete
uri: https://172.34.31.8:8088/annotation.json?id=28
body:
encoding: US-ASCII
string: ''
headers:
X-Api-Key:
- cR0JqqTM8bizW73MY1IAHCPJUTwDmOdunhYK9b2VQ98
response:
status:
code: 200
message: OK
headers:
Content-Type:
- text/plain; charset=utf-8
Content-Length:
- '2'
Date:
- Thu, 04 Jul 2019 01:01:23 GMT
Server:
- Python/3.6 aiohttp/3.5.4
body:
encoding: UTF-8
string: ok
http_version:
recorded_at: Thu, 04 Jul 2019 01:01:23 GMT
- request:
method: get
uri: https://172.34.31.8:8088/annotations.json?stream_id=2646
body:
encoding: US-ASCII
string: ''
headers:
X-Api-Key:
- cR0JqqTM8bizW73MY1IAHCPJUTwDmOdunhYK9b2VQ98
response:
status:
code: 200
message: OK
headers:
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '342'
Date:
- Thu, 04 Jul 2019 01:01:23 GMT
Server:
- Python/3.6 aiohttp/3.5.4
body:
encoding: UTF-8
string: '[{"id": 22, "title": "hot!!!", "content": "", "start": 1561861116610000,
"stream_id": 2646, "end": 1561862838572000}, {"id": 26, "title": "gim", "content":
"", "start": 1561860893040785, "stream_id": 2646, "end": null}, {"id": 29,
"title": "wide range", "content": null, "start": 1561839624945000, "stream_id":
2646, "end": 1561930090469000}]'
http_version:
recorded_at: Thu, 04 Jul 2019 01:01:23 GMT
recorded_with: VCR 4.0.0
---
http_interactions:
- request:
method: get
uri: https://172.34.31.8:8088/annotations.json?stream_id=101
body:
encoding: US-ASCII
string: ''
headers:
X-Api-Key:
- cR0JqqTM8bizW73MY1IAHCPJUTwDmOdunhYK9b2VQ98
response:
status:
code: 500
message: Mock Error
headers:
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '2'
Date:
- Wed, 03 Jul 2019 18:36:54 GMT
Server:
- Python/3.6 aiohttp/3.5.4
body:
encoding: UTF-8
string: "mock error"
http_version:
recorded_at: Wed, 03 Jul 2019 18:36:54 GMT
recorded_with: VCR 4.0.0
---
http_interactions:
- request:
method: get
uri: https://172.34.31.8:8088/annotations.json?stream_id=2646
body:
encoding: US-ASCII
string: ''
headers:
X-Api-Key:
- cR0JqqTM8bizW73MY1IAHCPJUTwDmOdunhYK9b2VQ98
response:
status:
code: 200
message: OK
headers:
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '727'
Date:
- Wed, 03 Jul 2019 18:35:18 GMT
Server:
- Python/3.6 aiohttp/3.5.4
body:
encoding: UTF-8
string: '[{"id": 3, "title": "Instant", "content": "instant temperature", "start":
1561752347819968, "stream_id": 2646, "end": null}, {"id": 22, "title": "hot!!!",
"content": "", "start": 1561861116610000, "stream_id": 2646, "end": 1561862838572000},
{"id": 23, "title": "something else", "content": "this is something new",
"start": 1561863245618000, "stream_id": 2646, "end": 1561863575876000}, {"id":
26, "title": "gim", "content": "", "start": 1561860893040785, "stream_id":
2646, "end": null}, {"id": 28, "title": "tpp jhpt", "content": "too hot!",
"start": 1561753681898272, "stream_id": 2646, "end": null}, {"id": 29, "title":
"wide range", "content": null, "start": 1561839624945000, "stream_id": 2646,
"end": 1561930090469000}]'
http_version:
recorded_at: Wed, 03 Jul 2019 18:35:19 GMT
recorded_with: VCR 4.0.0
---
http_interactions:
- request:
method: get
uri: https://172.34.31.8:8088/annotations.json?stream_id=2646
body:
encoding: US-ASCII
string: ''
headers:
X-Api-Key:
- cR0JqqTM8bizW73MY1IAHCPJUTwDmOdunhYK9b2VQ98
response:
status:
code: 200
message: OK
headers:
Content-Type:
- application/json; charset=utf-8
Content-Length:
- '727'
Date:
- Wed, 03 Jul 2019 18:22:59 GMT
Server:
- Python/3.6 aiohttp/3.5.4
body:
encoding: UTF-8
string: '[{"id": 3, "title": "Instant", "content": "instant temperature", "start":
1561752347819968, "stream_id": 2646, "end": null}, {"id": 22, "title": "hot!!!",
"content": "", "start": 1561861116610000, "stream_id": 2646, "end": 1561862838572000},
{"id": 23, "title": "something else", "content": "this is something new",
"start": 1561863245618000, "stream_id": 2646, "end": 1561863575876000}, {"id":
26, "title": "gim", "content": "", "start": 1561860893040785, "stream_id":
2646, "end": null}, {"id": 28, "title": "tpp jhpt", "content": "too hot!",
"start": 1561753681898272, "stream_id": 2646, "end": null}, {"id": 29, "title":
"wide range", "content": null, "start": 1561839624945000, "stream_id": 2646,
"end": 1561930090469000}]'
http_version:
recorded_at: Wed, 03 Jul 2019 18:22:59 GMT
recorded_with: VCR 4.0.0
require 'rails_helper'
RSpec.describe AnnotationsController, type: :controller do
RSpec.describe AnnotationsController, type: :request do
let(:owner) { create(:user, first_name: 'Owner') }
let(:admin) { create(:user, first_name: 'Admin')}
let(:viewer) { create(:user, first_name: 'Viewer')}
let(:user) { create(:user, first_name: 'User')}
let(:nilm) do create(:nilm, name: "Test NILM", node_type: 'joule',
admins: [admin], owners: [owner], viewers: [viewer])
end
let(:db) {create(:db, nilm: nilm)}
let(:stream) {create(:db_stream, db: db)}
describe 'GET #annotations' do
# retrieve annotations for a given stream
context 'with authorized user' do
it 'returns all annotations' do
annotations = build_list(:annotation, 10, db_stream: stream)
mock_adapter = instance_double(Joule::Adapter)
expect(mock_adapter).to receive(:get_annotations).and_return(annotations)
allow(NodeAdapterFactory).to receive(:from_nilm).and_return(mock_adapter)
get "/db_streams/#{stream.id}/annotations.json", headers: user.create_new_auth_token
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body['data'].length).to eq 10
body['data'].each do |annotation|
expect(annotation['db_stream_id']).to eq stream.id
expect(annotation).to include('id', 'title', 'content', 'start', 'end')
end
end
it 'returns error message if backend fails' do
mock_adapter = instance_double(Joule::Adapter)
expect(mock_adapter).to receive(:get_annotations).and_raise(RuntimeError.new('test'))
allow(NodeAdapterFactory).to receive(:from_nilm).and_return(mock_adapter)
get "/db_streams/#{stream.id}/annotations.json", headers: user.create_new_auth_token
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body['messages']['errors']).to include('test')
end
it 'returns error message if backend is not available' do
allow(NodeAdapterFactory).to receive(:from_nilm).and_return(nil)
get "/db_streams/#{stream.id}/annotations.json", headers: user.create_new_auth_token
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body['messages']['errors']).to include('Cannot contact installation')
end
end
context 'without sign-in' do
it 'returns unauthorized' do
get "/db_streams/#{stream.id}/annotations.json"
expect(response).to have_http_status(:unauthorized)
end
end
end
describe 'POST #annotations' do
# create a new annotation for a stream
context 'with owner' do
it 'creates annotations' do
mock_adapter = instance_double(Joule::Adapter)
expect(mock_adapter).to receive(:create_annotation) do |annotation|
expect(annotation.title).to eq "Title"
expect(annotation.content).to eq "Content"
expect(annotation.db_stream.id).to eq stream.id
expect(annotation.start_time).to eq 100
expect(annotation.end_time).to be 200
end
allow(NodeAdapterFactory).to receive(:from_nilm).and_return(mock_adapter)
post "/db_streams/#{stream.id}/annotations.json", headers: owner.create_new_auth_token,
params: {
title: "Title",
content: "Content",
start: 100,
end: 200}
body = JSON.parse(response.body)
expect(body['data'].length).to eq 1
expect(body['data'][0]['title']).to eq 'Title'
end
it 'returns error if backend fails' do
mock_adapter = instance_double(Joule::Adapter)
expect(mock_adapter).to receive(:create_annotation).and_raise(RuntimeError.new('test'))
allow(NodeAdapterFactory).to receive(:from_nilm).and_return(mock_adapter)
post "/db_streams/#{stream.id}/annotations.json", headers: owner.create_new_auth_token
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body['messages']['errors']).to include('test')
end
end
context 'with viewer' do
it 'returns unauthorized' do
post "/db_streams/#{stream.id}/annotations.json", headers: viewer.create_new_auth_token
expect(response).to have_http_status(:unauthorized)
end
end
context 'with anyone else' do
it 'returns unauthorized' do
post "/db_streams/#{stream.id}/annotations.json", headers: user.create_new_auth_token
expect(response).to have_http_status(:unauthorized)
end
end
context 'without sign-in' do
it 'returns unauthorized' do
post "/db_streams/#{stream.id}/annotations.json"
expect(response).to have_http_status(:unauthorized)
end
end
end
describe 'DESTROY #annotations' do
# deletes specified annotation
context 'with owner' do
it 'deletes the annotation' do
mock_adapter = instance_double(Joule::Adapter)
expect(mock_adapter).to receive(:delete_annotation) do |id|
expect(id).to eq 10
end
allow(NodeAdapterFactory).to receive(:from_nilm).and_return(mock_adapter)
delete "/db_streams/#{stream.id}/annotations/10.json",
headers: owner.create_new_auth_token
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body['messages']['errors'].empty?).to be true
end
it 'returns error if backend fails' do
mock_adapter = instance_double(Joule::Adapter)
expect(mock_adapter).to receive(:delete_annotation).and_raise(RuntimeError.new('test'))
allow(NodeAdapterFactory).to receive(:from_nilm).and_return(mock_adapter)
delete "/db_streams/#{stream.id}/annotations/10.json", headers: owner.create_new_auth_token
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body['messages']['errors']).to include('test')
end
end
context 'with viewer' do
it 'returns unauthorized' do
delete "/db_streams/#{stream.id}/annotations/10.json", headers: viewer.create_new_auth_token
expect(response).to have_http_status(:unauthorized)
end
end
context 'with anyone else' do
it 'returns unauthorized' do
delete "/db_streams/#{stream.id}/annotations/10.json", headers: user.create_new_auth_token
expect(response).to have_http_status(:unauthorized)
end
end
context 'without sign-in' do
it 'returns unauthorized' do
delete "/db_streams/#{stream.id}/annotations/10.json"
expect(response).to have_http_status(:unauthorized)
end
end
end
end
FactoryBot.define do
factory :annotation do
title { Faker::Lorem.words(3).join(' ') }
content { Faker::Lorem.sentence }
start_time { Faker::Number.between(1000,2000) }
end_time { Faker::Number.between(3000,4000)}
end
end
\ No newline at end of file
......@@ -24,7 +24,7 @@ require 'simplecov-console'
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([
SimpleCov::Formatter::HTMLFormatter,
SimpleCov::Formatter::Console,
#SimpleCov::Formatter::Console,
])
SimpleCov.start 'rails' do
add_group "Models", "app/models"
......
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