diff --git a/.gitignore b/.gitignore index 288c5a2d..214def79 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,11 @@ /app/assets/builds/* !/app/assets/builds/.keep + +/coverage + /node_modules +/doc +/logs + +/.idea diff --git a/.rspec b/.rspec new file mode 100644 index 00000000..82b8369c --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper \ No newline at end of file diff --git a/.ruby-version b/.ruby-version index 849c0c47..a603bb50 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-2.7.5 +2.7.5 diff --git a/Gemfile b/Gemfile index b4f7b825..2facfb93 100644 --- a/Gemfile +++ b/Gemfile @@ -70,3 +70,15 @@ group :test do gem "selenium-webdriver" gem "webdrivers" end + +gem 'rspec', '~> 3.12' + +gem "simplecov", "~> 0.22.0", :group => :test, :require => false + +gem "simplecov_json_formatter", "~> 0.1.4", :group => :test, :require => false + +gem "rspec-rails", "~> 6.1", :groups => [:development, :test] + +gem "rubycritic", require: false + +gem "rdoc" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index f5dbc2bb..aa9658c9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -76,6 +76,11 @@ GEM tzinfo (~> 2.0) addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) + ast (2.4.2) + axiom-types (0.1.1) + descendants_tracker (~> 0.0.4) + ice_nine (~> 0.11.0) + thread_safe (~> 0.3, >= 0.3.1) base64 (0.2.0) bigdecimal (3.1.4) bindex (0.8.1) @@ -94,6 +99,8 @@ GEM capybara-screenshot (1.0.26) capybara (>= 1.0, < 4) launchy + coercible (1.0.0) + descendants_tracker (~> 0.0.1) concurrent-ruby (1.2.2) connection_pool (2.4.1) crass (1.0.6) @@ -139,15 +146,28 @@ GEM debug (1.8.0) irb (>= 1.5.0) reline (>= 0.3.1) + descendants_tracker (0.0.4) + thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.5.0) + docile (1.4.0) drb (2.2.0) ruby2_keywords erubi (1.12.0) ffi (1.16.3) + flay (2.13.1) + erubi (~> 1.10) + path_expander (~> 1.0) + ruby_parser (~> 3.0) + sexp_processor (~> 4.0) + flog (4.8.0) + path_expander (~> 1.0) + ruby_parser (~> 3.1, > 3.1.0) + sexp_processor (~> 4.8) globalid (1.2.1) activesupport (>= 6.1) i18n (1.14.1) concurrent-ruby (~> 1.0) + ice_nine (0.11.2) io-console (0.6.0) irb (1.8.3) rdoc @@ -157,6 +177,7 @@ GEM activesupport (>= 5.0.0) jsbundling-rails (1.2.1) railties (>= 6.0.0) + kwalify (0.7.2) launchy (2.5.2) addressable (~> 2.8) loofah (2.21.4) @@ -169,6 +190,7 @@ GEM net-smtp marcel (1.0.2) matrix (0.4.2) + metric_fu-Saikuro (1.1.3) mime-types (3.5.1) mime-types-data (~> 3.2015) mime-types-data (3.2023.1003) @@ -193,6 +215,10 @@ GEM racc (~> 1.4) nokogiri (1.15.4-x86_64-linux) racc (~> 1.4) + parser (3.2.2.4) + ast (~> 2.4.1) + racc + path_expander (1.1.1) psych (5.1.1.1) stringio public_suffix (5.0.3) @@ -236,19 +262,66 @@ GEM rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) + rainbow (3.1.1) rake (13.1.0) rdoc (6.6.0) psych (>= 4.0.0) + reek (6.1.4) + kwalify (~> 0.7.0) + parser (~> 3.2.0) + rainbow (>= 2.0, < 4.0) regexp_parser (2.8.2) reline (0.4.0) io-console (~> 0.5) rexml (3.2.6) + rspec (3.12.0) + rspec-core (~> 3.12.0) + rspec-expectations (~> 3.12.0) + rspec-mocks (~> 3.12.0) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.6) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-rails (6.1.0) + actionpack (>= 6.1) + activesupport (>= 6.1) + railties (>= 6.1) + rspec-core (~> 3.12) + rspec-expectations (~> 3.12) + rspec-mocks (~> 3.12) + rspec-support (~> 3.12) + rspec-support (3.12.1) ruby2_keywords (0.0.5) + ruby_parser (3.20.3) + sexp_processor (~> 4.16) + rubycritic (4.9.0) + flay (~> 2.13) + flog (~> 4.7) + launchy (>= 2.5.2) + parser (>= 3.2.2.1) + rainbow (~> 3.1.1) + reek (~> 6.0, < 7.0) + rexml + ruby_parser (~> 3.20) + simplecov (>= 0.22.0) + tty-which (~> 0.5.0) + virtus (~> 2.0) rubyzip (2.3.2) selenium-webdriver (4.9.0) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) + sexp_processor (4.17.0) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.12.3) + simplecov_json_formatter (0.1.4) sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) @@ -265,13 +338,19 @@ GEM sys-uname (1.2.3) ffi (~> 1.1) thor (1.3.0) + thread_safe (0.3.6) timeout (0.4.1) + tty-which (0.5.0) turbo-rails (1.5.0) actionpack (>= 6.0.0) activejob (>= 6.0.0) railties (>= 6.0.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) + virtus (2.0.0) + axiom-types (~> 0.1) + coercible (~> 1.0) + descendants_tracker (~> 0.0, >= 0.0.3) web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -303,9 +382,16 @@ DEPENDENCIES debug jbuilder jsbundling-rails + metric_fu-Saikuro (~> 1.1, >= 1.1.3) puma (>= 5.0) rails (~> 7.1.1) + rdoc + rspec (~> 3.12) + rspec-rails (~> 6.1) + rubycritic selenium-webdriver + simplecov (~> 0.22.0) + simplecov_json_formatter (~> 0.1.4) sprockets-rails sqlite3 (~> 1.4) stimulus-rails diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb new file mode 100644 index 00000000..b1db89ed --- /dev/null +++ b/app/controllers/graph_controller.rb @@ -0,0 +1,190 @@ +require 'json' + +class GraphController < ApplicationController + # Recebe um experimento do banco de dados, + # recolhe o log e retorna json com skills executadas. + def skillsGet + test_id = params[:id] # pega id da url referente ao log + @trials = TrialExecution.find_by(id: test_id) + started = false # boolean pra controle de quando começa o experimento + finished = false # boolean pra controle de quando termina o experimento + + isNav = true # boolean para controle de destino da navigation + navigationList = [] # guarda info das linhas de navigation + + json_data = [] + json_id = [] + + # Identifica linha de navegação ("navigation") e bota no json ("json_data") + # "navigationList" é uma lista identificativa do destino (room ou lab) + # + # "10.06, [INFO], robot6, {'y': 18.901, 'x': -33.896, 'yaw': -3.141}, None, None" + # # => { "time" => 10.06, "message" => Navigation to room} + def navigationLine(navigation, navigationList, json_data) # referente à linha de navigation + time = navigation[1].to_f + json_data << { "time" => time, "message" => "Navigation #{navigationList[0]}"} + end + + # Identifica linha de envio/espera de mensagem ("linhaLista") e bota no json (json_data) + # + # "86.29, [info], nurse, sync, received-request, (status=sending-request)" + # # => { "time" => 86.29, "message" => Sending message to nurse} + # + # "86.29, [info], nurse, sync, request-sent, (status=waiting)" + # # => { "time" => 86.29, "message" => Waiting the message get to nurse} + # + # "86.29, [info], nurse, sync, wait-message, (status=message-received)" + # # => { "time" => 86.29, "message" => Message sent to nurse} + def messageLine(linhaLista, json_data) # referente à linha de mensagem + time = linhaLista[0] + case + when linhaLista[5] == '(status=sending-request)' # request de mensagem + json_data << { "time" => time, "message" => "Sending message to #{linhaLista[2]}"} + + when linhaLista[5] == '(status=waiting)' # espera de mensagem + json_data << { "time" => time, "message" => "Waiting the message get to #{linhaLista[2]}"} + + when linhaLista[5] == '(status=message-received)' # mensagem recebida + json_data << { "time" => time, "message" => "Message sent to #{linhaLista[2]}"} + + else + + end + end + + # Identifica linha de sucesso ("linhaLista") e bota no json ("json_data") + # + # "161.70, [WARN], robot6, SUCCESS, None, None" + # # => { "time" => 161.70, "message" => Experiment completed successfully with 161.70 seconds!} + def successLine(linhaLista, json_data) + time = linhaLista[0] + puts "Experiment completed successfully with #{time} seconds!" + json_data << { "time" => time, "message" => "Experiment completed successfully with #{time} seconds!"} + end + + # Identifica linha de falha ("linhaLista") e bota no json ("json_data") + # + # "42.00, [WARN], robot6, NO-SKILL, authenticate_person, authenticate_nurse" + # # => { "time" => 42.00, "message" => Experiment failed with NO-SKILL: authenticate_person!} + # + # "281.18, [WARN], robot5, SKILL-FAILURE, navigation, navto_room" + # # => { "time" => 281.18, "message" => Skill navigation failed.} + # + # "49.07, [WARN], robot3, LOWBATT, None, None" + # # => { "time" => 49.07, "message" => Battery is low.} + def failureLine(linhaLista, json_data) + time = linhaLista[0] + case linhaLista[3] + when 'NO-SKILL' + json_data << { "time" => time, "message" => "Experiment failed with #{linhaLista[3]}: #{linhaLista[4]}."} + + when 'SKILL-FAILURE' + json_data << { "time" => time, "message" => "Skill #{linhaLista[4]} failed."} + + when 'LOWBATT' + json_data << { "time" => time, "message" => "Battery is low."} + end + end + + lines = @trials.log.split("\n") # separa cada linha do log + + lines.each do |line| + linhaLista = line.split(',').map(&:strip) + + if line.include?('ROBOTS_CONFIG') + # posição inicial e final do hash ROBOTS_CONFIG + startIndex = line.index("ROBOTS_CONFIG={") + endIndex = line.index("}", startIndex) + robotsConfigStr = line[startIndex..endIndex] + + # substitui aspas simples por aspas duplas + robotsConfigStr.gsub!("'", "\"") + + # remove "ROBOTS_CONFIG=" e analisa-se como JSON + begin + robotsConfigJson = robotsConfigStr.sub("ROBOTS_CONFIG=", "") + robotsConfigHash = JSON.parse(robotsConfigJson) + rescue + json_data << { "message" => "TIMEOUT"} + break + end + + localPlan = robotsConfigHash['local_plan'] + + c = 0 + localPlan.each do |action| + c += 1 + if action[0] == 'navigation' + + case + when action[2] == 'navto_room' + navigationList.append('to room') + + when action[2] == 'navto_lab' + navigationList.append('to lab') + + else + navigationList.append('to X') + end + + end + end + + else + # montando padrões de linha + start = line.match(/(\d+\.\d+), \[DEBUG\], logger, Simulation open, (\w+), (\w+)/) || line.match(/(\d+\.\d+), \[INFO\], (\w+), {'y': (-?\d+\.\d+), 'x': (-?\d+\.\d+), 'yaw': (-?\d+\.\d+)}, (\w+), (\w+)/) + # === # + navigation = line.match(/(\d+\.\d+), \[INFO\], (\w+), {'battery-level': '(\d+\.\d+)'}, (\w+), (\w+)/) || line.match(/(\d+\.\d+), \[INFO\], (\w+), {'y': (-?\d+\.\d+), 'x': (-?\d+\.\d+), 'yaw': (-?\d+\.\d+)}, (\w+), (\w+)/) + # === # + message = line.match(/(\d+\.\d+), \[info\], (\w+)/) + # === # + success = line.match(/(\d+\.\d+), \[WARN\], (\w+), SUCCESS, (\w+)/) + # === # + timeout = line.match(/\[WARN\], logger, TIMEOUT, (\w+)/) + # === # + failure = line.match(/(\d+\.\d+), \[WARN\], (\w+), SKILL-FAILURE, (\w+)/) || line.match(/(\d+\.\d+), \[WARN\], (\w+), NO-SKILL, (\w+)/) || line.match(/(\d+\.\d+), \[WARN\], (\w+), LOWBATT, (\w+)/) + # === # + + + case + when navigation && started == true # caso a linha seja de navigation + if !isNav + navigationList.delete_at(0) + end + isNav = true + navigationLine(navigation, navigationList, json_data) + + when !navigation && started == true # caso a linha não seja de navigation + isNav = false + if message # se não for navigation, pode ser de mensagem + messageLine(linhaLista, json_data) + end + + if success + successLine(linhaLista, json_data) + end + + if failure + failureLine(linhaLista, json_data) + end + + if timeout + json_data << { "message" => "TIMEOUT"} + end + + when start + started = true + json_data << { "message" => "Experiment started!"} + + end + end + end + + + if @trials + jsonString = JSON.generate(json_data) + render json: jsonString + end + + end +end diff --git a/app/controllers/velocity_controller.rb b/app/controllers/velocity_controller.rb new file mode 100644 index 00000000..ba724dc9 --- /dev/null +++ b/app/controllers/velocity_controller.rb @@ -0,0 +1,41 @@ +require 'json' + +class VelocityController < ApplicationController + def graph + @teste = "teste" + end + + #rota utilizada para adiquirir um JSON contendo as informações de velocidade média a cada período de tempo + def getData + test_id = params[:id] + + #Recebe o log como string e retorna um array contendo apenas as informações de posição + def get_position_data(log_string) + output_array = [] + log_string.split("\n").each do |line| + if (match = line.match(/(\d+\.\d+), \[.*?\], .*?, \{'y': (.*?), 'x': (.*?), 'yaw': (.*?)}/)) + time, y, x, yaw = match.captures + output_array << { 'time' => time.to_f, 'y' => y.to_f, 'x' => x.to_f, 'yaw' => yaw.to_f } + end + end + output_array + end + + #Recebe as informações de posição e retoran um JSON contendo as velocidade médias + def get_speed_data(positon_array) + output_json = {} + positon_array.each_cons(2) do |i, i_next| + output_json[i_next["time"]] = (Math.sqrt((i_next["x"] - i["x"])**2 + (i_next["y"] - i["y"])**2)/(i_next["time"]-i["time"])) + end + output_json + end + + trial = TrialExecution.find_by(id: test_id) + + if((trial == nil) || (trial.log == nil)) + render json: {} + else + render json: get_speed_data(get_position_data(trial.log)) + end + end +end diff --git a/app/javascript/react/src/components/Graph.jsx b/app/javascript/react/src/components/Graph.jsx index 8ae10b09..a15d29d4 100644 --- a/app/javascript/react/src/components/Graph.jsx +++ b/app/javascript/react/src/components/Graph.jsx @@ -1,23 +1,144 @@ import React, {useEffect, useState} from 'react' - -const Graph = (props) => { +import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend } from 'recharts'; + +const Graph = () => { + const pathSegments = window.location.pathname.split('/'); + const id = pathSegments[pathSegments.length - 1]; // pegar ID do log - let [count, setCount] = useState(0) + let [req, setReq] = useState("") useEffect(() => { - fetch("/hello/worldGet").then(async res=>{ + fetch(`/graph/skillsGet/${id}`).then(async res=>{ const parse = await res.text() - console.log(parse) return parse }).then(res=>setReq(res)) }, []) + + return (
-

Counter prop:{props.trialID}: {count}

- +
) -} - -export default Graph +} + +const Component = ({ req }) => { + try { + reqArray = JSON.parse(req); + } catch (error) { + console.error('Erro ao fazer parse da string JSON:', error); + reqArray = []; + } + + semRepLista = [] + errorList = [] + reqArray.forEach(function(key, index){ + switch (index){ + case 0: // primeira message tem que ser start + if(key.message == 'Experiment started!'){ + semRepLista.push({"time": 0.00, "message": "Start!"}) + } + else{ + semRepLista.push({"time": 0.00, "message": "NOT STARTED!"}) // se nao, nao comecou + errorList.push({"time": 0.00, "message": "Error in start"}) + } + break; + + case reqArray.length - 1: // última message tem que ser sucesso + if(key.message.includes('Experiment completed successfully')){ + semRepLista.push({"time": key.time, "message": "Success!"}) + } + + else{ + if(key.message.includes('Skill')){ // ou falhou em alguma skill + errorList.push({"time": key.time, "message": key.message.substring(5)}) + } + + if(key.message.includes('Experiment failed')){ // ou faltou skill + errorList.push({"time": key.time, "message": key.message}) + } + + if(key.message.includes('TIMEOUT')){ // ou deu TIMEOUT + errorList.push({"time": reqArray[index - 1].time, "message": key.message}) + } + + if(key.message.includes('Battery')){ // ou acabou a bateria + errorList.push({"time": reqArray[index - 1].time, "message": key.message}) + } + + else if(errorList.length == 0){ + errorList.push({"time": reqArray[index - 1].time, "message": 'No action taken.'}) + } + } + break; + + default: + if(key.time == reqArray[index+1].time && key.message == reqArray[index+1].message){ + if(semRepLista[semRepLista.length-1].message != key.message){ + semRepLista.push(key) + } + } + + if(key.time == reqArray[index+1].time && key.message != reqArray[index+1].message){ + if(key.message == 'Sending message to nurse' || key.message == 'Waiting the message get to nurse'){ + if(semRepLista[semRepLista.length-1].message != 'Sending message to nurse'){ + semRepLista.push({"time": key.time, "message":"Sending message to nurse"}) + } + } + } + + if(key.message.includes("Message sent to")){ + if(semRepLista[semRepLista.length-1].message != key.message){ + semRepLista.push({"time": key.time, "message":'Message sent!'}) + } + } + + } + }) + + + return ( +
+ + + + + + + + + +
+ {errorList.length > 0 ? ( + errorList.map((item, index) => ( +
+

Experiment failed at {item.time} seconds: {item.message}

+
+ )) + ) : semRepLista.length <= 1 ? ( +

Experimento sem ações!

+ ) : ( +

Sucesso!

+ )} +
+ + +
+ ); +}; + +export default Graph \ No newline at end of file diff --git a/app/javascript/react/src/components/Hello.jsx b/app/javascript/react/src/components/Hello.jsx index 7aa859bf..8a75e836 100644 --- a/app/javascript/react/src/components/Hello.jsx +++ b/app/javascript/react/src/components/Hello.jsx @@ -1,8 +1,8 @@ import React, {useEffect, useState} from 'react' const Hello = (props) => { - - let [count, setCount] = useState(2) + + let [count, setCount] = useState(1) let [req, setReq] = useState("") useEffect(() => { diff --git a/app/javascript/react/src/components/Velocity.jsx b/app/javascript/react/src/components/Velocity.jsx new file mode 100644 index 00000000..9263f442 --- /dev/null +++ b/app/javascript/react/src/components/Velocity.jsx @@ -0,0 +1,51 @@ +import React, {useEffect, useState} from 'react' +import { LineChart, Line, CartesianGrid, XAxis, YAxis } from 'recharts' + +const Velocity = () => { + let url = window.location.href + let [req, setReq] = useState("") + + useEffect(() => {fetch(`/velocity/getData/${url[url.length-1]}`).then(async res=>{ + const parse = await res.json() + return parse + }).then(res=>setReq(res)) + }, []) + + + if (Object.keys(req).length == 0) { + return ( +
+

Erro

+
+ ) + + } else { + + var lista = [] + Object.keys(req).forEach(function(key){ + lista.push({"x": key, "y": req[key]}) + }) + + + const data = lista; // <- lista de dicionarios + + const renderLineChart = ( + + + + ); + console.log(lista) + return ( +
+

Gráfico de velocidado média em determinados tempos:

+ + + + + + +
+ ) + } +} +export default Velocity diff --git a/app/javascript/react/src/index.js b/app/javascript/react/src/index.js index a9759c53..ef644e8c 100644 --- a/app/javascript/react/src/index.js +++ b/app/javascript/react/src/index.js @@ -1,5 +1,6 @@ import { define } from 'remount' import Hello from "./components/Hello" -import Graph from "./components/Graph" +import Velocity from "./components/Velocity" +import Graph from './components/Graph' -define({ 'hello-component': Hello, 'graph-component': Graph }) +define({ 'hello-component': Hello, 'velocity-component': Velocity, 'graph-component': Graph }) diff --git a/app/views/graph/skills.html.erb b/app/views/graph/skills.html.erb new file mode 100644 index 00000000..07d83a11 --- /dev/null +++ b/app/views/graph/skills.html.erb @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/views/hello/world.html.erb b/app/views/hello/world.html.erb index 2be2c312..c5d912c1 100644 --- a/app/views/hello/world.html.erb +++ b/app/views/hello/world.html.erb @@ -1 +1 @@ - + diff --git a/app/views/velocity/getData.html.erb b/app/views/velocity/getData.html.erb new file mode 100644 index 00000000..271ce884 --- /dev/null +++ b/app/views/velocity/getData.html.erb @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/views/velocity/graph.html.erb b/app/views/velocity/graph.html.erb new file mode 100644 index 00000000..271ce884 --- /dev/null +++ b/app/views/velocity/graph.html.erb @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index fbc672dd..b982f8da 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/config/routes.rb b/config/routes.rb index a27857a6..32994182 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,11 @@ Rails.application.routes.draw do get 'hello/world' get 'hello/worldGet', to: "hello#index" + get 'graph/skills/:id', to: "graph#skills" + get 'graph/skillsGet/:id', to: "graph#skillsGet" + get 'velocity/graph/:id', to: "velocity#graph" + get 'velocity/getData/:id', to: "velocity#getData" + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. diff --git a/db/schema.rb b/db/schema.rb index 183d56d5..6763f89a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -44,8 +44,10 @@ create_table "trial_executions", force: :cascade do |t| t.string "status" t.text "log" + t.integer "trial_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["trial_id"], name: "index_trial_executions_on_trial_id" end create_table "trial_factors", force: :cascade do |t| diff --git a/db/seeds.rb b/db/seeds.rb index 4fbd6ed9..7294e696 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -7,3 +7,55 @@ # ["Action", "Comedy", "Drama", "Horror"].each do |genre_name| # MovieGenre.find_or_create_by!(name: genre_name) # end + +def create_example_data() + Experiment.create([ name: "teste", disabled: false ]) + Trial.create([name: "testeTrial", disabled: false, deleted: false, runs: 20, experiment_id: Experiment.first.id]) + TrialExecution.create(status: "bom", log:"10.02, [INFO], robot4, {'battery-level': '17.26'}, None, None +10.02, [INFO], robot4, {'y': 34.57, 'x': -38.121, 'yaw': -3.142}, None, None +19.99, [INFO], robot4, {'battery-level': '17.00'}, None, None +19.99, [INFO], robot4, {'y': 33.238, 'x': -37.019, 'yaw': 3.141}, None, None +30.01, [INFO], robot4, {'battery-level': '16.74'}, None, None +30.01, [INFO], robot4, {'y': 31.112, 'x': -37.069, 'yaw': 3.141}, None, None +39.97, [INFO], robot4, {'y': 28.987, 'x': -37.012, 'yaw': 3.14}, None, None +39.97, [INFO], robot4, {'battery-level': '16.48'}, None, None +49.98, [INFO], robot4, {'battery-level': '16.22'}, None, None +50.01, [INFO], robot4, {'y': 26.87, 'x': -37.012, 'yaw': 3.142}, None, None +60.02, [INFO], robot4, {'battery-level': '15.96'}, None, None +60.02, [INFO], robot4, {'y': 24.742, 'x': -37.047, 'yaw': 3.142}, None, None +69.98, [INFO], robot4, {'y': 22.63, 'x': -37.066, 'yaw': 3.141}, None, None +70.00, [INFO], robot4, {'battery-level': '15.70'}, None, None +79.99, [INFO], robot4, {'battery-level': '15.44'}, None, None +79.99, [INFO], robot4, {'y': 20.504, 'x': -37.147, 'yaw': 3.142}, None, None +90.02, [INFO], robot4, {'y': 18.53, 'x': -36.598, 'yaw': 3.141}, None, None +90.02, [INFO], robot4, {'battery-level': '15.18'}, None, None +100.01, [INFO], robot4, {'battery-level': '14.92'}, None, None +100.01, [INFO], robot4, {'y': 17.763, 'x': -34.786, 'yaw': -3.142}, None, None +109.99, [INFO], robot4, {'y': 18.934, 'x': -33.913, 'yaw': 3.142}, None, None +109.99, [INFO], robot4, {'battery-level': '14.66'}, None, None +113.74, [info], nurse, sync, received-request, (status=sending-request) +113.74, [info], nurse, sync, request-sent, (status=waiting) +113.75, [info], nurse, sync, wait-message, (status=message-received) +120.00, [INFO], robot4, {'y': 18.079, 'x': -34.685, 'yaw': -3.142}, None, None +120.00, [INFO], robot4, {'battery-level': '14.40'}, None, None +129.99, [INFO], robot4, {'battery-level': '14.14'}, None, None +130.00, [INFO], robot4, {'y': 18.038, 'x': -36.106, 'yaw': -3.142}, None, None +140.02, [INFO], robot4, {'battery-level': '13.88'}, None, None +140.02, [INFO], robot4, {'y': 18.081, 'x': -36.168, 'yaw': 3.142}, None, None +149.98, [INFO], robot4, {'y': 17.575, 'x': -37.036, 'yaw': 3.142}, None, None +149.98, [INFO], robot4, {'battery-level': '13.62'}, None, None +160.01, [INFO], robot4, {'y': 17.345, 'x': -36.954, 'yaw': -3.141}, None, None +160.01, [INFO], robot4, {'battery-level': '13.36'}, None, None +170.01, [INFO], robot4, {'y': 17.274, 'x': -37.095, 'yaw': -3.141}, None, None +170.01, [INFO], robot4, {'battery-level': '13.10'}, None, None +179.97, [INFO], robot4, {'battery-level': '12.84'}, None, None +180.00, [INFO], robot4, {'y': 17.402, 'x': -37.034, 'yaw': -3.142}, None, None +190.01, [INFO], robot4, {'y': 17.205, 'x': -36.812, 'yaw': -3.141}, None, None +190.01, [INFO], robot4, {'battery-level': '12.58'}, None, None +200.02, [INFO], robot4, {'battery-level': '12.32'}, None, None +200.02, [INFO], robot4, {'y': 17.363, 'x': -36.885, 'yaw': 3.142}, None, None +210.01, [INFO], robot4, {'y': 17.131, 'x': -37.113, 'yaw': 3.142}, None, None +210.01, [INFO], robot4, {'battery-level': '12.06'}, None, None", trial_id: Trial.find_by(id: "1").id) +end + +#create_example_data() \ No newline at end of file diff --git a/features/skills.feature b/features/skills.feature new file mode 100644 index 00000000..8cf86a85 --- /dev/null +++ b/features/skills.feature @@ -0,0 +1,27 @@ +Feature: View skills data from the test run + As a user interested in the results of tests performed, + To understand the skills demonstrated during a test, + I want to visualize the skills data associated with the robot. + +Context: + Given that I have run a test in the simulator, + Then I should see the robot's skills in the test run. + +@javascript +Scenario: Failure + Given that the robot has different skills in its local plan, + And the progress of the plan depends on the success of each skill, + Then it must be informed which of the robot's skills failed. + + +@javascript +Scenario: Success + Given that a robot has a set of skills + And all skills are executed with success + Then the interface should show the graph of the skills + +@javascript +Scenario: Robot without skills + Given that a robot is selected for skills data visualization, + And this robot has no skills assigned, + Then the interface should indicate that there are no skills available for the robot. diff --git a/features/speed.feature b/features/speed.feature new file mode 100644 index 00000000..dbe212d9 --- /dev/null +++ b/features/speed.feature @@ -0,0 +1,30 @@ +Feature: View speed data + As a user I want to be able to view speed data from the test run + +@javascript +Scenario: Test not run (Sad) + Given that the user is on a experiment screen + And the test was never run + When I click on the speed button + Then it shouldn't be possible to view the data + +@javascript +Scenario: Test completed successfully (Happy) + Given that the user is on a experiment screen + And the test was run successfully + When I click on the speed button + Then I should see in a graph the speed information that was collected during the test run + +@javascript +Scenario: Test completed with failure (Sad) + Given that the user is on a experiment screen + And the test ran successfully but with a failure + When I click on the speed button + Then I should see the speed information until the point of failure + +@javascript +Scenario: Data collection failed (Sad) + Given that the user is on a experiment screen + And that the test was run but the speed information is missing + When I click on the speed button + Then the application should report an error diff --git a/features/step_definitions/skills_step.rb b/features/step_definitions/skills_step.rb new file mode 100644 index 00000000..0e45b1ea --- /dev/null +++ b/features/step_definitions/skills_step.rb @@ -0,0 +1,85 @@ +Given("that the robot has different skills in its local plan,") do +end + +And ("the progress of the plan depends on the success of each skill,") do + Experiment.create([ name: "teste", disabled: false ]) + Trial.create([name: "testeTrial", disabled: false, deleted: false, runs: 20, experiment_id: Experiment.find_by(id: "1").id]) + TrialExecution.create(status: "bom", log: "0.00, [INFO], robot3, {'battery-level': '8.04'}, None, None + 0.12, [DEBUG], logger, ROBOTS_CONFIG={'avg_speed': 0.15, 'battery_charge': 0.08039941318304296, 'battery_discharge_rate': 0.00064, 'id': 3, 'local_plan': [['navigation', ['IC Room 6', [[-38.0, 21.5, 0.0], [-37.0, 21.5], [-37.0, 18.93], [-33.9, 18.93, 3.14]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-33.9, 18.93, 3.14], [-37.0, 18.93], [-37.0, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'IC Room 2', 'name': 'r3', 'position': [-38.0, 21.5, 0.0], 'skills': ['approach_person', 'approach_robot', 'navigation', 'operate_drawer']}, None, None + 0.12, [DEBUG], logger, Simulation open, None, None + 10.05, [INFO], robot3, {'y': 21.423, 'x': -37.237, 'yaw': -3.141}, None, None + 10.05, [INFO], robot3, {'battery-level': '7.46'}, None, None + 20.08, [INFO], robot3, {'y': 19.318, 'x': -37.061, 'yaw': 3.139}, None, None + 20.08, [INFO], robot3, {'battery-level': '6.82'}, None, None + 30.06, [INFO], robot3, {'battery-level': '6.18'}, None, None + 30.06, [INFO], robot3, {'y': 17.825, 'x': -35.564, 'yaw': -3.142}, None, None + 40.03, [INFO], robot3, {'battery-level': '5.54'}, None, None + 40.03, [INFO], robot3, {'y': 18.858, 'x': -34.0, 'yaw': -3.142}, None, None + 46.90, [WARN], robot3, NO-SKILL, authenticate_person, authenticate_nurse", trial_id: Trial.find_by(id: "1").id) +end + +Then("it must be informed which of the robot's skills failed.") do + visit '/graph/skills/1' + page.should have_selector('p', text: 'Experiment failed ') + +end + +Given ("that a robot is selected for skills data visualization,") do + +end + +And ("this robot has no skills assigned,") do + Experiment.create([ name: "teste", disabled: false ]) + Trial.create([name: "testeTrial", disabled: false, deleted: false, runs: 20, experiment_id: Experiment.find_by(id: "1").id]) + TrialExecution.create(status: "bom", log: "0.00, [DEBUG], nurse, NURSE_CONFIG={'location': 'PC Room 3', 'position': [-28.5, 18.0, -1.57]}, None, None + 0.00, [INFO], robot1, {'battery-level': '24.00'}, None, None + 0.19, [DEBUG], logger, ROBOTS_CONFIG={'avg_speed': 0.15, 'battery_charge': 0.23995139509475963, 'battery_discharge_rate': 0.0006600000000000001, 'id': 1, 'local_plan': [['navigation', ['PC Room 3', [[-39.44, 33.95, 0.0], [-37.0, 33.95], [-37.0, 16.0], [-28.5, 16.0], [-28.5, 18.0, -1.57]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-28.5, 18.0, -1.57], [-28.5, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'IC Room 4', 'name': 'r1', 'position': [-39.44, 33.95, 0.0], 'skills': ['approach_person', 'approach_robot', 'navigation', 'operate_drawer']}, None, None + 0.19, [DEBUG], logger, Simulation open, None, None", trial_id: Trial.find_by(id: "1").id) +end + +Then ("the interface should indicate that there are no skills available for the robot.") do + visit '/graph/skills/1' + page.should have_selector('p', text: 'Experimento sem ações!') +end + +Given('that a robot has a set of skills') do +end + +Given('all skills are executed with success') do + Experiment.create([ name: "teste", disabled: false ]) + Trial.create([name: "testeTrial", disabled: false, deleted: false, runs: 20, experiment_id: Experiment.find_by(id: "1").id]) + TrialExecution.create(status: "bom", log: "0.19, [DEBUG], logger, ROBOTS_CONFIG={'avg_speed': 0.15, 'battery_charge': 0.5779176354739738, 'battery_discharge_rate': 0.0006000000000000001, 'id': 2, 'local_plan': [['navigation', ['PC Room 3', [[-21.0, 18.0, -1.57], [-21.0, 16.0], [-28.5, 16.0], [-28.5, 18.0, -1.57]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-28.5, 18.0, -1.57], [-28.5, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'PC Room 5', 'name': 'r2', 'position': [-21.0, 18.0, -1.57], 'skills': ['approach_person', 'approach_robot', 'authenticate_person', 'navigation', 'operate_drawer']}, None, None + 0.19, [DEBUG], logger, Simulation open, None, None + 10.07, [INFO], robot2, {'y': 17.533, 'x': -20.967, 'yaw': 3.142}, None, None + 10.07, [INFO], robot2, {'battery-level': '57.25'}, None, None + 20.02, [INFO], robot2, {'y': 16.111, 'x': -21.741, 'yaw': -3.141}, None, None + 20.02, [INFO], robot2, {'battery-level': '56.65'}, None, None + 30.07, [INFO], robot2, {'battery-level': '56.05'}, None, None + 30.07, [INFO], robot2, {'y': 16.007, 'x': -23.865, 'yaw': 3.141}, None, None + 40.07, [INFO], robot2, {'battery-level': '55.45'}, None, None + 40.07, [INFO], robot2, {'y': 15.987, 'x': -25.987, 'yaw': 3.139}, None, None + 50.01, [INFO], robot2, {'battery-level': '54.85'}, None, None + 50.01, [INFO], robot2, {'y': 16.048, 'x': -28.101, 'yaw': 3.141}, None, None + 60.06, [INFO], robot2, {'y': 17.831, 'x': -28.598, 'yaw': 3.14}, None, None + 60.06, [INFO], robot2, {'battery-level': '54.25'}, None, None + 70.01, [INFO], robot2, {'y': 18.047, 'x': -28.577, 'yaw': 3.142}, None, None + 70.01, [INFO], robot2, {'battery-level': '53.65'}, None, None + 74.05, [info], nurse, sync, received-request, (status=sending-request) + 74.05, [info], nurse, sync, request-sent, (status=waiting) + 74.05, [info], nurse, sync, wait-message, (status=message-received) + 80.09, [INFO], robot2, {'battery-level': '53.05'}, None, None + 80.09, [INFO], robot2, {'y': 17.0, 'x': -28.698, 'yaw': 3.141}, None, None + 90.06, [INFO], robot2, {'battery-level': '52.45'}, None, None + 90.06, [INFO], robot2, {'y': 16.105, 'x': -27.307, 'yaw': -3.142}, None, None + 100.04, [INFO], robot2, {'battery-level': '51.85'}, None, None + 100.04, [INFO], robot2, {'y': 14.956, 'x': -25.939, 'yaw': 3.141}, None, None + 110.06, [INFO], robot2, {'battery-level': '51.25'}, None, None + 110.06, [INFO], robot2, {'y': 12.981, 'x': -25.854, 'yaw': 3.142}, None, None + 118.90, [info], lab_arm, sync, wait-message, (status=message-received) + 119.82, [WARN], robot2, SUCCESS, None, None", trial_id: Trial.find_by(id: "1").id) +end + +Then('the interface should show the graph of the skills') do + visit '/graph/skills/1' + page.should have_selector('p', text: 'Sucesso!') +end \ No newline at end of file diff --git a/features/step_definitions/speed_step.rb b/features/step_definitions/speed_step.rb new file mode 100644 index 00000000..b34ec572 --- /dev/null +++ b/features/step_definitions/speed_step.rb @@ -0,0 +1,104 @@ +Given("that the user is on a experiment screen") do + #do nothing +end + +And ("the test was never run") do + Experiment.create([ name: "teste", disabled: false ]) + Trial.create([name: "testeTrial", disabled: false, deleted: false, runs: 20, experiment_id: Experiment.first.id]) + #Não existe trial execution +end + +When("I click on the speed button") do + visit "/velocity/graph/1" #sempre tem id 1 por causa da maneira como o cucumber funciona +end + +Then("it shouldn't be possible to view the data") do + expect(page).to have_content("Erro") +end + + +And("the test was run successfully") do + Experiment.create([ name: "teste", disabled: false ]) + Trial.create([name: "testeTrial", disabled: false, deleted: false, runs: 20, experiment_id: Experiment.first.id]) + TrialExecution.create(status: "bom", log:"10.02, [INFO], robot4, {'battery-level': '17.26'}, None, None +10.02, [INFO], robot4, {'y': 34.57, 'x': -38.121, 'yaw': -3.142}, None, None +19.99, [INFO], robot4, {'battery-level': '17.00'}, None, None +19.99, [INFO], robot4, {'y': 33.238, 'x': -37.019, 'yaw': 3.141}, None, None +30.01, [INFO], robot4, {'battery-level': '16.74'}, None, None +30.01, [INFO], robot4, {'y': 31.112, 'x': -37.069, 'yaw': 3.141}, None, None +39.97, [INFO], robot4, {'y': 28.987, 'x': -37.012, 'yaw': 3.14}, None, None +39.97, [INFO], robot4, {'battery-level': '16.48'}, None, None +49.98, [INFO], robot4, {'battery-level': '16.22'}, None, None +50.01, [INFO], robot4, {'y': 26.87, 'x': -37.012, 'yaw': 3.142}, None, None +60.02, [INFO], robot4, {'battery-level': '15.96'}, None, None +60.02, [INFO], robot4, {'y': 24.742, 'x': -37.047, 'yaw': 3.142}, None, None +69.98, [INFO], robot4, {'y': 22.63, 'x': -37.066, 'yaw': 3.141}, None, None +70.00, [INFO], robot4, {'battery-level': '15.70'}, None, None +79.99, [INFO], robot4, {'battery-level': '15.44'}, None, None +79.99, [INFO], robot4, {'y': 20.504, 'x': -37.147, 'yaw': 3.142}, None, None +90.02, [INFO], robot4, {'y': 18.53, 'x': -36.598, 'yaw': 3.141}, None, None +90.02, [INFO], robot4, {'battery-level': '15.18'}, None, None +100.01, [INFO], robot4, {'battery-level': '14.92'}, None, None +100.01, [INFO], robot4, {'y': 17.763, 'x': -34.786, 'yaw': -3.142}, None, None +109.99, [INFO], robot4, {'y': 18.934, 'x': -33.913, 'yaw': 3.142}, None, None +109.99, [INFO], robot4, {'battery-level': '14.66'}, None, None +113.74, [info], nurse, sync, received-request, (status=sending-request) +113.74, [info], nurse, sync, request-sent, (status=waiting) +113.75, [info], nurse, sync, wait-message, (status=message-received) +120.00, [INFO], robot4, {'y': 18.079, 'x': -34.685, 'yaw': -3.142}, None, None +120.00, [INFO], robot4, {'battery-level': '14.40'}, None, None +129.99, [INFO], robot4, {'battery-level': '14.14'}, None, None +130.00, [INFO], robot4, {'y': 18.038, 'x': -36.106, 'yaw': -3.142}, None, None +140.02, [INFO], robot4, {'battery-level': '13.88'}, None, None +140.02, [INFO], robot4, {'y': 18.081, 'x': -36.168, 'yaw': 3.142}, None, None +149.98, [INFO], robot4, {'y': 17.575, 'x': -37.036, 'yaw': 3.142}, None, None +149.98, [INFO], robot4, {'battery-level': '13.62'}, None, None +160.01, [INFO], robot4, {'y': 17.345, 'x': -36.954, 'yaw': -3.141}, None, None +160.01, [INFO], robot4, {'battery-level': '13.36'}, None, None +170.01, [INFO], robot4, {'y': 17.274, 'x': -37.095, 'yaw': -3.141}, None, None +170.01, [INFO], robot4, {'battery-level': '13.10'}, None, None +179.97, [INFO], robot4, {'battery-level': '12.84'}, None, None +180.00, [INFO], robot4, {'y': 17.402, 'x': -37.034, 'yaw': -3.142}, None, None +190.01, [INFO], robot4, {'y': 17.205, 'x': -36.812, 'yaw': -3.141}, None, None +190.01, [INFO], robot4, {'battery-level': '12.58'}, None, None +200.02, [INFO], robot4, {'battery-level': '12.32'}, None, None +200.02, [INFO], robot4, {'y': 17.363, 'x': -36.885, 'yaw': 3.142}, None, None +210.01, [INFO], robot4, {'y': 17.131, 'x': -37.113, 'yaw': 3.142}, None, None +210.01, [INFO], robot4, {'battery-level': '12.06'}, None, None", trial_id: Trial.find_by(id: "1").id) +end + + +Then("I should see in a graph the speed information that was collected during the test run") do + page.should have_css('div.recharts-wrapper') +end + +Then("I should see the speed information until the point of failure") do + page.should have_css('div.recharts-wrapper') +end + +Then("the application should report an error") do + expect(page).to have_content("Erro") +end + +And("the test ran successfully but with a failure") do + Experiment.create([ name: "teste", disabled: false ]) + Trial.create([name: "testeTrial", disabled: false, deleted: false, runs: 20, experiment_id: Experiment.first.id]) + TrialExecution.create(status: "bom", log:"0.00, [INFO], robot3, {'battery-level': '8.04'}, None, None + 0.12, [DEBUG], logger, ROBOTS_CONFIG={'avg_speed': 0.15, 'battery_charge': 0.08039941318304296, 'battery_discharge_rate': 0.00064, 'id': 3, 'local_plan': [['navigation', ['IC Room 6', [[-38.0, 21.5, 0.0], [-37.0, 21.5], [-37.0, 18.93], [-33.9, 18.93, 3.14]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-33.9, 18.93, 3.14], [-37.0, 18.93], [-37.0, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'IC Room 2', 'name': 'r3', 'position': [-38.0, 21.5, 0.0], 'skills': ['approach_person', 'approach_robot', 'navigation', 'operate_drawer']}, None, None + 0.12, [DEBUG], logger, Simulation open, None, None + 10.05, [INFO], robot3, {'y': 21.423, 'x': -37.237, 'yaw': -3.141}, None, None + 10.05, [INFO], robot3, {'battery-level': '7.46'}, None, None + 20.08, [INFO], robot3, {'y': 19.318, 'x': -37.061, 'yaw': 3.139}, None, None + 20.08, [INFO], robot3, {'battery-level': '6.82'}, None, None + 30.06, [INFO], robot3, {'battery-level': '6.18'}, None, None + 30.06, [INFO], robot3, {'y': 17.825, 'x': -35.564, 'yaw': -3.142}, None, None + 40.03, [INFO], robot3, {'battery-level': '5.54'}, None, None + 40.03, [INFO], robot3, {'y': 18.858, 'x': -34.0, 'yaw': -3.142}, None, None + 46.90, [WARN], robot3, NO-SKILL, authenticate_person, authenticate_nurse", trial_id: Trial.find_by(id: "1").id) +end + +And("that the test was run but the speed information is missing") do + Experiment.create([ name: "teste", disabled: false ]) + Trial.create([name: "testeTrial", disabled: false, deleted: false, runs: 20, experiment_id: Experiment.first.id]) + TrialExecution.create(status: "bom", trial_id: Trial.find_by(id: "1").id) +end diff --git a/features/support/env.rb b/features/support/env.rb index aa0a0b73..336c8a7d 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -80,4 +80,9 @@ config.server_port = '3000' end -Capybara.javascript_driver = :selenium_remote_chrome \ No newline at end of file +Capybara.register_driver :chrome_headless do |app| + Capybara::Selenium::Driver.new app, browser: :chrome, + options: Selenium::WebDriver::Chrome::Options.new(args: %w[headless disable-gpu]) +end + +Capybara.javascript_driver = :chrome_headless \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..bd023e0b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,525 @@ +{ + "name": "app", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "app", + "dependencies": { + "@hotwired/stimulus": "^3.2.2", + "@hotwired/turbo-rails": "^7.3.0", + "bun": "^1.0.18", + "bundle": "^2.1.0", + "chart.js": "^4.4.1", + "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", + "react-dom": "^18.2.0", + "recharts": "^2.10.3", + "remount": "^1.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.23.5", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@hotwired/stimulus": { + "version": "3.2.2", + "license": "MIT" + }, + "node_modules/@hotwired/turbo": { + "version": "7.3.0", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@hotwired/turbo-rails": { + "version": "7.3.0", + "license": "MIT", + "dependencies": { + "@hotwired/turbo": "^7.3.0", + "@rails/actioncable": "^7.0" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, + "node_modules/@oven/bun-darwin-aarch64": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-aarch64/-/bun-darwin-aarch64-1.0.18.tgz", + "integrity": "sha512-lXTdQpajIxP6cSAl4cvdKGVFrjPWKRVrK+PfvlX5Ub/fhyve8nKc5u1BcBG9448QqJ7xCD94bHFDgHxj3kwSmQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-darwin-x64": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64/-/bun-darwin-x64-1.0.18.tgz", + "integrity": "sha512-WHdTNKjFq7n8RwDPQj6BSop/uDYMpTKU+DY6VzSo0Qv+Dx3n00TaWSdexGrJZfAaPD2Z1GWVuJsGlCJ6nFYehQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-darwin-x64-baseline": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@oven/bun-darwin-x64-baseline/-/bun-darwin-x64-baseline-1.0.18.tgz", + "integrity": "sha512-13Hkg2vfK6blR63OCJZxJGPPsozeQEP7djawopQBS/StWPxL7Ph+kLIqja7MUtgRC/n/t8mBDM4V8c8KYrursQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@oven/bun-linux-aarch64": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-aarch64/-/bun-linux-aarch64-1.0.18.tgz", + "integrity": "sha512-TA4QG8nWXsnluwyi0tnzbTj0lpI18Nl/VZfuwUGfaXyRT6MSTnhhsdPu8nPKNvN6dtzfJLkKxejH8dw7FyfwPw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64/-/bun-linux-x64-1.0.18.tgz", + "integrity": "sha512-4quR8sGCmE4XwH+tCnpgVFpO/VwDzaLGbXB3bZ7dOy9yp3UjDVVMbgq3kUAZwR915cjC9bvS0ham2E9QyFQMYw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@oven/bun-linux-x64-baseline": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/@oven/bun-linux-x64-baseline/-/bun-linux-x64-baseline-1.0.18.tgz", + "integrity": "sha512-mfud9gyQI3dTxT7aTqUzCICQeJ6BoHfyDjyqo95v42whAhXL0C5HVDBSLjoBBIeLirJsqXoVCOnCZILFWS1Zrw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rails/actioncable": { + "version": "7.1.1", + "license": "MIT" + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "license": "MIT" + }, + "node_modules/bun": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/bun/-/bun-1.0.18.tgz", + "integrity": "sha512-l0GiCckLxetsUmZwiJCgXor6NCvZVXg+Avk9mVb1JmIukm2+4e5HZWpelVwjVzPLmAHlDv2VyoCx4OX+XiWKgA==", + "cpu": [ + "arm64", + "x64" + ], + "hasInstallScript": true, + "os": [ + "darwin", + "linux" + ], + "bin": { + "bun": "bin/bun", + "bunx": "bin/bun" + }, + "optionalDependencies": { + "@oven/bun-darwin-aarch64": "1.0.18", + "@oven/bun-darwin-x64": "1.0.18", + "@oven/bun-darwin-x64-baseline": "1.0.18", + "@oven/bun-linux-aarch64": "1.0.18", + "@oven/bun-linux-x64": "1.0.18", + "@oven/bun-linux-x64-baseline": "1.0.18" + } + }, + "node_modules/bundle": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bundle/-/bundle-2.1.0.tgz", + "integrity": "sha512-d7TeT8m2HuymDjSEmMppWe/h5SSPPUZkaWKrAofx6gNXDdZ3FL/81oOTGPG+LIaZbNr9m4rtUi98Yw0Q1vHIIw==" + }, + "node_modules/chart.js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.1.tgz", + "integrity": "sha512-C74QN1bxwV1v2PEujhmKjOZ7iUM4w6BWs23Md/6aOZZSlwMzeCIDGuZay++rBgChYru7/+QFeoQW0fQoP534Dg==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=7" + } + }, + "node_modules/clsx": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "license": "MIT" + }, + "node_modules/dom-helpers": { + "version": "3.4.0", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.17.21", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/react": { + "version": "18.2.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "license": "MIT" + }, + "node_modules/react-smooth": { + "version": "2.0.5", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.0", + "react-transition-group": "2.9.0" + }, + "peerDependencies": { + "prop-types": "^15.6.0", + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "2.9.0", + "license": "BSD-3-Clause", + "dependencies": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" + } + }, + "node_modules/recharts": { + "version": "2.10.3", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.19", + "react-is": "^16.10.2", + "react-smooth": "^2.0.5", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "prop-types": "^15.6.0", + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "license": "MIT" + }, + "node_modules/remount": { + "version": "1.0.0", + "license": "MIT", + "peerDependencies": { + "react": ">= 18.0.0", + "react-dom": ">= 18.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.1", + "license": "MIT" + }, + "node_modules/victory-vendor": { + "version": "36.7.0", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + } + } +} diff --git a/package.json b/package.json index 25b33f79..012c14ca 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,13 @@ "dependencies": { "@hotwired/stimulus": "^3.2.2", "@hotwired/turbo-rails": "^7.3.0", + "bun": "^1.0.18", + "bundle": "^2.1.0", + "chart.js": "^4.4.1", "react": "^18.2.0", + "react-chartjs-2": "^5.2.0", "react-dom": "^18.2.0", + "recharts": "^2.10.3", "remount": "^1.0.0" } -} \ No newline at end of file +} diff --git a/spec/models/experiment_spec.rb b/spec/models/experiment_spec.rb new file mode 100644 index 00000000..6910a33c --- /dev/null +++ b/spec/models/experiment_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe Experiment, type: :model do + it 'exemplo sucesso' do + expect(1).to equal(1) + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 00000000..823bf4d3 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,83 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +require 'spec_helper' + +require 'simplecov' +require 'simplecov_json_formatter' + +SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([ + SimpleCov::Formatter::JSONFormatter, + SimpleCov::Formatter::HTMLFormatter +]) + +SimpleCov.start do + add_group 'Config', 'config' + add_group 'Controllers', 'app/controllers' + add_group 'Libs', 'lib' + add_group 'Models', 'app/models' + add_group 'Serializers', 'app/serializers' + add_group 'Specs', 'spec' +end + +ENV['RAILS_ENV'] ||= 'test' +require_relative '../config/environment' +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Rails.root.glob('spec/support/**/*.rb').sort.each { |f| require f } + +# Checks for pending migrations and applies them before tests are run. +# If you are not using ActiveRecord, you can remove these lines. +begin + ActiveRecord::Migration.maintain_test_schema! +rescue ActiveRecord::PendingMigrationError => e + abort e.to_s.strip +end +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_paths = [ + Rails.root.join('spec/fixtures') + ] + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # You can uncomment this line to turn off ActiveRecord support entirely. + # config.use_active_record = false + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, type: :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://rspec.info/features/6-0/rspec-rails + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/requests/graph_controller_spec.rb b/spec/requests/graph_controller_spec.rb new file mode 100644 index 00000000..a7623f32 --- /dev/null +++ b/spec/requests/graph_controller_spec.rb @@ -0,0 +1,205 @@ +require 'rails_helper.rb' + +RSpec.describe "GraphController", type: :request do + describe "GET graph#skillsGet" do + let(:trial_execution) { instance_double(TrialExecution, {id: 99, log: "0.00, [DEBUG], nurse, NURSE_CONFIG={'location': 'PC Room 3', 'position': [-28.5, 18.0, -1.57]}, None, None + 0.00, [INFO], robot2, {'battery-level': '63.50'}, None, None + 0.11, [DEBUG], logger, ROBOTS_CONFIG={'avg_speed': 0.15, 'battery_charge': 0.634952869577942, 'battery_discharge_rate': 0.00054, 'id': 2, 'local_plan': [['navigation', ['PC Room 3', [[-21.0, 18.0, -1.57], [-21.0, 16.0], [-28.5, 16.0], [-28.5, 18.0, -1.57]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-28.5, 18.0, -1.57], [-28.5, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'PC Room 5', 'name': 'r2', 'position': [-21.0, 18.0, -1.57], 'skills': ['approach_person', 'approach_robot', 'authenticate_person', 'navigation', 'operate_drawer']}, None, None + 0.11, [DEBUG], logger, Simulation open, None, None + 10.07, [INFO], robot2, {'y': 17.977, 'x': -20.956, 'yaw': -3.141}, None, None + 10.07, [INFO], robot2, {'battery-level': '63.01'}, None, None + 20.01, [INFO], robot2, {'battery-level': '62.47'}, None, None + 20.01, [INFO], robot2, {'y': 16.197, 'x': -21.448, 'yaw': 3.141}, None, None + 30.05, [INFO], robot2, {'battery-level': '61.93'}, None, None + 30.05, [INFO], robot2, {'y': 16.101, 'x': -23.573, 'yaw': 3.141}, None, None + 40.01, [INFO], robot2, {'battery-level': '61.39'}, None, None + 40.01, [INFO], robot2, {'y': 16.087, 'x': -25.671, 'yaw': 3.141}, None, None + 50.01, [INFO], robot2, {'battery-level': '60.85'}, None, None + 50.01, [INFO], robot2, {'y': 16.095, 'x': -27.778, 'yaw': -3.139}, None, None + 60.06, [INFO], robot2, {'battery-level': '60.31'}, None, None + 60.06, [INFO], robot2, {'y': 17.701, 'x': -28.627, 'yaw': 3.142}, None, None + 70.02, [INFO], robot2, {'battery-level': '59.77'}, None, None + 70.02, [INFO], robot2, {'y': 17.975, 'x': -28.622, 'yaw': -3.142}, None, None + 73.92, [info], nurse, sync, received-request, (status=sending-request) + 73.92, [info], nurse, sync, request-sent, (status=waiting) + 73.92, [info], nurse, sync, wait-message, (status=message-received) + 80.03, [INFO], robot2, {'battery-level': '59.23'}, None, None + 80.03, [INFO], robot2, {'y': 16.913, 'x': -28.699, 'yaw': 3.139}, None, None + 89.94, [INFO], robot2, {'battery-level': '58.69'}, None, None + 90.03, [INFO], robot2, {'y': 16.168, 'x': -27.158, 'yaw': 3.142}, None, None + 100.05, [INFO], robot2, {'y': 14.855, 'x': -25.881, 'yaw': -3.142}, None, None + 100.05, [INFO], robot2, {'battery-level': '58.15'}, None, None + 110.03, [INFO], robot2, {'battery-level': '57.61'}, None, None + 110.03, [INFO], robot2, {'y': 13.027, 'x': -25.904, 'yaw': 3.141}, None, None + 118.29, [info], lab_arm, sync, wait-message, (status=message-received) + 119.17, [WARN], robot2, SUCCESS, None, None"}) } + + + before do + allow(TrialExecution).to receive(:find_by).with(id: trial_execution.id.to_s).and_return(trial_execution) + get "/graph/skillsGet/99" + end + + it "Acessa graph/skillsGet" do + expect(response).to have_http_status(200) + end + end + + describe "GET graph#skillsGet" do + # Se nao existe linha com local plan, nao captura skill + let(:trial_execution) { instance_double(TrialExecution, {id: 98, log: "[WARN], logger, TIMEOUT, None, None" })} + + before do + allow(TrialExecution).to receive(:find_by).with(id: trial_execution.id.to_s).and_return(trial_execution) + get "/graph/skillsGet/98" + end + + it 'Erro: sem iniciação do local_plan' do + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to eq([]) + end + end + + # Necessita-se de uma linha com local plan para se identificar as proximas skills + describe "GET graph#skillsGet" do + let(:trial_execution) { instance_double(TrialExecution, {id: 97, log: "0.20, [DEBUG], logger, ROBOTS_CONFIG={'local_plan': [['navigation', ['IC Room 6', [[-39.44, 33.95, 0.0], [-37.0, 33.95], [-37.0, 18.93], [-33.9, 18.93, 3.14]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-33.9, 18.93, 3.14], [-37.0, 18.93], + [WARN], logger, TIMEOUT, None, None" })} + + before do + allow(TrialExecution).to receive(:find_by).with(id: trial_execution.id.to_s).and_return(trial_execution) + end + + it 'Existe local_plan e msg de TIMEOUT' do + get '/graph/skillsGet/97' + expect(response).to have_http_status(:success) + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to eq([{ "message" => "TIMEOUT" }]) + end + end + + # Msg de Start + describe "GET graph#skillsGet" do + let(:trial_execution) { instance_double(TrialExecution, {id: 96, log: "0.11, [DEBUG], logger, ROBOTS_CONFIG={'local_plan': [['navigation', ['IC Room 2', [[-33.9, 18.93, 3.14], [-37.0, 18.93], [-37.0, 21.5], [-38.0, 21.5, 0.0]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-38.0, 21.5, 0.0], [-37.0, 21.5], [-37.0, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'IC Room 6', 'name': 'r6', 'position': [-33.9, 18.93, 3.14], 'skills': ['approach_person', 'approach_robot', 'navigation', 'operate_drawer']}, None, None + 0.11, [DEBUG], logger, Simulation open, None, None"} )} + + before do + allow(TrialExecution).to receive(:find_by).with(id: trial_execution.id.to_s).and_return(trial_execution) + end + + it 'Comando de start' do + get '/graph/skillsGet/96' + expect(response).to have_http_status(:success) + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to eq([{ "message" => "Experiment started!"}]) + end + end + + # Msg de Navigation to room + Falta de skill + describe "GET graph#skillsGet" do + let(:trial_execution) { instance_double(TrialExecution, {id: 95, log: "0.11, [DEBUG], logger, ROBOTS_CONFIG={'local_plan': [['navigation', ['IC Room 2', [[-33.9, 18.93, 3.14], [-37.0, 18.93], [-37.0, 21.5], [-38.0, 21.5, 0.0]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-38.0, 21.5, 0.0], [-37.0, 21.5], [-37.0, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'IC Room 6', 'name': 'r6', 'position': [-33.9, 18.93, 3.14], 'skills': ['approach_person', 'approach_robot', 'navigation', 'operate_drawer']}, None, None + 0.11, [DEBUG], logger, Simulation open, None, None + 10.03, [INFO], robot6, {'y': 18.858, 'x': -33.903, 'yaw': -3.141}, None, None + 10.03, [INFO], robot6, {'battery-level': '53.44'}, None, None + 55.48, [WARN], robot6, NO-SKILL, authenticate_person, authenticate_nurse"})} + + before do + allow(TrialExecution).to receive(:find_by).with(id: trial_execution.id.to_s).and_return(trial_execution) + end + + it 'Navigation to room + Falta de skill' do + get '/graph/skillsGet/95' + expect(response).to have_http_status(:success) + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to eq([{"message" => "Experiment started!"}, {"time" => 10.03,"message" => "Navigation to room"}, {"time" => 10.03,"message" => "Navigation to room"}, {"time" => "55.48","message" => "Experiment failed with NO-SKILL: authenticate_person."}]) + end + end + + # Msg de falha em skill + describe "GET graph#skillsGet" do + let(:trial_execution) { instance_double(TrialExecution, {id: 94, log: "0.19, [DEBUG], logger, ROBOTS_CONFIG={'local_plan': [['navigation', ['IC Room 6', [[-38.0, 21.5, 0.0], [-37.0, 21.5], [-37.0, 18.93], [-33.9, 18.93, 3.14]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-33.9, 18.93, 3.14], [-37.0, 18.93], [-37.0, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'IC Room 2', 'name': 'r3', 'position': [-38.0, 21.5, 0.0], 'skills': ['approach_person', 'approach_robot', 'authenticate_person', 'navigation', 'operate_drawer']}, None, None + 0.19, [DEBUG], logger, Simulation open, None, None + 176.81, [WARN], robot3, SKILL-FAILURE, navigation, navto_lab"})} + + before do + allow(TrialExecution).to receive(:find_by).with(id: trial_execution.id.to_s).and_return(trial_execution) + end + + it 'Falha em skill' do + get '/graph/skillsGet/94' + expect(response).to have_http_status(:success) + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to eq([{"message" => "Experiment started!"}, {"time" => "176.81","message" => "Skill navigation failed."}]) + end + end + + # Msg de envio para enfermeira + describe "GET graph#skillsGet" do + let(:trial_execution) { instance_double(TrialExecution, {id: 93, log: "0.19, [DEBUG], logger, ROBOTS_CONFIG={'local_plan': [['navigation', ['IC Room 6', [[-38.0, 21.5, 0.0], [-37.0, 21.5], [-37.0, 18.93], [-33.9, 18.93, 3.14]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-33.9, 18.93, 3.14], [-37.0, 18.93], [-37.0, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'IC Room 2', 'name': 'r3', 'position': [-38.0, 21.5, 0.0], 'skills': ['approach_person', 'approach_robot', 'authenticate_person', 'navigation', 'operate_drawer']}, None, None + 0.19, [DEBUG], logger, Simulation open, None, None + 68.58, [info], nurse, sync, received-request, (status=sending-request) + 68.58, [info], nurse, sync, request-sent, (status=waiting) + 68.58, [info], nurse, sync, wait-message, (status=message-received)"})} + + before do + allow(TrialExecution).to receive(:find_by).with(id: trial_execution.id.to_s).and_return(trial_execution) + end + + it 'Envio de mensagem - enfermeira' do + get '/graph/skillsGet/93' + expect(response).to have_http_status(:success) + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to eq([{"message" => "Experiment started!"}, {"time" => "68.58","message" => "Sending message to nurse"},{"time" => "68.58","message" => "Waiting the message get to nurse"},{"time" => "68.58","message" => "Message sent to nurse"}]) + end + end + + # Msg de Navigation to lab + envio para lab_arm + describe "GET graph#skillsGet" do + let(:trial_execution) { instance_double(TrialExecution, {id: 92, log: "0.19, [DEBUG], logger, ROBOTS_CONFIG={'local_plan': [['navigation', ['IC Room 6', [[-38.0, 21.5, 0.0], [-37.0, 21.5], [-37.0, 18.93], [-33.9, 18.93, 3.14]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-33.9, 18.93, 3.14], [-37.0, 18.93], [-37.0, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'IC Room 2', 'name': 'r3', 'position': [-38.0, 21.5, 0.0], 'skills': ['approach_person', 'approach_robot', 'authenticate_person', 'navigation', 'operate_drawer']}, None, None + 0.19, [DEBUG], logger, Simulation open, None, None + 10.01, [INFO], robot4, {'battery-level': '64.70'}, None, None + 10.01, [INFO], robot4, {'y': 34.241, 'x': -33.519, 'yaw': 3.142}, None, None + 108.75, [info], nurse, sync, received-request, (status=sending-request) + 108.75, [info], nurse, sync, request-sent, (status=waiting) + 108.75, [info], nurse, sync, wait-message, (status=message-received) + 110.04, [INFO], robot4, {'battery-level': '59.10'}, None, None + 110.04, [INFO], robot4, {'y': 21.387, 'x': -38.117, 'yaw': 3.139}, None, None + 210.62, [info], lab_arm, sync, wait-message, (status=message-received)"})} + + before do + allow(TrialExecution).to receive(:find_by).with(id: trial_execution.id.to_s).and_return(trial_execution) + end + + it 'Navigation to lab + lab_arm' do + get '/graph/skillsGet/92' + expect(response).to have_http_status(:success) + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to eq([{"message" => "Experiment started!"}, {"time" => 10.01,"message" => "Navigation to room"},{"time" => 10.01,"message" => "Navigation to room"}, {"time" => "108.75","message" => "Sending message to nurse"},{"time" => "108.75","message" => "Waiting the message get to nurse"},{"time" => "108.75","message" => "Message sent to nurse"}, {"time" => 110.04,"message" => "Navigation to lab"}, {"time" => 110.04,"message" => "Navigation to lab"}, {"time" => "210.62","message" => "Message sent to lab_arm"}]) + end + end + + # Msg de Sucesso! + describe "GET graph#skillsGet" do + let(:trial_execution) { instance_double(TrialExecution, {id: 91, log: "0.13, [DEBUG], logger, ROBOTS_CONFIG={'local_plan': [['navigation', ['PC Room 3', [[-27.23, 18.0, -1.57], [-27.23, 16.0], [-28.5, 16.0], [-28.5, 18.0, -1.57]]], 'navto_room'], ['approach_person', ['nurse'], 'approach_nurse'], ['authenticate_person', ['nurse'], 'authenticate_nurse'], ['operate_drawer', ['open'], 'open_drawer_for_nurse'], ['send_message', ['nurse'], 'notify_nurse_of_open_drawer_for_nurse_completed'], ['wait_message', ['nurse'], 'wait_nurse_to_complete_deposit'], ['operate_drawer', ['close'], 'close_drawer_nurse'], ['navigation', ['Laboratory', [[-28.5, 18.0, -1.57], [-28.5, 16.0], [-26.0, 16.0], [-26.0, 13.0, 1.57]]], 'navto_lab'], ['approach_robot', ['lab_arm'], 'approach_arm'], ['operate_drawer', ['open'], 'open_drawer_lab'], ['send_message', ['lab_arm'], 'notify_lab_arm_of_open_drawer_lab_completed'], ['wait_message', ['lab_arm'], 'wait_lab_arm_to_complete_pick_up_sample'], ['operate_drawer', ['close'], 'close_drawer_lab']], 'location': 'PC Room 4', 'name': 'r6', 'position': [-27.23, 18.0, -1.57], 'skills': ['approach_person', 'approach_robot', 'authenticate_person', 'navigation', 'operate_drawer']}, None, None + 0.13, [DEBUG], logger, Simulation open, None, None + 81.78, [WARN], robot6, SUCCESS, None, None"})} + + before do + allow(TrialExecution).to receive(:find_by).with(id: trial_execution.id.to_s).and_return(trial_execution) + end + + it 'Sucesso!' do + get '/graph/skillsGet/91' + expect(response).to have_http_status(:success) + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to eq([{"message" => "Experiment started!"}, {"time" => "81.78","message" => "Experiment completed successfully with 81.78 seconds!"}]) + end + end +end diff --git a/spec/requests/velocity_controller_spec.rb b/spec/requests/velocity_controller_spec.rb new file mode 100644 index 00000000..4470cf2b --- /dev/null +++ b/spec/requests/velocity_controller_spec.rb @@ -0,0 +1,70 @@ +require 'rails_helper.rb' + +RSpec.describe "VelocityController", type: :request do + describe "GET velocity#getData" do + it "Acessa velocity/getData/:id" do + get '/velocity/getData/1' + expect(response).to have_http_status(200) + end + end + + + describe "GET velocity#getData" do + Experiment.create([ name: "teste", disabled: false ]) + Trial.create([name: "testeTrial", disabled: false, deleted: false, runs: 20, experiment_id: Experiment.first.id]) + TrialExecution.create(status: "bom", log:"10.02, [INFO], robot4, {'battery-level': '17.26'}, None, None; + 10.02, [INFO], robot4, {'y': 34.57, 'x': -38.121, 'yaw': -3.142}, None, None; + 19.99, [INFO], robot4, {'battery-level': '17.00'}, None, None; + 19.99, [INFO], robot4, {'y': 33.238, 'x': -37.019, 'yaw': 3.141}, None, None; + 30.01, [INFO], robot4, {'battery-level': '16.74'}, None, None; + 30.01, [INFO], robot4, {'y': 31.112, 'x': -37.069, 'yaw': 3.141}, None, None; + 39.97, [INFO], robot4, {'y': 28.987, 'x': -37.012, 'yaw': 3.14}, None, None; + 39.97, [INFO], robot4, {'battery-level': '16.48'}, None, None; + 49.98, [INFO], robot4, {'battery-level': '16.22'}, None, None; + 50.01, [INFO], robot4, {'y': 26.87, 'x': -37.012, 'yaw': 3.142}, None, None; + 60.02, [INFO], robot4, {'battery-level': '15.96'}, None, None; + 60.02, [INFO], robot4, {'y': 24.742, 'x': -37.047, 'yaw': 3.142}, None, None; + 69.98, [INFO], robot4, {'y': 22.63, 'x': -37.066, 'yaw': 3.141}, None, None; + 70.00, [INFO], robot4, {'battery-level': '15.70'}, None, None; + 79.99, [INFO], robot4, {'battery-level': '15.44'}, None, None; + 79.99, [INFO], robot4, {'y': 20.504, 'x': -37.147, 'yaw': 3.142}, None, None; + 90.02, [INFO], robot4, {'y': 18.53, 'x': -36.598, 'yaw': 3.141}, None, None; + 90.02, [INFO], robot4, {'battery-level': '15.18'}, None, None; + 100.01, [INFO], robot4, {'battery-level': '14.92'}, None, None; + 100.01, [INFO], robot4, {'y': 17.763, 'x': -34.786, 'yaw': -3.142}, None, None; + 109.99, [INFO], robot4, {'y': 18.934, 'x': -33.913, 'yaw': 3.142}, None, None; + 109.99, [INFO], robot4, {'battery-level': '14.66'}, None, None; + 113.74, [info], nurse, sync, received-request, (status=sending-request); + 113.74, [info], nurse, sync, request-sent, (status=waiting); + 113.75, [info], nurse, sync, wait-message, (status=message-received); + 120.00, [INFO], robot4, {'y': 18.079, 'x': -34.685, 'yaw': -3.142}, None, None; + 120.00, [INFO], robot4, {'battery-level': '14.40'}, None, None; + 129.99, [INFO], robot4, {'battery-level': '14.14'}, None, None; + 130.00, [INFO], robot4, {'y': 18.038, 'x': -36.106, 'yaw': -3.142}, None, None; + 140.02, [INFO], robot4, {'battery-level': '13.88'}, None, None; + 140.02, [INFO], robot4, {'y': 18.081, 'x': -36.168, 'yaw': 3.142}, None, None; + 149.98, [INFO], robot4, {'y': 17.575, 'x': -37.036, 'yaw': 3.142}, None, None; + 149.98, [INFO], robot4, {'battery-level': '13.62'}, None, None; + 160.01, [INFO], robot4, {'y': 17.345, 'x': -36.954, 'yaw': -3.141}, None, None; + 160.01, [INFO], robot4, {'battery-level': '13.36'}, None, None; + 170.01, [INFO], robot4, {'y': 17.274, 'x': -37.095, 'yaw': -3.141}, None, None; + 170.01, [INFO], robot4, {'battery-level': '13.10'}, None, None; + 179.97, [INFO], robot4, {'battery-level': '12.84'}, None, None; + 180.00, [INFO], robot4, {'y': 17.402, 'x': -37.034, 'yaw': -3.142}, None, None; + 190.01, [INFO], robot4, {'y': 17.205, 'x': -36.812, 'yaw': -3.141}, None, None; + 190.01, [INFO], robot4, {'battery-level': '12.58'}, None, None; + 200.02, [INFO], robot4, {'battery-level': '12.32'}, None, None; + 200.02, [INFO], robot4, {'y': 17.363, 'x': -36.885, 'yaw': 3.142}, None, None; + 210.01, [INFO], robot4, {'y': 17.131, 'x': -37.113, 'yaw': 3.142}, None, None; + 210.01, [INFO], robot4, {'battery-level': '12.06'}, None, None", trial_id: Trial.find_by(id: "1").id) + + + it 'Resposta correta' do + get '/velocity/getData/1' + expect(response).to have_http_status(:success) + parsed_response = JSON.parse(response.body) + + expect(parsed_response).to eq("19.99" => 0.17339667773468448,"30.01" => 0.21223431909464818,"39.97" => 0.21343015392853468,"50.01" => 0.21085657370517905,"60.02" => 0.21261616478365847,"69.98" => 0.21205677332189088,"79.99" => 0.21254170619499257,"90.02" => 0.2042792557843504,"100.01" => 0.19696161799713408,"109.99" => 0.1463533104811412,"120.0" => 0.11508079586645197,"130.0" => 0.14215913618195625,"140.02" => 0.007530136874106592,"149.98" => 0.10087538816778391,"160.01" => 0.024344991154787752,"170.01" => 0.015786703265723092,"180.0" => 0.014193403536685849,"190.01" => 0.029650814141785335,"200.02" => 0.017387496875047776,"210.01" => 0.032560702364623904) + end + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 00000000..327b58ea --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,94 @@ +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. +=begin + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # https://rspec.info/features/3-12/rspec-core/configuration/zero-monkey-patching-mode/ + config.disable_monkey_patching! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = "doc" + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/test/integration/visualizar_bateria_13.feature b/test/integration/visualizar_bateria_13.feature deleted file mode 100644 index b4ef2d43..00000000 --- a/test/integration/visualizar_bateria_13.feature +++ /dev/null @@ -1,24 +0,0 @@ -Funcionalidade: Visualizar os dados de bateria do robô -Eu como Engenheiro de Sistemas Robóticos -Quero visualizar o status da bateria do robô em um dado momento -A fim de monitorar e otimizar o consumo de energia durante o funcionamento contínuo do robô - -Contexto: - Dado que eu esteja na interface que disponibiliza os dados de bateria - E o sistema de teste de bateria está ativo - -Cenário: Consulta de dados de bateria após o término do teste (triste) - Dado que eu solicite o status da bateria em um determinado instante - E que esse instante não existe no teste - Então deverá ser exibida uma mensagem informando que foi possível concluir a visualização do teste de bateria, porque o instante solicitado está fora do intervalo do teste - -Cenário: Status de bateria retorna dados incorretos (triste) - Dado que eu solicite o status da bateria em um determinado instante - E que o nível de bateria recebido pela aplicação não é um valor percentual decimal entre 0% e 100% - Então deverá ser exibida uma mensagem informando que não foi possível concluir a visualização do teste de bateria, porque o formato dos dados é inválido - -Cenário: A pesquisa de status da bateria retorna porcentagem (feliz) - Dado que eu solicite o status da bateria em um determinado instante - E que esse instante existe no teste - E que o nível de bateria recebido pela aplicação é um valor percentual decimal entre 0% e 100% - Então eu deveria ver a porcentagem da bateria correspondente desse instante \ No newline at end of file diff --git a/test/integration/visualizar_posicao_14.feature b/test/integration/visualizar_posicao_14.feature deleted file mode 100644 index 2d3452c6..00000000 --- a/test/integration/visualizar_posicao_14.feature +++ /dev/null @@ -1,24 +0,0 @@ -Funcionalidade: visualizar os dados de posição do robô -Eu como avaliador da navegação do robo -Quero visualizar a posição do robô em um dado momento, -Afim de analisar os percursos escolhidos durante o teste - -Contexto: - Dado que eu esteja na interfarce que disponibiliza os dados de posição - - Cenario: Um avaliador seleciona momento fora do escopo do teste (triste) - Dado que o teste durou 5 minutos - E que eu solicito a posição no momento 6:00 - E que eu clique em "gerar posição" - Então eu deveria ver uma mensagem na tela dizendo "Não existem dados de posição para esse momento" - - Cenario: A pesquisa de posição retorna coordenadas (feliz) - Dado que eu solicitei a posição no momento 6:00 - E que esse momento existe no teste - Então eu deveria ver um conjunto de coodenadas em relação a posição do robo - - Cenario: A pesquisa de posição retorna dados incorretos (triste) - Dado que eu solicitei a posição no momento 6:00 - E que esse momento existe no teste - E que os dados recebidos pela aplicação não são númericos - Então eu deveria ver uma mensagem na tela dizendo "não foi possível concluir a busca pelos dados" \ No newline at end of file diff --git a/wiki.md b/wiki.md new file mode 100644 index 00000000..ba978999 --- /dev/null +++ b/wiki.md @@ -0,0 +1,34 @@ +# Projeto ide-experimentador + +## Grupo 6 + +- Bernardo Ramalho Rabello (211055218) +- Debora Venturelli Machado (190086238) +- Emanuel de Oliveira Barbosa (211010403) +- Pedro Arthur de Moura Neves (211055352) + + +## Projeto + +- Scrum Master: Pedro Arthur +- Product Owner: Emanuel de Oliveira + +- Issue 15: Dado que sou um usuário, quero visualizar dados de velocidade do teste executado. +- Issue 16: Dado que sou um usuário, quero visualizar dados de skills do teste executado. + + +## Funcionalidades +### Visualizar dados de skills do teste executado + 1. Mostrar análise de resultados sobre as skills nos testes executados: sucesso e falha; + 2. Caso sucesso no item 1, apresentar funcionalidades das skills utilizadas e seus respectivos tempos; + 3. Caso falha no item 1, indicar o erro e interromper execução. + - Responsáveis: Emanuel de Oliveira e Pedro Arthur + +### Visualizar dados de velocidade do teste executado + 1. Mostrar velocidade média dos robôs nos testes executados por meio de gráficos; + 2. Indicar erro caso falte informação sobre a velocidade; + - Responsáveis: Bernardo Ramalho e Debora Venturelli + +## Política de Branching + - Branch principal + - Branch de desenvolvimento