Compare commits
103 Commits
rails
..
d526fa30f4
| Author | SHA1 | Date | |
|---|---|---|---|
| d526fa30f4 | |||
| 3dbc11d294 | |||
| b19c95187b | |||
| a736113abd | |||
| 9c9b038ef8 | |||
| 85749a4616 | |||
| 619c122769 | |||
| 8c5f510c70 | |||
| 8b2c152803 | |||
| 98717db3d5 | |||
| 5d249eb3c7 | |||
| 4ed915a2c0 | |||
| 39f95575da | |||
| 6e1ab89209 | |||
| 9cd6c78741 | |||
| 5b730df803 | |||
| 0ce4a3ecee | |||
| 12ece12394 | |||
| 05c20b5811 | |||
| bd822664b0 | |||
| 3f0efce0d8 | |||
| eeedc57cd3 | |||
| 164eea1bde | |||
| 85fe3b0b38 | |||
| 519955e57a | |||
| 96b746822c | |||
| eac833fd6d | |||
| ad391c84a4 | |||
| 641c9315bc | |||
| 3a136865b0 | |||
| f40d69a98d | |||
| 40cfdcc2a3 | |||
| 260d0d1268 | |||
| e1f5bd3950 | |||
| 1f0c481105 | |||
| dd8e419e52 | |||
| c74ca114d8 | |||
| 0a1037e79a | |||
| bc5ae4962f | |||
| ec2bf45a6e | |||
| 57163b10e4 | |||
| 25d394627d | |||
| 85dfdb163a | |||
| b593ef7593 | |||
| 26698082f4 | |||
| 42a0b95015 | |||
| 5cc3b8f824 | |||
| d59c75281e | |||
| 55e4f397f8 | |||
| 49d1276031 | |||
| bc70fb8dd0 | |||
| 0231ebad2d | |||
| 541b5236f0 | |||
| 6215cecb53 | |||
| 886f566ae2 | |||
| fdd350e16f | |||
| bc4cb181c3 | |||
| 822f49bcc2 | |||
| aec77628f7 | |||
| ecb696372d | |||
| 31b8404be1 | |||
| 8cd47d7e70 | |||
| d17b66920a | |||
| 47cb580393 | |||
| 883019b181 | |||
| 2cc80e239b | |||
| ed085e4b40 | |||
| cf9235cb18 | |||
| 28b6cc66bb | |||
| e3a334546f | |||
| d899ffe58a | |||
| e6853a52d7 | |||
| 6d26eea419 | |||
| 778bd25ef2 | |||
| 6aca95d832 | |||
| 357bb69257 | |||
| 1e0cd49cf8 | |||
| 5628c69d66 | |||
| e6333b855f | |||
| f7979cd005 | |||
| ef2e0a12a5 | |||
| c83d517437 | |||
| 8dee8b1f40 | |||
| 175ce24b27 | |||
| 516f125ea7 | |||
| 34741691ed | |||
| fa9245d7ec | |||
| 1a363a5862 | |||
| b819f4f1cd | |||
| 394a8ef91f | |||
| c940a248d7 | |||
| 269587e6c9 | |||
| 3c9e6eab6b | |||
| a1a00d9fe5 | |||
| 7e38154bc1 | |||
| f0115847b8 | |||
| b8bec03357 | |||
| 7655b75410 | |||
| 691e2e9b1e | |||
| 291db231d5 | |||
| 6c1c8bca0a | |||
| 6f680e72e5 | |||
| b376bf3a79 |
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
BUNDLE_PATH: "vendor/bundle"
|
||||||
+11
@@ -56,3 +56,14 @@ build-iPhoneSimulator/
|
|||||||
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
||||||
# .rubocop-https?--*
|
# .rubocop-https?--*
|
||||||
|
|
||||||
|
# Ignore local data
|
||||||
|
data/
|
||||||
|
|
||||||
|
# Node modules
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Compiled assets
|
||||||
|
public/*/
|
||||||
|
|
||||||
|
# Ignore production configuration files to protect against credential leaks
|
||||||
|
config/production.yaml
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
plugins:
|
||||||
|
- rubocop-rspec
|
||||||
|
- rubocop-sequel
|
||||||
|
|
||||||
|
AllCops:
|
||||||
|
NewCops: enable
|
||||||
|
|
||||||
|
Layout/EmptyLinesAroundClassBody:
|
||||||
|
EnforcedStyle: 'empty_lines_except_namespace'
|
||||||
|
Layout/EmptyLinesAroundModuleBody:
|
||||||
|
EnforcedStyle: 'empty_lines_except_namespace'
|
||||||
|
Layout/FirstHashElementIndentation:
|
||||||
|
EnforcedStyle: 'consistent'
|
||||||
|
Metrics/ClassLength:
|
||||||
|
Max: 150
|
||||||
|
Style/ClassVars:
|
||||||
|
Enabled: false
|
||||||
|
Style/GlobalVars:
|
||||||
|
Enabled: false
|
||||||
|
Style/MethodCallWithoutArgsParentheses:
|
||||||
|
Enabled: false
|
||||||
|
Style/MethodCallWithArgsParentheses:
|
||||||
|
Enabled: true
|
||||||
|
Style/RedundantReturn:
|
||||||
|
Enabled: false
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
steps:
|
||||||
|
setup:
|
||||||
|
image: ruby:3.4
|
||||||
|
env:
|
||||||
|
RACK_ENV: testing
|
||||||
|
commands:
|
||||||
|
- gem install rake
|
||||||
|
- bundle config set --local path "vendor/bundle"
|
||||||
|
- bundle install
|
||||||
|
- RACK_ENV=testing rake db:migrate
|
||||||
|
|
||||||
|
test_ruby34:
|
||||||
|
image: ruby:3.4
|
||||||
|
env:
|
||||||
|
RACK_ENV: testing
|
||||||
|
commands:
|
||||||
|
- gem install rake
|
||||||
|
- bundle config set --local path "vendor/bundle"
|
||||||
|
- rake test:unit
|
||||||
|
group: tests
|
||||||
|
|
||||||
|
style:
|
||||||
|
image: ruby:3.4
|
||||||
|
env:
|
||||||
|
RACK_ENV: testing
|
||||||
|
commands:
|
||||||
|
- gem install rake
|
||||||
|
- bundle config set --local path "vendor/bundle"
|
||||||
|
- rake test:lint
|
||||||
|
|
||||||
|
gitea_release:
|
||||||
|
image: plugins/gitea-release
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: gitea_api_key
|
||||||
|
base_url: https://git.metaunix.net
|
||||||
|
title: "${CI_COMMIT_TAG}"
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
FROM ruby:3.4-slim
|
||||||
|
|
||||||
|
# 1. Install essential build tools for gems like 'pg' or 'sqlite3'
|
||||||
|
RUN apt-get update -qq && apt-get install -y \
|
||||||
|
build-essential \
|
||||||
|
libpq-dev \
|
||||||
|
curl \
|
||||||
|
git
|
||||||
|
|
||||||
|
WORKDIR /usr/src/game-data
|
||||||
|
|
||||||
|
# 2. Set environment variables for the Gem volume we discussed
|
||||||
|
ENV BUNDLE_PATH=/usr/local/bundle \
|
||||||
|
BUNDLE_BIN=/usr/local/bundle/bin \
|
||||||
|
PATH=/usr/local/bundle/bin:$PATH
|
||||||
|
|
||||||
|
# 3. Copy Gemfile first to leverage layer caching
|
||||||
|
COPY Gemfile Gemfile.lock ./
|
||||||
|
RUN bundle install
|
||||||
|
|
||||||
|
# 4. Copy the application code
|
||||||
|
COPY . ./
|
||||||
|
|
||||||
|
# 5. Make sure your entrypoint script is executable
|
||||||
|
RUN chmod +x entrypoints/dev.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["bash", "entrypoints/dev.sh"]
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Node.js runtime
|
||||||
|
FROM node:24
|
||||||
|
|
||||||
|
WORKDIR /usr/src/game-data/
|
||||||
|
|
||||||
|
COPY package.* /usr/src/game-data/
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
VOLUME /usr/src/game-data/node_modules/
|
||||||
|
|
||||||
|
# Run the app
|
||||||
|
CMD [ "npm", "run", "gulp" ]
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
gem 'sinatra', '~> 4.1'
|
||||||
|
gem 'sinatra-contrib', '~> 4.1'
|
||||||
|
gem 'puma', '~> 6.6'
|
||||||
|
|
||||||
|
gem 'sequel', '~> 5.92'
|
||||||
|
gem 'sqlite3', '~> 2.6'
|
||||||
|
|
||||||
|
gem 'logger'
|
||||||
|
|
||||||
|
group :development, :test do
|
||||||
|
gem 'rerun'
|
||||||
|
gem 'wdm', '>= 0.1.0' if Gem.win_platform?
|
||||||
|
|
||||||
|
# rubocop and extensions for code style
|
||||||
|
gem 'rubocop'
|
||||||
|
gem 'rubocop-rspec'
|
||||||
|
gem 'rubocop-sequel'
|
||||||
|
end
|
||||||
|
|
||||||
|
group :test do
|
||||||
|
gem 'rspec'
|
||||||
|
gem 'rack-test'
|
||||||
|
gem 'database_cleaner-sequel'
|
||||||
|
end
|
||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
GEM
|
||||||
|
remote: https://rubygems.org/
|
||||||
|
specs:
|
||||||
|
ast (2.4.3)
|
||||||
|
base64 (0.3.0)
|
||||||
|
bigdecimal (3.2.2)
|
||||||
|
database_cleaner-core (2.0.1)
|
||||||
|
database_cleaner-sequel (2.0.2)
|
||||||
|
database_cleaner-core (~> 2.0.0)
|
||||||
|
sequel
|
||||||
|
diff-lcs (1.6.2)
|
||||||
|
ffi (1.17.2-aarch64-linux-gnu)
|
||||||
|
ffi (1.17.2-aarch64-linux-musl)
|
||||||
|
ffi (1.17.2-arm-linux-gnu)
|
||||||
|
ffi (1.17.2-arm-linux-musl)
|
||||||
|
ffi (1.17.2-arm64-darwin)
|
||||||
|
ffi (1.17.2-x86-linux-gnu)
|
||||||
|
ffi (1.17.2-x86-linux-musl)
|
||||||
|
ffi (1.17.2-x86_64-darwin)
|
||||||
|
ffi (1.17.2-x86_64-linux-gnu)
|
||||||
|
ffi (1.17.2-x86_64-linux-musl)
|
||||||
|
json (2.12.2)
|
||||||
|
language_server-protocol (3.17.0.5)
|
||||||
|
lint_roller (1.1.0)
|
||||||
|
listen (3.9.0)
|
||||||
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||||
|
rb-inotify (~> 0.9, >= 0.9.10)
|
||||||
|
logger (1.7.0)
|
||||||
|
multi_json (1.15.0)
|
||||||
|
mustermann (3.0.3)
|
||||||
|
ruby2_keywords (~> 0.0.1)
|
||||||
|
nio4r (2.7.4)
|
||||||
|
parallel (1.27.0)
|
||||||
|
parser (3.3.8.0)
|
||||||
|
ast (~> 2.4.1)
|
||||||
|
racc
|
||||||
|
prism (1.4.0)
|
||||||
|
puma (6.6.0)
|
||||||
|
nio4r (~> 2.0)
|
||||||
|
racc (1.8.1)
|
||||||
|
rack (3.2.0)
|
||||||
|
rack-protection (4.1.1)
|
||||||
|
base64 (>= 0.1.0)
|
||||||
|
logger (>= 1.6.0)
|
||||||
|
rack (>= 3.0.0, < 4)
|
||||||
|
rack-session (2.1.1)
|
||||||
|
base64 (>= 0.1.0)
|
||||||
|
rack (>= 3.0.0)
|
||||||
|
rack-test (2.2.0)
|
||||||
|
rack (>= 1.3)
|
||||||
|
rainbow (3.1.1)
|
||||||
|
rb-fsevent (0.11.2)
|
||||||
|
rb-inotify (0.11.1)
|
||||||
|
ffi (~> 1.0)
|
||||||
|
regexp_parser (2.10.0)
|
||||||
|
rerun (0.14.0)
|
||||||
|
listen (~> 3.0)
|
||||||
|
rspec (3.13.1)
|
||||||
|
rspec-core (~> 3.13.0)
|
||||||
|
rspec-expectations (~> 3.13.0)
|
||||||
|
rspec-mocks (~> 3.13.0)
|
||||||
|
rspec-core (3.13.5)
|
||||||
|
rspec-support (~> 3.13.0)
|
||||||
|
rspec-expectations (3.13.5)
|
||||||
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
|
rspec-support (~> 3.13.0)
|
||||||
|
rspec-mocks (3.13.5)
|
||||||
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
|
rspec-support (~> 3.13.0)
|
||||||
|
rspec-support (3.13.4)
|
||||||
|
rubocop (1.76.1)
|
||||||
|
json (~> 2.3)
|
||||||
|
language_server-protocol (~> 3.17.0.2)
|
||||||
|
lint_roller (~> 1.1.0)
|
||||||
|
parallel (~> 1.10)
|
||||||
|
parser (>= 3.3.0.2)
|
||||||
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
|
regexp_parser (>= 2.9.3, < 3.0)
|
||||||
|
rubocop-ast (>= 1.45.0, < 2.0)
|
||||||
|
ruby-progressbar (~> 1.7)
|
||||||
|
unicode-display_width (>= 2.4.0, < 4.0)
|
||||||
|
rubocop-ast (1.45.1)
|
||||||
|
parser (>= 3.3.7.2)
|
||||||
|
prism (~> 1.4)
|
||||||
|
rubocop-rspec (3.6.0)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (~> 1.72, >= 1.72.1)
|
||||||
|
rubocop-sequel (0.4.1)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (>= 1.72.1, < 2)
|
||||||
|
ruby-progressbar (1.13.0)
|
||||||
|
ruby2_keywords (0.0.5)
|
||||||
|
sequel (5.93.0)
|
||||||
|
bigdecimal
|
||||||
|
sinatra (4.1.1)
|
||||||
|
logger (>= 1.6.0)
|
||||||
|
mustermann (~> 3.0)
|
||||||
|
rack (>= 3.0.0, < 4)
|
||||||
|
rack-protection (= 4.1.1)
|
||||||
|
rack-session (>= 2.0.0, < 3)
|
||||||
|
tilt (~> 2.0)
|
||||||
|
sinatra-contrib (4.1.1)
|
||||||
|
multi_json (>= 0.0.2)
|
||||||
|
mustermann (~> 3.0)
|
||||||
|
rack-protection (= 4.1.1)
|
||||||
|
sinatra (= 4.1.1)
|
||||||
|
tilt (~> 2.0)
|
||||||
|
sqlite3 (2.7.0-aarch64-linux-gnu)
|
||||||
|
sqlite3 (2.7.0-aarch64-linux-musl)
|
||||||
|
sqlite3 (2.7.0-arm-linux-gnu)
|
||||||
|
sqlite3 (2.7.0-arm-linux-musl)
|
||||||
|
sqlite3 (2.7.0-arm64-darwin)
|
||||||
|
sqlite3 (2.7.0-x86-linux-gnu)
|
||||||
|
sqlite3 (2.7.0-x86-linux-musl)
|
||||||
|
sqlite3 (2.7.0-x86_64-darwin)
|
||||||
|
sqlite3 (2.7.0-x86_64-linux-gnu)
|
||||||
|
sqlite3 (2.7.0-x86_64-linux-musl)
|
||||||
|
tilt (2.6.0)
|
||||||
|
unicode-display_width (3.1.4)
|
||||||
|
unicode-emoji (~> 4.0, >= 4.0.4)
|
||||||
|
unicode-emoji (4.0.4)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
aarch64-linux-gnu
|
||||||
|
aarch64-linux-musl
|
||||||
|
arm-linux-gnu
|
||||||
|
arm-linux-musl
|
||||||
|
arm64-darwin
|
||||||
|
x86-linux-gnu
|
||||||
|
x86-linux-musl
|
||||||
|
x86_64-darwin
|
||||||
|
x86_64-linux-gnu
|
||||||
|
x86_64-linux-musl
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
database_cleaner-sequel
|
||||||
|
logger
|
||||||
|
puma (~> 6.6)
|
||||||
|
rack-test
|
||||||
|
rerun
|
||||||
|
rspec
|
||||||
|
rubocop
|
||||||
|
rubocop-rspec
|
||||||
|
rubocop-sequel
|
||||||
|
sequel (~> 5.92)
|
||||||
|
sinatra (~> 4.1)
|
||||||
|
sinatra-contrib (~> 4.1)
|
||||||
|
sqlite3 (~> 2.6)
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
2.6.9
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) <year> <owner>
|
Copyright (c) 2023 Bit Goblin
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,68 @@
|
|||||||
# game-data
|

|
||||||
|
|
||||||
Web-based tool to store and organize PC hardware gaming benchmarks
|

|
||||||
|
|
||||||
|
# Game Data
|
||||||
|
|
||||||
|
Web-based tool to store and organize PC hardware gaming benchmarks.
|
||||||
|
|
||||||
|
## Project Goals
|
||||||
|
|
||||||
|
The goals of this project are to:
|
||||||
|
|
||||||
|
* Record benchmarking results from multiple devices - e.g. log from a laptop or a phone.
|
||||||
|
* Group results into tests to keep track of different testing configurations.
|
||||||
|
* Encourage running tests multiple times - it's good practice to run a benchmark multiple times for accuracy.
|
||||||
|
* Create comparisons of hardware tests to compare performance.
|
||||||
|
* Generate graphs of hardware comparisons for usage in videos and articles.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Game Data runs on Ruby, and takes advantage of [Bundler](https://bundler.io/) to manage code dependencies and [Rake](https://ruby.github.io/rake/) to run various tasks for maintaining the app. You can install them globally like so:
|
||||||
|
|
||||||
|
Debian/Ubuntu: `apt install -y ruby ruby-bundler rake`
|
||||||
|
RedHat and clones: `dnf install -y ruby rubygem-bundler rubygem-rake`
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
**TBD**
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Via Docker
|
||||||
|
|
||||||
|
If you'd prefer not to install dependencies and such to your local OS, you can do the development via Docker. The scripts provided in `bin/` will build Docker images for running the Ruby app and building the front-end assets via Gulp. *Both containers will automatically watch for changes.*
|
||||||
|
|
||||||
|
**Note:** Using the scripts below, the Docker images will remove themselves when stopped. This is to make clean up a bit more streamlined.
|
||||||
|
|
||||||
|
1. [Install Docker](https://docs.docker.com/engine/install/) for your OS.
|
||||||
|
|
||||||
|
2. Build the docker images for Ruby and Gulp:
|
||||||
|
|
||||||
|
`bin/docker-build.sh`
|
||||||
|
|
||||||
|
3. Run the docker images:
|
||||||
|
|
||||||
|
`bin/docker-run.sh`
|
||||||
|
|
||||||
|
4. If everything is running successfully you can open your browser and go to https://localhost:9292.
|
||||||
|
|
||||||
|
### Local/Native Development
|
||||||
|
|
||||||
|
1. Install dependencies via bundler:
|
||||||
|
|
||||||
|
`bundle install`
|
||||||
|
|
||||||
|
2. Perform database migrations:
|
||||||
|
|
||||||
|
`rake db:migrate`
|
||||||
|
|
||||||
|
3. Run the server in development with auto-reloading:
|
||||||
|
|
||||||
|
`rake server:dev`
|
||||||
|
|
||||||
|
4. If everything is running successfully you can open your browser and go to https://localhost:9292.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is available under the BSD 2-Clause license.
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
require 'bundler/setup'
|
||||||
|
|
||||||
|
namespace :db do
|
||||||
|
desc 'Run migrations'
|
||||||
|
task :migrate, [:version] do |t, args|
|
||||||
|
require 'sequel/core'
|
||||||
|
# load configuration
|
||||||
|
require_relative 'src/config'
|
||||||
|
conf = Config.new()
|
||||||
|
|
||||||
|
Sequel.extension :migration
|
||||||
|
version = args[:version].to_i if args[:version]
|
||||||
|
Sequel.connect(adapter: conf.get('database.adapter'), database: conf.get('database.database')) do |db|
|
||||||
|
Sequel::Migrator.run(db, 'db/migrations', target: version)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :server do
|
||||||
|
task :start do
|
||||||
|
ENV['RACK_ENV'] = 'production'
|
||||||
|
system("puma")
|
||||||
|
end
|
||||||
|
|
||||||
|
task :dev do
|
||||||
|
system('rerun --no-notify --dir="src/" puma')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :test do
|
||||||
|
task :unit do
|
||||||
|
ENV['RACK_ENV'] = 'testing'
|
||||||
|
system("rspec")
|
||||||
|
end
|
||||||
|
|
||||||
|
task :lint do
|
||||||
|
system("rubocop src/ spec/")
|
||||||
|
end
|
||||||
|
end
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1008 KiB |
@@ -0,0 +1,48 @@
|
|||||||
|
$ ->
|
||||||
|
# let us know when javascript is running.
|
||||||
|
console.log('Ready.')
|
||||||
|
|
||||||
|
lastColumn = null
|
||||||
|
ascending = true
|
||||||
|
|
||||||
|
tableHeaders = $('th')
|
||||||
|
tableHeaders.click (e) ->
|
||||||
|
column = $(this).index()
|
||||||
|
table = $(this).closest('table')
|
||||||
|
|
||||||
|
if column is lastColumn
|
||||||
|
ascending = not ascending
|
||||||
|
else
|
||||||
|
ascending = true
|
||||||
|
|
||||||
|
lastColumn = column
|
||||||
|
sortTable(table, column, ascending)
|
||||||
|
|
||||||
|
sortTable = (table, column, ascending) ->
|
||||||
|
rows = table.find('tbody tr').get()
|
||||||
|
|
||||||
|
compareFunction = (a, b) ->
|
||||||
|
res = a.cells[column].textContent.localeCompare b.cells[column].textContent
|
||||||
|
if ascending then res else -res
|
||||||
|
|
||||||
|
rows.sort compareFunction
|
||||||
|
$(rows).detach().appendTo(table.find('tbody'))
|
||||||
|
return
|
||||||
|
|
||||||
|
averageResults = (results, decimals = 2) ->
|
||||||
|
avgScore = 0
|
||||||
|
minScore = Infinity
|
||||||
|
maxScore = -Infinity
|
||||||
|
|
||||||
|
factor = (10 ^ decimals)
|
||||||
|
|
||||||
|
for result in results
|
||||||
|
avgScore += result.avg_score
|
||||||
|
minScore = Math.min(minScore, result.min_score)
|
||||||
|
maxScore = Math.max(maxScore, result.max_score)
|
||||||
|
|
||||||
|
return {
|
||||||
|
avgScore: Math.round((avgScore / results.length) * factor) / factor,
|
||||||
|
minScore: minScore,
|
||||||
|
maxScore: maxScore,
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
$ ->
|
||||||
|
chartInstance = null
|
||||||
|
|
||||||
|
$('#report-benchmarks').on 'change', (e) ->
|
||||||
|
$('#report-tests option').prop('selected', false)
|
||||||
|
|
||||||
|
$('#reports-download').on 'click', (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
canvas = $('#benchmark-chart')[0]
|
||||||
|
a = document.createElement 'a'
|
||||||
|
a.href = canvas.toDataURL 'image/png'
|
||||||
|
a.download = 'chart.png'
|
||||||
|
a.click()
|
||||||
|
|
||||||
|
$('#reports-button').on 'click', (e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
$('#reports-download').attr('disabled', true)
|
||||||
|
chartInstance.destroy() if chartInstance
|
||||||
|
|
||||||
|
benchmarkId = $('#report-benchmarks').val()
|
||||||
|
testIds = $('#report-tests').val()
|
||||||
|
|
||||||
|
benchmarkSearchParams = new URLSearchParams
|
||||||
|
benchmark_id: benchmarkId
|
||||||
|
benchmarkRes = await fetch("/api/v1/benchmark/details?#{benchmarkSearchParams}")
|
||||||
|
benchmarkData = await benchmarkRes.json()
|
||||||
|
|
||||||
|
data =
|
||||||
|
labels: []
|
||||||
|
datasets: []
|
||||||
|
|
||||||
|
switch benchmarkData.scoring
|
||||||
|
when 'pts'
|
||||||
|
data.datasets.push({
|
||||||
|
label: 'Average Score'
|
||||||
|
data: []
|
||||||
|
})
|
||||||
|
when 'fps'
|
||||||
|
data.datasets.push({
|
||||||
|
label: 'Average FPS'
|
||||||
|
data: []
|
||||||
|
})
|
||||||
|
data.datasets.push({
|
||||||
|
label: 'Minimum FPS'
|
||||||
|
data: []
|
||||||
|
})
|
||||||
|
when 'ms'
|
||||||
|
data.datasets.push({
|
||||||
|
label: 'Average Frame Time'
|
||||||
|
data: []
|
||||||
|
})
|
||||||
|
data.datasets.push({
|
||||||
|
label: 'Minimum Frame Time'
|
||||||
|
data: []
|
||||||
|
})
|
||||||
|
|
||||||
|
for testId in testIds
|
||||||
|
try
|
||||||
|
testSearchParams = new URLSearchParams
|
||||||
|
test_id: testId
|
||||||
|
testRes = await fetch("/api/v1/test/details?#{testSearchParams}")
|
||||||
|
testData = await testRes.json()
|
||||||
|
|
||||||
|
resultSearchParams = new URLSearchParams
|
||||||
|
test_id: testId
|
||||||
|
benchmark_id: benchmarkId
|
||||||
|
resultRes = await fetch("/api/v1/result/list?#{resultSearchParams}")
|
||||||
|
resultData = await resultRes.json()
|
||||||
|
|
||||||
|
resultAverage = averageResults(resultData)
|
||||||
|
|
||||||
|
data.labels.push(testData.name)
|
||||||
|
data.datasets[0].data.push(resultAverage.avgScore)
|
||||||
|
console.log(data.datasets[0].data)
|
||||||
|
switch benchmarkData.scoring
|
||||||
|
when 'fps', 'ms'
|
||||||
|
data.datasets[1].data.push(resultAverage.minScore)
|
||||||
|
catch error
|
||||||
|
console.error 'An error occurred while fetching benchmark results.', error
|
||||||
|
|
||||||
|
ctx = $('#benchmark-chart')[0].getContext('2d')
|
||||||
|
|
||||||
|
options =
|
||||||
|
indexAxis: 'y'
|
||||||
|
plugins:
|
||||||
|
title:
|
||||||
|
display: true
|
||||||
|
text: benchmarkData.name
|
||||||
|
font:
|
||||||
|
size: '24'
|
||||||
|
datalabels:
|
||||||
|
anchor: 'end'
|
||||||
|
align: 'left'
|
||||||
|
color: 'black'
|
||||||
|
font:
|
||||||
|
weight: 'bold'
|
||||||
|
formatter: (value) -> value
|
||||||
|
scales:
|
||||||
|
y:
|
||||||
|
beginAtZero: true
|
||||||
|
|
||||||
|
chartInstance = new Chart ctx,
|
||||||
|
type: 'bar'
|
||||||
|
data: data
|
||||||
|
options: options
|
||||||
|
plugins: [ChartDataLabels]
|
||||||
|
|
||||||
|
$('#reports-download').attr('disabled', false)
|
||||||
|
$('#benchmark-chart').removeClass('disabled')
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
testId = $('#results-table').data('test-id')
|
||||||
|
|
||||||
|
fetchTestBenchmarkResults = (testId, benchmarkId) ->
|
||||||
|
try
|
||||||
|
benchmarkSearchParams = new URLSearchParams
|
||||||
|
benchmark_id: benchmarkId
|
||||||
|
benchmarkRes = await fetch("/api/v1/benchmark/details?#{benchmarkSearchParams}")
|
||||||
|
benchmarkData = await benchmarkRes.json()
|
||||||
|
|
||||||
|
resultSearchParams = new URLSearchParams
|
||||||
|
test_id: testId
|
||||||
|
benchmark_id: benchmarkId
|
||||||
|
resultRes = await fetch("/api/v1/result/list?#{resultSearchParams}")
|
||||||
|
resultData = await resultRes.json()
|
||||||
|
|
||||||
|
resultAverage = averageResults(resultData)
|
||||||
|
|
||||||
|
tableRow = $("#results-table tr[data-benchmark-id=#{benchmarkId}]")
|
||||||
|
|
||||||
|
tableRow.append('<td><a href="/benchmark/' + benchmarkData.id + '">' + benchmarkData.name + '</a></td>')
|
||||||
|
tableRow.append('<td>' + benchmarkData.scoring + '</td>')
|
||||||
|
tableRow.append('<td>' + resultData.length + '</td>')
|
||||||
|
|
||||||
|
if resultData.length != 0
|
||||||
|
tableRow.append('<td>' + resultAverage.avgScore + '</td>')
|
||||||
|
|
||||||
|
if benchmarkData.scoring == 'fps'
|
||||||
|
tableRow.append('<td>' + resultAverage.minScore + '</td>')
|
||||||
|
tableRow.append('<td>' + resultAverage.maxScore + '</td>')
|
||||||
|
else
|
||||||
|
tableRow.append('<td>N/a</td>')
|
||||||
|
tableRow.append('<td>N/a</td>')
|
||||||
|
else
|
||||||
|
tableRow.append('<td>N/a</td>')
|
||||||
|
tableRow.append('<td>N/a</td>')
|
||||||
|
tableRow.append('<td>N/a</td>')
|
||||||
|
catch error
|
||||||
|
console.error 'An error occurred while fetching benchmark results.', error
|
||||||
|
|
||||||
|
$('#results-table tbody tr').each((index, tr) ->
|
||||||
|
benchmarkId = $(tr).data('benchmark-id')
|
||||||
|
console.log("Fetching results for benchmark id: " + benchmarkId)
|
||||||
|
fetchTestBenchmarkResults(testId, benchmarkId)
|
||||||
|
)
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
@use "sass:color"
|
||||||
|
|
||||||
|
//$primary-color: #3399ff
|
||||||
|
$primary-color: cornflowerblue
|
||||||
|
$primary-color-highlight: color.adjust($primary-color, $lightness: -10%)
|
||||||
|
|
||||||
|
html
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
|
||||||
|
body
|
||||||
|
background: rgb(240, 235, 248)
|
||||||
|
|
||||||
|
table
|
||||||
|
border: 1px solid #666
|
||||||
|
|
||||||
|
a
|
||||||
|
transition: color 220ms ease-in-out
|
||||||
|
|
||||||
|
#wrapper
|
||||||
|
background: white
|
||||||
|
padding: 1.5rem 2rem
|
||||||
|
border: 1px solid #bbb
|
||||||
|
border-radius: 8px
|
||||||
|
|
||||||
|
#main-nav
|
||||||
|
li
|
||||||
|
a
|
||||||
|
font-size: 1.25rem
|
||||||
|
|
||||||
|
#site-title
|
||||||
|
img
|
||||||
|
max-height: 40px
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
docker build -t game-data -f Dockerfile.dev .
|
||||||
|
docker build -t game-data-gulp -f Dockerfile.gulp .
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
docker build -t game-data -f Dockerfile.dev .
|
||||||
|
docker build -t game-data-gulp -f Dockerfile.gulp .
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
docker exec game-data rake %*
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
docker exec game-data rake "$@"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
docker run --rm -d -t -v "%cd%:/usr/src/game-data" -p 9292:9292 --name game-data game-data
|
||||||
|
docker run --rm -d -t -v "%cd%:/usr/src/game-data" --name game-data-gulp game-data-gulp npm run gulp watch
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
docker run --rm -d -t -v "$(pwd):/usr/src/game-data" -p 9292:9292 --name game-data game-data
|
||||||
|
docker run --rm -d -t -v "$(pwd):/usr/src/game-data" --name game-data-gulp game-data-gulp npm run gulp watch
|
||||||
|
|
||||||
Executable
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Configure bundler to use local vendor path
|
||||||
|
bundle config set --local path 'vendor/bundle'
|
||||||
|
# Install gems
|
||||||
|
bundle install
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Load application config
|
||||||
|
|
||||||
|
root = ::File.dirname(__FILE__)
|
||||||
|
require ::File.join( root, 'src', 'server' )
|
||||||
|
run GameData.new
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
server:
|
||||||
|
host: '0.0.0.0'
|
||||||
|
port: '9292'
|
||||||
|
|
||||||
|
testing:
|
||||||
|
minimum_results_required: 3
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
database:
|
||||||
|
adapter: 'sqlite'
|
||||||
|
database: 'data/gamedata.db'
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
app_dir = File.expand_path('..', __dir__)
|
||||||
|
directory app_dir
|
||||||
|
|
||||||
|
environment ENV.fetch('RACK_ENV', 'development')
|
||||||
|
|
||||||
|
require_relative '../src/config'
|
||||||
|
conf = Config.new()
|
||||||
|
|
||||||
|
bind "tcp://#{conf.get('server.host')}:#{conf.get('server.port')}"
|
||||||
|
workers 2
|
||||||
|
threads 1, 5
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
database:
|
||||||
|
adapter: 'sqlite'
|
||||||
|
database: 'data/gamedata_testing.db'
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
Sequel.migration do
|
||||||
|
|
||||||
|
up do
|
||||||
|
create_table(:hardware) do
|
||||||
|
primary_key :id
|
||||||
|
String :name, null: false
|
||||||
|
String :type, null: false
|
||||||
|
String :description, text: true
|
||||||
|
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table(:benchmarks) do
|
||||||
|
primary_key :id
|
||||||
|
String :name, null: false
|
||||||
|
String :description, text: true
|
||||||
|
String :scoring, null: false
|
||||||
|
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
down do
|
||||||
|
drop_table(:hardware)
|
||||||
|
drop_table(:benchmarks)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
Sequel.migration do
|
||||||
|
|
||||||
|
up do
|
||||||
|
# create tests table
|
||||||
|
create_table(:results) do
|
||||||
|
primary_key :id
|
||||||
|
foreign_key :hardware_id, :hardware
|
||||||
|
foreign_key :benchmark_id, :benchmarks
|
||||||
|
Float :avg_score, null: false
|
||||||
|
Float :min_score
|
||||||
|
Float :max_score
|
||||||
|
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
down do
|
||||||
|
drop_table(:results)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
Sequel.migration do
|
||||||
|
|
||||||
|
up do
|
||||||
|
# create tests table
|
||||||
|
create_table(:tests) do
|
||||||
|
primary_key :id
|
||||||
|
foreign_key :hardware_id, :hardware
|
||||||
|
String :name, null: false
|
||||||
|
String :description
|
||||||
|
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
end
|
||||||
|
|
||||||
|
# create many-to-many table between tests and benchmarks
|
||||||
|
create_table(:benchmarks_tests) do
|
||||||
|
primary_key :id
|
||||||
|
foreign_key :benchmark_id, :benchmarks
|
||||||
|
foreign_key :test_id, :tests
|
||||||
|
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
end
|
||||||
|
|
||||||
|
# modify results table to integrate with the new tests table
|
||||||
|
alter_table(:results) do
|
||||||
|
drop_foreign_key :hardware_id
|
||||||
|
add_foreign_key :test_id, :tests
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
down do
|
||||||
|
alter_table(:results) do
|
||||||
|
drop_foreign_key :test_id
|
||||||
|
add_foreign_key :hardware_id, :hardware
|
||||||
|
end
|
||||||
|
drop_table(:benchmarks_tests)
|
||||||
|
drop_table(:tests)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
Sequel.migration do
|
||||||
|
up do
|
||||||
|
# 1. Create benchmark_profiles
|
||||||
|
create_table(:benchmark_profiles) do
|
||||||
|
primary_key :id
|
||||||
|
String :label, null: false
|
||||||
|
String :settings, null: false
|
||||||
|
foreign_key :benchmark_id, :benchmarks, null: false, on_delete: :cascade
|
||||||
|
DateTime :created_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
DateTime :updated_at, default: Sequel::CURRENT_TIMESTAMP
|
||||||
|
end
|
||||||
|
|
||||||
|
# 2. Create join table (tests <-> benchmark_profiles)
|
||||||
|
create_table(:benchmark_profiles_tests) do
|
||||||
|
primary_key :id
|
||||||
|
foreign_key :test_id, :tests, null: false, on_delete: :cascade
|
||||||
|
foreign_key :benchmark_profile_id, :benchmark_profiles, null: false, on_delete: :cascade
|
||||||
|
|
||||||
|
index [:test_id, :benchmark_profile_id], unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
# 3. Add benchmark_profile_id to results
|
||||||
|
alter_table(:results) do
|
||||||
|
add_foreign_key :benchmark_profile_id, :benchmark_profiles, null: true, on_delete: :cascade
|
||||||
|
end
|
||||||
|
|
||||||
|
# 4. Migrate data from old schema
|
||||||
|
from(:benchmarks).each do |b_row|
|
||||||
|
# Create a BenchmarkProfile for this (test, benchmark) pair
|
||||||
|
bp_id = self[:benchmark_profiles].insert(
|
||||||
|
benchmark_id: b_row[:id],
|
||||||
|
label: 'Default',
|
||||||
|
settings: '{}'
|
||||||
|
)
|
||||||
|
|
||||||
|
from(:benchmarks_tests).each do |bt_row|
|
||||||
|
if bt_row[:benchmark_id] == b_row[:id]
|
||||||
|
# Link it to the test
|
||||||
|
self[:benchmark_profiles_tests].insert(
|
||||||
|
test_id: bt_row[:test_id],
|
||||||
|
benchmark_profile_id: bp_id
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update results belonging to this test + benchmark pair
|
||||||
|
self[:results]
|
||||||
|
.where(test_id: bt_row[:test_id], benchmark_id: bt_row[:benchmark_id])
|
||||||
|
.update(benchmark_profile_id: bp_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# 5. Clean up old schema
|
||||||
|
alter_table(:results) do
|
||||||
|
drop_foreign_key :benchmark_id
|
||||||
|
end
|
||||||
|
|
||||||
|
drop_table(:benchmarks_tests)
|
||||||
|
end
|
||||||
|
|
||||||
|
down do
|
||||||
|
# 1. Recreate old join table
|
||||||
|
create_table(:benchmarks_tests) do
|
||||||
|
foreign_key :test_id, :tests, null: false
|
||||||
|
foreign_key :benchmark_id, :benchmarks, null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
# 2. Add benchmark_id back to results
|
||||||
|
alter_table(:results) do
|
||||||
|
add_foreign_key :benchmark_id, :benchmarks, null: true
|
||||||
|
end
|
||||||
|
|
||||||
|
# 3. Restore data
|
||||||
|
from(:benchmark_profiles_tests).each do |bpt_row|
|
||||||
|
bp = self[:benchmark_profiles][id: bpt_row[:benchmark_profile_id]]
|
||||||
|
next unless bp # safety check
|
||||||
|
|
||||||
|
# Recreate old benchmarks_tests entry
|
||||||
|
self[:benchmarks_tests].insert(
|
||||||
|
test_id: bpt_row[:test_id],
|
||||||
|
benchmark_id: bp[:benchmark_id]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update results to point back to benchmark_id
|
||||||
|
self[:results]
|
||||||
|
.where(test_id: bpt_row[:test_id], benchmark_profile_id: bp[:id])
|
||||||
|
.update(benchmark_id: bp[:benchmark_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
# 4. Remove new schema
|
||||||
|
alter_table(:results) do
|
||||||
|
drop_foreign_key :benchmark_profile_id
|
||||||
|
end
|
||||||
|
|
||||||
|
drop_table(:benchmark_profiles_tests)
|
||||||
|
drop_table(:benchmark_profiles)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Run the migrations to make sure the DB is up-to-date
|
||||||
|
echo 'Checking database status...'
|
||||||
|
rake db:migrate
|
||||||
|
|
||||||
|
# Start the HTTP server
|
||||||
|
echo 'Starting development server...'
|
||||||
|
rake server:dev
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
const sass = require('gulp-sass')(require('sass'));
|
||||||
|
const coffee = require('gulp-coffee');
|
||||||
|
const sourcemaps = require('gulp-sourcemaps');
|
||||||
|
const plumber = require('gulp-plumber');
|
||||||
|
|
||||||
|
// Compile .sass files to compressed CSS
|
||||||
|
function compileSass() {
|
||||||
|
return gulp.src('assets/styles/**/*.sass')
|
||||||
|
.pipe(plumber())
|
||||||
|
.pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError))
|
||||||
|
.pipe(gulp.dest('public/css'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile .coffee files to JavaScript with source maps
|
||||||
|
function compileCoffee() {
|
||||||
|
return gulp.src('assets/scripts/**/*.coffee', { sourcemaps: true })
|
||||||
|
.pipe(plumber())
|
||||||
|
.pipe(coffee({ bare: true }))
|
||||||
|
.pipe(gulp.dest('public/js', { sourcemaps: '.' }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy image files to public/img/
|
||||||
|
function copyImages() {
|
||||||
|
return gulp.src('assets/img/**/*', {encoding: false})
|
||||||
|
.pipe(gulp.dest('public/img/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch files for changes
|
||||||
|
function watchFiles(cb) {
|
||||||
|
gulp.watch('assets/styles/**/*.sass', compileSass);
|
||||||
|
gulp.watch('assets/scripts/**/*.coffee', compileCoffee);
|
||||||
|
gulp.watch('assets/img/**/*', copyImages)
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chain all asset builds together
|
||||||
|
function buildAssets() {
|
||||||
|
return gulp.parallel(compileSass, compileCoffee, copyImages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform initial build then watch
|
||||||
|
function buildAndWatch() {
|
||||||
|
return gulp.series(
|
||||||
|
buildAssets(),
|
||||||
|
watchFiles
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// one-time build
|
||||||
|
exports.build = buildAssets();
|
||||||
|
|
||||||
|
// start builds with file watching
|
||||||
|
exports.watch = buildAndWatch();
|
||||||
|
|
||||||
|
// Define default task (defaults to watch)
|
||||||
|
exports.default = exports.watch;
|
||||||
Generated
+3159
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "game-data",
|
||||||
|
"description": "PC hardware benchmarking data logger",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"main": "src/server.rb",
|
||||||
|
"scripts": {
|
||||||
|
"gulp": "gulp"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.metaunix.net/BitGoblin/game-data"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"pc",
|
||||||
|
"hardware",
|
||||||
|
"benchmarking"
|
||||||
|
],
|
||||||
|
"author": "Gregory Ballantine <gballantine@bitgoblin.tech>",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"devDependencies": {
|
||||||
|
"gulp": "^5.0.1",
|
||||||
|
"gulp-coffee": "^3.0.3",
|
||||||
|
"gulp-plumber": "^1.2.1",
|
||||||
|
"gulp-sass": "^6.0.1",
|
||||||
|
"gulp-sourcemaps": "^3.0.0",
|
||||||
|
"sass": "^1.89.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
require_relative '../../src/models/benchmark'
|
||||||
|
|
||||||
|
RSpec.describe(BenchmarkController) do
|
||||||
|
# GET /benchmark - redirects to /benchmark/list
|
||||||
|
describe 'GET /benchmark' do
|
||||||
|
before { get '/benchmark' }
|
||||||
|
|
||||||
|
it 'Benchmark base route is a redirect.' do
|
||||||
|
expect(last_response).to(be_redirect)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark base route is an HTML response.' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark base route Location header points to /benchmark/list' do
|
||||||
|
expect(last_response['Location']).to(eq("#{BASE_URL}/benchmark/list"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /benchmark/list - displays a table of benchmarks
|
||||||
|
describe 'GET /benchmark/list' do
|
||||||
|
before { get '/benchmark/list' }
|
||||||
|
|
||||||
|
it 'Benchmark list page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark list page is an HTML response.' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Benchmark list page contains 'List of benchmarks' on page." do
|
||||||
|
expect(last_response.body).to(include('List of benchmarks'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /benchmark/add - form for adding benchmark
|
||||||
|
describe 'GET /benchmark/add' do
|
||||||
|
before { get '/benchmark/add' }
|
||||||
|
|
||||||
|
it 'Benchmark add page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark add page is an HTML response.' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Benchmark add page contains 'Add new benchmark' on page." do
|
||||||
|
expect(last_response.body).to(include('Add new benchmark'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /benchmark/add - backend for adding a benchmark
|
||||||
|
describe 'POST /benchmark/add' do
|
||||||
|
before do
|
||||||
|
request_data = {
|
||||||
|
benchmark_name: 'Test Benchmark',
|
||||||
|
benchmark_scoring: 'fps',
|
||||||
|
benchmark_description: 'Benchmark for testing'
|
||||||
|
}
|
||||||
|
post '/benchmark/add', request_data
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark add POST route is a redirect.' do
|
||||||
|
expect(last_response).to(be_redirect)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark add POST route is an HTML response.' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark add POST route Location header points to /benchmark/1' do
|
||||||
|
expect(last_response['Location']).to(eq("#{BASE_URL}/benchmark/1"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark add POST route creates new Benchmark.' do
|
||||||
|
expect(Benchmark.count).to(eq(1))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark add POST route created benchmark has name.' do
|
||||||
|
expect(Benchmark.first.name).to(eq('Test Benchmark'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark add POST route created benchmark has scoring type.' do
|
||||||
|
expect(Benchmark.first.scoring).to(eq('fps'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark add POST route created benchmark has description.' do
|
||||||
|
expect(Benchmark.first.description).to(eq('Benchmark for testing'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /benchmark/:benchmark_id - page for viewing a benchmark model
|
||||||
|
describe 'GET /benchmark/:benchmark_id' do
|
||||||
|
before do
|
||||||
|
@benchmark = Benchmark.create(name: 'Test Benchmark', scoring: 'fps')
|
||||||
|
get "/benchmark/#{@benchmark.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark view page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark view page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark view page contains "Add new benchmark" on page.' do
|
||||||
|
expect(last_response.body).to(include("#{@benchmark.name}"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /benchmark/:benchmark_id/edit - page for editing a benchmark model
|
||||||
|
describe 'GET /benchmark/:benchmark_id/edit' do
|
||||||
|
before do
|
||||||
|
@benchmark = Benchmark.create(name: 'Test Benchmark', scoring: 'fps')
|
||||||
|
get "/benchmark/#{@benchmark.id}/edit"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark edit page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark edit page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark edit page contains "Editing: <benchmark name>" on page.' do
|
||||||
|
expect(last_response.body).to(include("Editing: #{@benchmark.name}"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
require_relative '../../src/models/hardware'
|
||||||
|
|
||||||
|
RSpec.describe(HardwareController) do
|
||||||
|
# GET /hardware - redirects to /hardware/list
|
||||||
|
describe 'GET /hardware' do
|
||||||
|
before { get '/hardware' }
|
||||||
|
|
||||||
|
it 'Hardware base route is a redirect' do
|
||||||
|
expect(last_response).to(be_redirect)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware base route is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware base route Location header points to /hardware/list' do
|
||||||
|
expect(last_response['Location']).to(eq("#{BASE_URL}/hardware/list"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /hardware/list - displays a table of hardwares
|
||||||
|
describe 'GET /hardware/list' do
|
||||||
|
before { get '/hardware/list' }
|
||||||
|
|
||||||
|
it 'Hardware list page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware list page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Hardware list page contains 'List of hardware' on page." do
|
||||||
|
expect(last_response.body).to(include('List of hardware'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /hardware/add - form for adding hardware
|
||||||
|
describe 'GET /hardware/add' do
|
||||||
|
before { get '/hardware/add' }
|
||||||
|
|
||||||
|
it 'Hardware add page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware add page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Hardware add page contains 'Add new hardware' on page." do
|
||||||
|
expect(last_response.body).to(include('Add new hardware'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /hardware/add - backend for adding a hardware component
|
||||||
|
describe 'POST /hardware/add' do
|
||||||
|
before do
|
||||||
|
request_data = {
|
||||||
|
hardware_name: 'Test Hardware',
|
||||||
|
hardware_type: 'gpu'
|
||||||
|
}
|
||||||
|
post '/hardware/add', request_data
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware add POST route is a redirect.' do
|
||||||
|
expect(last_response).to(be_redirect)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware add POST route is an HTML response.' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware add POST route Location header points to /hardware/1' do
|
||||||
|
expect(last_response['Location']).to(eq("#{BASE_URL}/hardware/1"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware add POST route creates new Hardware.' do
|
||||||
|
expect(Hardware.count).to(eq(1))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware add POST route created hardware has name.' do
|
||||||
|
expect(Hardware.first.name).to(eq('Test Hardware'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware add POST route created hardware has type.' do
|
||||||
|
expect(Hardware.first.type).to(eq('gpu'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /hardware/:hardware_id - page for viewing a hardware model
|
||||||
|
describe 'GET /hardware/:hardware_id' do
|
||||||
|
before do
|
||||||
|
@hardware = Hardware.create(name: 'Test Hardware', type: 'gpu')
|
||||||
|
get "/hardware/#{@hardware.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware view page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware view page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware view page contains "Add new hardware" on page.' do
|
||||||
|
expect(last_response.body).to(include("#{@hardware.name}"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /hardware/:hardware_id/edit - page for editing a hardware model
|
||||||
|
describe 'GET /hardware/:hardware_id/edit' do
|
||||||
|
before do
|
||||||
|
@hardware = Hardware.create(name: 'Test Hardware', type: 'gpu')
|
||||||
|
get "/hardware/#{@hardware.id}/edit"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware edit page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware edit page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware edit page contains "Editing: <hardware name>" on page.' do
|
||||||
|
expect(last_response.body).to(include("Editing: #{@hardware.name}"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe(IndexController) do
|
||||||
|
describe 'GET /' do
|
||||||
|
before { get '/' }
|
||||||
|
|
||||||
|
it 'Dashboard returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Dashboard is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Dashboard contains 'Game Data' on page (nav bar should be loaded)." do
|
||||||
|
expect(last_response.body).to(include('Game Data'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Dashboard contains 'Ruby version' on page (footer should be loaded)." do
|
||||||
|
expect(last_response.body).to(include('Ruby version'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe(ReportsController) do
|
||||||
|
describe 'GET /report' do
|
||||||
|
before { get '/report' }
|
||||||
|
|
||||||
|
it 'Reports page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Reports page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Reports page contains "Generate report" on page.' do
|
||||||
|
expect(last_response.body).to(include('Generate report'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe(TestController) do
|
||||||
|
# GET /test - redirects to /test/list
|
||||||
|
describe 'GET /test' do
|
||||||
|
before { get '/test' }
|
||||||
|
|
||||||
|
it 'Test base route is a redirect' do
|
||||||
|
expect(last_response).to(be_redirect)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test base route is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test base route Location header points to /test/list' do
|
||||||
|
expect(last_response['Location']).to(eq("#{BASE_URL}/test/list"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /test/list - displays a table of tests
|
||||||
|
describe 'GET /test/list' do
|
||||||
|
before { get '/test/list' }
|
||||||
|
|
||||||
|
it 'Test list page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test list page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Test list page contains 'List of tests' on page." do
|
||||||
|
expect(last_response.body).to(include('List of tests'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /test/add - form for adding test
|
||||||
|
describe 'GET /test/add' do
|
||||||
|
before { get '/test/add' }
|
||||||
|
|
||||||
|
it 'Test add page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "Test add page contains 'Add new test' on page." do
|
||||||
|
expect(last_response.body).to(include('Add new test'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST /test/add - backend for adding a test
|
||||||
|
describe 'POST /test/add' do
|
||||||
|
before do
|
||||||
|
@hardware = Hardware.create(name: 'Test Hardware', type: 'gpu')
|
||||||
|
@benchmark = Benchmark.create(name: 'Test Benchmark', scoring: 'fps')
|
||||||
|
request_data = {
|
||||||
|
test_name: 'Test Test',
|
||||||
|
test_hardware: @hardware.id,
|
||||||
|
'test_benchmarks[]': [@benchmark.id],
|
||||||
|
test_description: 'Test for testing'
|
||||||
|
}
|
||||||
|
post '/test/add', request_data
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add POST route is a redirect.' do
|
||||||
|
expect(last_response).to(be_redirect)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add POST route is an HTML response.' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add POST route Location header points to /test/1' do
|
||||||
|
expect(last_response['Location']).to(eq("#{BASE_URL}/test/1"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add POST route creates new Test.' do
|
||||||
|
expect(Test.count).to(eq(1))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add POST route created test has name.' do
|
||||||
|
expect(Test.first.name).to(eq('Test Test'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add POST route created test has hardware.' do
|
||||||
|
expect(Test.first.hardware.id).to(eq(@hardware.id))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add POST route created test has benchmarks.' do
|
||||||
|
expect(Test.first.benchmarks.length).to(eq(1))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add POST route created test\'s benchmark can be read.' do
|
||||||
|
expect(Test.first.benchmarks[0].id).to(eq(@benchmark.id))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test add POST route created test has description.' do
|
||||||
|
expect(Test.first.description).to(eq('Test for testing'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /test/:test_id - page for viewing a test model
|
||||||
|
describe 'GET /test/:test_id' do
|
||||||
|
before do
|
||||||
|
@hardware = Hardware.create(name: 'Test Hardware', type: 'gpu')
|
||||||
|
@benchmark = Benchmark.create(name: 'Test Benchmark', scoring: 'fps')
|
||||||
|
@test = Test.create(
|
||||||
|
name: 'Test Test',
|
||||||
|
hardware_id: @hardware.id,
|
||||||
|
description: 'Test for testing'
|
||||||
|
)
|
||||||
|
@test.add_benchmark(@benchmark)
|
||||||
|
get "/test/#{@test.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test view page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test view page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test view page contains test name on page.' do
|
||||||
|
expect(last_response.body).to(include("#{@test.name}"))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test view page contains hardware name on page.' do
|
||||||
|
expect(last_response.body).to(include("#{@hardware.name}"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /test/:test_id/edit - page for editing a test model
|
||||||
|
describe 'GET /test/:test_id/edit' do
|
||||||
|
before do
|
||||||
|
@hardware = Hardware.create(name: 'Test Hardware', type: 'gpu')
|
||||||
|
@benchmark = Benchmark.create(name: 'Test Benchmark', scoring: 'fps')
|
||||||
|
@test = Test.create(
|
||||||
|
name: 'Test Test',
|
||||||
|
hardware_id: @hardware.id,
|
||||||
|
description: 'Test for testing'
|
||||||
|
)
|
||||||
|
@test.add_benchmark(@benchmark)
|
||||||
|
get "/test/#{@test.id}/edit"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test edit page returns 200.' do
|
||||||
|
expect(last_response).to(be_ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test edit page is an HTML response' do
|
||||||
|
expect(last_response['Content-Type']).to(include('text/html'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test edit page contains "Editing: <test name>" on page.' do
|
||||||
|
expect(last_response.body).to(include("Editing: #{@test.name}"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe(Benchmark) do
|
||||||
|
describe 'Benchmark Creation' do
|
||||||
|
it 'Benchmark creation updates model count.' do
|
||||||
|
expect do
|
||||||
|
described_class.create(name: 'Test Benchmark', scoring: 'fps')
|
||||||
|
end.to(change(described_class, :count).by(1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Benchmark Read' do
|
||||||
|
before { described_class.create(name: 'Test Benchmark', scoring: 'fps') }
|
||||||
|
|
||||||
|
it 'Benchmark model has name.' do
|
||||||
|
bench = described_class.first()
|
||||||
|
expect(bench.name).to(eq('Test Benchmark'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Benchmark model has scoring.' do
|
||||||
|
bench = described_class.first()
|
||||||
|
expect(bench.scoring).to(eq('fps'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe(Hardware) do
|
||||||
|
describe 'Hardware Creation' do
|
||||||
|
it 'Hardware creation updates model count.' do
|
||||||
|
expect { described_class.create(name: 'Test Hardware', type: 'gpu') }.to(change(described_class, :count).by(1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Hardware Read' do
|
||||||
|
before { described_class.create(name: 'Test Hardware', type: 'gpu') }
|
||||||
|
|
||||||
|
it 'Hardware model has name.' do
|
||||||
|
hardware = described_class.first()
|
||||||
|
expect(hardware.name).to(eq('Test Hardware'))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Hardware model has scoring.' do
|
||||||
|
hardware = described_class.first()
|
||||||
|
expect(hardware.type).to(eq('gpu'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe(Test) do
|
||||||
|
describe 'Test Creation' do
|
||||||
|
it 'Test creation updates model count.' do
|
||||||
|
expect { described_class.create(name: 'Test Test') }.to(change(described_class, :count).by(1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Test Read' do
|
||||||
|
before do
|
||||||
|
described_class.create(name: 'Test Test')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test model has name.' do
|
||||||
|
tst = described_class.first()
|
||||||
|
expect(tst.name).to(eq('Test Test'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'Test one-to-many association with Hardware' do
|
||||||
|
it 'Test model has Hardware associated with it.' do
|
||||||
|
hardware = Hardware.create(name: 'Test Hardware', type: 'gpu')
|
||||||
|
tst = described_class.create(name: 'Test Test', hardware_id: hardware.id)
|
||||||
|
expect(tst.hardware).to(eq(hardware))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Test model\'s hardware has name set.' do
|
||||||
|
hardware = Hardware.create(name: 'Test Hardware', type: 'gpu')
|
||||||
|
tst = described_class.create(name: 'Test Test', hardware_id: hardware.id)
|
||||||
|
expect(tst.hardware.name).to(eq('Test Hardware'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
ENV['APP_ENV'] = 'test'
|
||||||
|
|
||||||
|
require_relative '../src/server'
|
||||||
|
require 'rspec'
|
||||||
|
require 'rack/test'
|
||||||
|
require 'database_cleaner/sequel'
|
||||||
|
|
||||||
|
# setting this here so all redirect tests can reference the same base URL
|
||||||
|
BASE_URL = 'http://example.org'
|
||||||
|
|
||||||
|
module RSpecMixin
|
||||||
|
|
||||||
|
include Rack::Test::Methods
|
||||||
|
|
||||||
|
def app
|
||||||
|
GameData
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
RSpec.configure do |config|
|
||||||
|
config.include(RSpecMixin)
|
||||||
|
|
||||||
|
config.before(:suite) do
|
||||||
|
DatabaseCleaner.strategy = :transaction
|
||||||
|
end
|
||||||
|
|
||||||
|
config.around do |suite|
|
||||||
|
DatabaseCleaner.cleaning do
|
||||||
|
suite.run
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module AppInfo
|
||||||
|
|
||||||
|
VERSION = '0.2.1'
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'yaml'
|
||||||
|
|
||||||
|
# Config - loads and manages the app's configuration
|
||||||
|
class Config
|
||||||
|
|
||||||
|
DEFAULT_CONFIG = 'config/defaults.yaml'
|
||||||
|
ENVIRONMENT_CONFIG = ENV.fetch('RACK_ENV', 'development')
|
||||||
|
|
||||||
|
def initialize(config_path = "config/#{ENVIRONMENT_CONFIG}.yaml")
|
||||||
|
@data = YAML.load_file(DEFAULT_CONFIG)
|
||||||
|
|
||||||
|
# merge in user-defined configuration if it exists
|
||||||
|
@data.merge!(YAML.load_file(config_path)) if File.exist?(config_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(key)
|
||||||
|
bits = key.split('.')
|
||||||
|
value = @data
|
||||||
|
|
||||||
|
bits.each do |bit|
|
||||||
|
value = value[bit]
|
||||||
|
end
|
||||||
|
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'sinatra/json'
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/benchmark'
|
||||||
|
require_relative '../models/test'
|
||||||
|
require_relative '../models/result'
|
||||||
|
|
||||||
|
# /api/v1 routes
|
||||||
|
class APIv1Controller < BaseController
|
||||||
|
|
||||||
|
get '/api/v1/benchmark/details' do
|
||||||
|
benchmark_id = params[:benchmark_id]
|
||||||
|
|
||||||
|
benchmark = Benchmark.where(id: benchmark_id).first()
|
||||||
|
|
||||||
|
json benchmark.values()
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/api/v1/result/list' do
|
||||||
|
test_id = params[:test_id]
|
||||||
|
benchmark_id = params[:benchmark_id]
|
||||||
|
|
||||||
|
results = Result.where(test_id: test_id, benchmark_id: benchmark_id).all()
|
||||||
|
|
||||||
|
json results.map(&:values)
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/api/v1/test/details' do
|
||||||
|
test_id = params[:test_id]
|
||||||
|
|
||||||
|
tst = Test.where(id: test_id).first()
|
||||||
|
|
||||||
|
json tst.values()
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'sinatra/base'
|
||||||
|
|
||||||
|
# BaseController - base modular Sinatra app class
|
||||||
|
class BaseController < Sinatra::Base
|
||||||
|
|
||||||
|
# Register view helpers
|
||||||
|
require_relative '../helpers'
|
||||||
|
helpers Helpers
|
||||||
|
|
||||||
|
# Set up our view engine
|
||||||
|
set :views, File.join(settings.root, '/../../views')
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/benchmark'
|
||||||
|
|
||||||
|
# /benchmark routes
|
||||||
|
class BenchmarkController < BaseController
|
||||||
|
|
||||||
|
get '/benchmark' do
|
||||||
|
redirect('/benchmark/list')
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/benchmark/list' do
|
||||||
|
benchmarks = Benchmark.reverse(:updated_at).limit(10).all()
|
||||||
|
|
||||||
|
erb :'benchmark/index', locals: {
|
||||||
|
title: 'List of Benchmarks',
|
||||||
|
benchmarks: benchmarks
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/benchmark/add' do
|
||||||
|
erb :'benchmark/add', locals: {
|
||||||
|
title: 'Add Benchmark'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
post '/benchmark/add' do
|
||||||
|
benchmark = Benchmark.create(
|
||||||
|
name: params[:benchmark_name],
|
||||||
|
scoring: params[:benchmark_scoring],
|
||||||
|
description: params[:benchmark_description]
|
||||||
|
)
|
||||||
|
|
||||||
|
redirect "/benchmark/#{benchmark.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/benchmark/:benchmark_id' do
|
||||||
|
benchmark = Benchmark.where(id: params[:benchmark_id]).first()
|
||||||
|
erb :'benchmark/view', locals: {
|
||||||
|
title: benchmark.name,
|
||||||
|
benchmark: benchmark
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/benchmark/:benchmark_id/edit' do
|
||||||
|
benchmark = Benchmark.where(id: params[:benchmark_id]).first()
|
||||||
|
erb :'benchmark/edit', locals: {
|
||||||
|
title: "Editing: #{benchmark.name}",
|
||||||
|
benchmark: benchmark
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
post '/benchmark/:benchmark_id/edit' do
|
||||||
|
benchmark = Benchmark.where(id: params[:benchmark_id]).first()
|
||||||
|
|
||||||
|
benchmark.update(
|
||||||
|
name: params[:benchmark_name],
|
||||||
|
scoring: params[:benchmark_scoring],
|
||||||
|
description: params[:benchmark_description]
|
||||||
|
)
|
||||||
|
|
||||||
|
redirect "/benchmark/#{benchmark.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/hardware'
|
||||||
|
require_relative '../models/benchmark'
|
||||||
|
|
||||||
|
# /hardware routes
|
||||||
|
class HardwareController < BaseController
|
||||||
|
|
||||||
|
get '/hardware' do
|
||||||
|
redirect('/hardware/list')
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/hardware/list' do
|
||||||
|
hardware = Hardware.reverse(:updated_at).limit(10).all()
|
||||||
|
|
||||||
|
erb :'hardware/index', locals: {
|
||||||
|
title: 'List of Hardware',
|
||||||
|
hardware: hardware
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/hardware/add' do
|
||||||
|
erb :'hardware/add', locals: {
|
||||||
|
title: 'Add Hardware'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
post '/hardware/add' do
|
||||||
|
hardware = Hardware.create(
|
||||||
|
name: params[:hardware_name],
|
||||||
|
type: params[:hardware_type]
|
||||||
|
)
|
||||||
|
|
||||||
|
redirect "/hardware/#{hardware.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/hardware/:hardware_id' do
|
||||||
|
benchmarks = Benchmark.order(:name).all()
|
||||||
|
hardware = Hardware.where(id: params[:hardware_id]).first()
|
||||||
|
erb :'hardware/view', locals: {
|
||||||
|
title: hardware.name,
|
||||||
|
hardware: hardware,
|
||||||
|
benchmarks: benchmarks
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/hardware/:hardware_id/edit' do
|
||||||
|
hardware = Hardware.where(id: params[:hardware_id]).first()
|
||||||
|
erb :'hardware/edit', locals: {
|
||||||
|
title: "Editing: #{hardware.name}",
|
||||||
|
hardware: hardware
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
post '/hardware/:hardware_id/edit' do
|
||||||
|
hardware = Hardware.where(id: params[:hardware_id]).first()
|
||||||
|
|
||||||
|
hardware.update(
|
||||||
|
name: params[:hardware_name],
|
||||||
|
type: params[:hardware_type]
|
||||||
|
)
|
||||||
|
|
||||||
|
redirect "/hardware/#{hardware.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/test'
|
||||||
|
require_relative '../models/benchmark_profile'
|
||||||
|
|
||||||
|
# / (top-level) routes
|
||||||
|
class IndexController < BaseController
|
||||||
|
|
||||||
|
get '/' do
|
||||||
|
tests = Test.reverse(:updated_at).limit(10).all()
|
||||||
|
|
||||||
|
erb :'index/index', locals: {
|
||||||
|
title: 'Dashboard',
|
||||||
|
tests: tests
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'sinatra/json'
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/benchmark'
|
||||||
|
require_relative '../models/result'
|
||||||
|
require_relative '../models/test'
|
||||||
|
|
||||||
|
# /reports routes
|
||||||
|
class ReportsController < BaseController
|
||||||
|
|
||||||
|
get '/report' do
|
||||||
|
benchmarks = Benchmark.order(:name).all()
|
||||||
|
tests = Test.order(:name).all()
|
||||||
|
|
||||||
|
erb :'reports/index', locals: {
|
||||||
|
title: 'Generate Reports',
|
||||||
|
tests: tests,
|
||||||
|
benchmarks: benchmarks
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
post '/report' do
|
||||||
|
report_type = params[:type]
|
||||||
|
report_choice = params[:choice]
|
||||||
|
report_compare = params[:compare]
|
||||||
|
|
||||||
|
if report_type == 'benchmark'
|
||||||
|
choice = Benchmark.where(id: report_choice).first().name
|
||||||
|
names = []
|
||||||
|
avg_results = []
|
||||||
|
min_results = []
|
||||||
|
|
||||||
|
report_compare.each do |c|
|
||||||
|
tst = Test.where(id: c).first()
|
||||||
|
names.push(tst.name)
|
||||||
|
|
||||||
|
res = Result.where(benchmark_id: report_choice, test_id: c).first()
|
||||||
|
avg_results.push(res.avg_score)
|
||||||
|
min_results.push(res.min_score)
|
||||||
|
end
|
||||||
|
|
||||||
|
json({
|
||||||
|
choice: choice,
|
||||||
|
names: names,
|
||||||
|
avg_results: avg_results,
|
||||||
|
min_results: min_results
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/result'
|
||||||
|
|
||||||
|
# /result routes
|
||||||
|
class ResultController < BaseController
|
||||||
|
|
||||||
|
post '/result/add' do
|
||||||
|
result_minimum = params[:result_minimum] if params.key?(:result_minimum)
|
||||||
|
result_maximum = params[:result_maximum] if params.key?(:result_maximum)
|
||||||
|
|
||||||
|
Result.create(
|
||||||
|
test_id: params[:result_test],
|
||||||
|
benchmark_profile_id: params[:result_benchmark],
|
||||||
|
avg_score: params[:result_average],
|
||||||
|
min_score: result_minimum,
|
||||||
|
max_score: result_maximum
|
||||||
|
)
|
||||||
|
|
||||||
|
if params.key?(:result_referrer)
|
||||||
|
if params[:result_referrer] == 'test'
|
||||||
|
redirect "/test/#{params[:result_test]}"
|
||||||
|
elsif params[:result_referrer] == 'benchmark'
|
||||||
|
redirect "/benchmark/#{params[:result_benchmark]}"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
redirect '/result'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/benchmark'
|
||||||
|
require_relative '../models/hardware'
|
||||||
|
require_relative '../models/test'
|
||||||
|
|
||||||
|
# /test routes
|
||||||
|
class TestController < BaseController
|
||||||
|
|
||||||
|
get '/test' do
|
||||||
|
redirect('/test/list')
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/test/list' do
|
||||||
|
tests = Test.reverse(:updated_at).limit(10).all()
|
||||||
|
|
||||||
|
erb :'test/index', locals: {
|
||||||
|
title: 'List of Tests',
|
||||||
|
tests: tests
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/test/add' do
|
||||||
|
hardware = Hardware.order(:name).all()
|
||||||
|
benchmarks = Benchmark.order(:name).all()
|
||||||
|
|
||||||
|
erb :'test/add', locals: {
|
||||||
|
title: 'Add Test',
|
||||||
|
hardware: hardware,
|
||||||
|
benchmarks: benchmarks
|
||||||
|
}
|
||||||
|
end
|
||||||
|
post '/test/add' do
|
||||||
|
tst = Test.create(
|
||||||
|
name: params[:test_name],
|
||||||
|
hardware_id: params[:test_hardware],
|
||||||
|
description: params[:test_description]
|
||||||
|
)
|
||||||
|
|
||||||
|
# create an array of the selected benchmarks
|
||||||
|
benchmarks = Array(params[:test_benchmarks])
|
||||||
|
# associate the benchmarks to the test
|
||||||
|
benchmarks.each do |b|
|
||||||
|
tst.add_benchmark_profile(b)
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect "/test/#{tst.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/test/:test_id' do
|
||||||
|
tst = Test.where(id: params[:test_id]).first()
|
||||||
|
erb :'test/view', locals: {
|
||||||
|
title: tst.name,
|
||||||
|
test: tst
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/test/:test_id/edit' do
|
||||||
|
tst = Test.where(id: params[:test_id]).first()
|
||||||
|
hardware = Hardware.order(:name).all()
|
||||||
|
benchmarks = Benchmark.order(:name).all()
|
||||||
|
|
||||||
|
erb :'test/edit', locals: {
|
||||||
|
title: "Editing: #{tst.name}",
|
||||||
|
test: tst,
|
||||||
|
hardware: hardware,
|
||||||
|
benchmarks: benchmarks
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
post '/test/:test_id/edit' do
|
||||||
|
tst = Test.where(id: params[:test_id]).first()
|
||||||
|
|
||||||
|
tst.update(
|
||||||
|
name: params[:test_name],
|
||||||
|
hardware_id: params[:test_hardware],
|
||||||
|
description: params[:test_description]
|
||||||
|
)
|
||||||
|
|
||||||
|
selected_benchmarks = Array(params[:test_benchmarks])
|
||||||
|
|
||||||
|
# remove benchmarks no longer associated with the test
|
||||||
|
tst.benchmark_profiles.dup.each do |b|
|
||||||
|
tst.remove_benchmark_profile(b.id) unless selected_benchmarks.include?(b.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
# associate the benchmarks to the test
|
||||||
|
selected_benchmarks.each do |b|
|
||||||
|
tst.add_benchmark_profile(b) unless tst.benchmark?(b)
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect "/test/#{tst.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'appinfo'
|
||||||
|
|
||||||
|
# Helpers - view helper functions
|
||||||
|
module Helpers
|
||||||
|
|
||||||
|
def ruby_version
|
||||||
|
return RUBY_VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
def app_version
|
||||||
|
return AppInfo::VERSION
|
||||||
|
end
|
||||||
|
|
||||||
|
def date_format(date)
|
||||||
|
dt = date.to_datetime
|
||||||
|
return dt.strftime('%B %d, %Y @ %I:%M:%S %p %Z')
|
||||||
|
end
|
||||||
|
|
||||||
|
def average_array(arr, decimals = 1)
|
||||||
|
sum = 0
|
||||||
|
|
||||||
|
arr.each do |i|
|
||||||
|
sum += i
|
||||||
|
end
|
||||||
|
|
||||||
|
return (sum / arr.length).round(decimals)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Benchmark - database model for PC benchmarks
|
||||||
|
class Benchmark < Sequel::Model
|
||||||
|
|
||||||
|
one_to_many :benchmark_profiles
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# BenchmarkProfile - database model for benchmark settings profile
|
||||||
|
class BenchmarkProfile < Sequel::Model
|
||||||
|
|
||||||
|
many_to_one :benchmark
|
||||||
|
many_to_many :tests
|
||||||
|
one_to_many :results
|
||||||
|
|
||||||
|
def display_name
|
||||||
|
"#{benchmark.name} @ #{label}"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Hardware - database model for PC hardware
|
||||||
|
class Hardware < Sequel::Model(:hardware)
|
||||||
|
|
||||||
|
one_to_many :tests
|
||||||
|
|
||||||
|
def bench_results
|
||||||
|
br = {}
|
||||||
|
|
||||||
|
results.each do |r|
|
||||||
|
br[r.benchmark.name.to_s] = [] unless br.key?(r.benchmark.name)
|
||||||
|
|
||||||
|
br[r.benchmark.name.to_s].push(r.avg_score)
|
||||||
|
end
|
||||||
|
|
||||||
|
return br
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Result - database model for benchmark results
|
||||||
|
class Result < Sequel::Model
|
||||||
|
|
||||||
|
many_to_one :test
|
||||||
|
many_to_one :benchmark_profile
|
||||||
|
|
||||||
|
def formatted_score
|
||||||
|
return @avg_score
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Test - database model for hardware tests
|
||||||
|
class Test < Sequel::Model
|
||||||
|
|
||||||
|
one_to_many :result
|
||||||
|
many_to_one :hardware
|
||||||
|
many_to_many :benchmark_profiles
|
||||||
|
|
||||||
|
def benchmark?(benchmark_id)
|
||||||
|
return benchmark_profiles_dataset.where(Sequel[:benchmark_profiles][:id] => benchmark_id).any?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'sinatra/base'
|
||||||
|
require 'sequel'
|
||||||
|
require 'sqlite3'
|
||||||
|
|
||||||
|
require_relative 'config'
|
||||||
|
|
||||||
|
# Load configuration from environment config file
|
||||||
|
$conf = Config.new()
|
||||||
|
|
||||||
|
# Load the Sequel timestamps plugin
|
||||||
|
Sequel::Model.plugin(:timestamps)
|
||||||
|
# Initialize Sequel gem for database actions
|
||||||
|
DB = Sequel.connect(adapter: $conf.get('database.adapter'), database: $conf.get('database.database'))
|
||||||
|
|
||||||
|
# Load in routes (must happen after Sequel is loaded!)
|
||||||
|
require_relative 'controllers/api1'
|
||||||
|
require_relative 'controllers/benchmark'
|
||||||
|
require_relative 'controllers/hardware'
|
||||||
|
require_relative 'controllers/index'
|
||||||
|
require_relative 'controllers/reports'
|
||||||
|
require_relative 'controllers/result'
|
||||||
|
require_relative 'controllers/test'
|
||||||
|
|
||||||
|
# GameData - main app that gets launched
|
||||||
|
# - inherits from Sinatra::Base to instantiate the server
|
||||||
|
# - sets up some base app configuration
|
||||||
|
# - registers route classes with the base app
|
||||||
|
class GameData < Sinatra::Base
|
||||||
|
|
||||||
|
enable :sessions
|
||||||
|
|
||||||
|
# Set up static file serving
|
||||||
|
enable :static
|
||||||
|
set :public_folder, File.join(__dir__, '/../public')
|
||||||
|
|
||||||
|
use IndexController
|
||||||
|
use HardwareController
|
||||||
|
use BenchmarkController
|
||||||
|
use TestController
|
||||||
|
use ResultController
|
||||||
|
use ReportsController
|
||||||
|
use APIv1Controller
|
||||||
|
|
||||||
|
end
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>Add new benchmark</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<form class="col-12" action="/benchmark/add" method="post">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-9">
|
||||||
|
<label for="benchmark_name">Benchmark name</label>
|
||||||
|
<input id="benchmark_name" class="form-control" type="text" name="benchmark_name" placeholder="Example benchmark">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-3">
|
||||||
|
<label for="benchmark_scoring">Scoring type</label>
|
||||||
|
<select id="benchmark_scoring" class="form-select" name="benchmark_scoring">
|
||||||
|
<option value="fps">Frames per Second (fps)</option>
|
||||||
|
<option value="ms">Frame Time (ms)</option>
|
||||||
|
<option value="pts">Total Points</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<label for="benchmark_description">Benchmark description</label>
|
||||||
|
<textarea id="benchmark_description" class="form-control" name="benchmark_description" placeholder="Enter a description/notes here."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<input class="btn btn-primary w-100" type="submit" value="Create Benchmark">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>Editing: <%= benchmark.name %></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<form class="cell small-12" action="/benchmark/<%= benchmark.id %>/edit" method="post">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-9">
|
||||||
|
<label for="benchmark_name">Benchmark name</label>
|
||||||
|
<input id="benchmark_name" class="form-control" type="text" name="benchmark_name" placeholder="Example benchmark" value="<%= benchmark.name %>">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-3">
|
||||||
|
<label for="benchmark_scoring">Scoring type</label>
|
||||||
|
<select id="benchmark_scoring" class="form-select" name="benchmark_scoring">
|
||||||
|
<option value="fps" <% if benchmark.scoring == 'fps' %>selected<% end %>>Frames per Second (fps)</option>
|
||||||
|
<option value="ms" <% if benchmark.scoring == 'ms' %>selected<% end %>>Frame Time (ms)</option>
|
||||||
|
<option value="pts" <% if benchmark.scoring == 'pts' %>selected<% end %>>Total Points</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<label for="benchmark_description">Benchmark description</label>
|
||||||
|
<textarea id="benchmark_description" class="form-control" name="benchmark_description" placeholder="Enter a description/notes here."><%= benchmark.description %></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<input class="btn btn-primary w-100" type="submit" value="Submit Changes">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>List of benchmarks</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<p>
|
||||||
|
<a href="/benchmark/add">Add new benchmark</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<% if benchmarks.length > 0 %>
|
||||||
|
<div class="col-12">
|
||||||
|
<table class="table table-hover table-responsive">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Benchmark name</th>
|
||||||
|
<th>Scoring type</th>
|
||||||
|
<th>Notes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% benchmarks.each do |b| %>
|
||||||
|
<tr>
|
||||||
|
<td><a href="/benchmark/<%= b.id %>"><%= b.name %></a></td>
|
||||||
|
<td><%= b.scoring %></td>
|
||||||
|
<td><%= b.description %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<div class="col-12">
|
||||||
|
<p>I'm sorry, there doesn't appear to be any benchmarks added yet. Check again later!</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1><%= benchmark.name %></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<p><a href="/benchmark/<%= benchmark.id %>/edit">Edit</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
Benchmark scoring type: <%= benchmark.scoring %>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
Description:
|
||||||
|
<p><%= benchmark.description %></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h3 class="mb-3">Profiles created for this benchmark:</h3>
|
||||||
|
|
||||||
|
<% if benchmark.benchmark_profiles.length > 0 %>
|
||||||
|
<table class="table table-hover table-responsive">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Profile Label</th>
|
||||||
|
<th>Tests Linked</th>
|
||||||
|
<th>Created at</th>
|
||||||
|
<th>Last updated</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% benchmark.benchmark_profiles.each do |bp| %>
|
||||||
|
<tr>
|
||||||
|
<td><%= bp.display_name %></td>
|
||||||
|
<td><%= bp.tests.length %></td>
|
||||||
|
<td><%= bp.created_at %></td>
|
||||||
|
<td><%= bp.updated_at %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<% else %>
|
||||||
|
<p>There are no profiles associated with this benchmark.</p>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>Add new hardware</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
|
||||||
|
<form class="col-12" action="/hardware/add" method="post">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12 col-md-9">
|
||||||
|
<label for="hardware_name">Hardware name</label>
|
||||||
|
<input id="hardware_name" class="form-control" type="text" name="hardware_name" placeholder="Example hardware">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-3">
|
||||||
|
<label for="hardware_type">Type</label>
|
||||||
|
<select id="hardware_type" class="form-select" name="hardware_type">
|
||||||
|
<option value="gpu">Graphics card</option>
|
||||||
|
<option value="cpu">Processor</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<input class="btn btn-primary w-100" type="submit" value="Create Hardware">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>Add new hardware</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
|
||||||
|
<form class="col-12" action="/hardware/<%= hardware.id %>/edit" method="post">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12 col-md-9">
|
||||||
|
<label for="hardware_name">Hardware name</label>
|
||||||
|
<input id="hardware_name" class="form-control" type="text" name="hardware_name" placeholder="Example hardware" value="<%= hardware.name %>">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-3">
|
||||||
|
<label for="hardware_type">Type</label>
|
||||||
|
<select id="hardware_type" class="form-select" name="hardware_type">
|
||||||
|
<option value="gpu" <% if hardware.type == 'gpu' %>selected<% end %>>Graphics card</option>
|
||||||
|
<option value="cpu" <% if hardware.type == 'cpu' %>selected<% end %>>Processor</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<input class="btn btn-primary w-100" type="submit" value="Submit Changes">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>List of hardware</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<p>
|
||||||
|
<a href="/hardware/add">Add new hardware</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<% if hardware.length > 0 %>
|
||||||
|
<div class="col-12">
|
||||||
|
<table class="table table-hover table-responsive">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Hardware name</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Date added</th>
|
||||||
|
<th>Date modified</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% hardware.each do |h| %>
|
||||||
|
<tr>
|
||||||
|
<td><a href="/hardware/<%= h.id %>"><%= h.name %></a></td>
|
||||||
|
<td><%= h.type %></td>
|
||||||
|
<td><%= date_format(h.created_at) %></td>
|
||||||
|
<td><%= date_format(h.updated_at) %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<div class="col-12">
|
||||||
|
<p>I'm sorry, there doesn't appear to be any hardware added yet. Check again later!</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1><%= hardware.name %></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<p><a href="/hardware/<%= hardware.id %>/edit">Edit</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
Hardware type: <%= hardware.type %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h3 class="mb-3">Tests using this benchmark:</h3>
|
||||||
|
|
||||||
|
<% if hardware.tests.length > 0 %>
|
||||||
|
<table class="table table-hover table-responsive">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Test title</th>
|
||||||
|
<th>Benchmarks</th>
|
||||||
|
<th>Last updated</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% hardware.tests.each do |t| %>
|
||||||
|
<tr>
|
||||||
|
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
||||||
|
<td><%= t.benchmarks.length %></td>
|
||||||
|
<td><%= t.updated_at %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<% else %>
|
||||||
|
<p>There are no tests associated with this benchmark.</p>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<div class="row">
|
||||||
|
<% if tests.length > 0 %>
|
||||||
|
<div class="12-col mb-3">
|
||||||
|
<h2>Latest benchmark results:</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="12-col">
|
||||||
|
<table class="table table-hover table-responsive">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th data-sort="name">Test name</th>
|
||||||
|
<th data-sort="benchmark-count"># Benchmarks</th>
|
||||||
|
<th data-sort="updated'">Last Updated</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% tests.each do |t| %>
|
||||||
|
<tr>
|
||||||
|
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
||||||
|
<td><%= t.benchmark_profiles.length %></td>
|
||||||
|
<td><%= t.updated_at %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<div class="12-col">
|
||||||
|
<p>I'm sorry, there don't appear to be any benchmark results logged yet. Check again later!</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<link rel="shortcut icon" href="/img/favicon.png">
|
||||||
|
<title><%= title %> | Game Data</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="/css/rimmington.css">
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" charset="utf-8"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/js/bootstrap.min.js" charset="utf-8"></script>
|
||||||
|
<script src="/js/edgeville.js" charset="utf-8"></script>
|
||||||
|
</head>
|
||||||
|
<body class="d-flex flex-column min-vh-100">
|
||||||
|
<!-- main navigation -->
|
||||||
|
<%= erb :'partials/navbar', :locals => locals %>
|
||||||
|
|
||||||
|
<!-- main content -->
|
||||||
|
<main class="flex-grow-1 py-4">
|
||||||
|
<div id="wrapper" class="container mb-4">
|
||||||
|
<%= yield %>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<!-- site footer -->
|
||||||
|
<%= erb :'partials/footer', :locals => locals %>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<footer id="main-footer" class="bg-light border-top py-3 text-center">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<p>Game Data version v<%= app_version() %></p>
|
||||||
|
<p class="mb-0">Running Ruby version v<%= ruby_version() %></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<div id="main-nav" class="navbar navbar-expand-md bg-dark border-bottom border-body mb-3" data-bs-theme="dark">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a id="site-title" class="navbar-brand mb-0 h1" href="#">
|
||||||
|
Game Data
|
||||||
|
<img src="/img/app-logo.png" alt="">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
|
<ul class="navbar-nav me-auto mb-2 mb-md-0">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/">Dashboard</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/benchmark">Benchmarks</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/hardware">Hardware</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/test">Test</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/report">Reports</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>Generate report</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<form class="col-12" action="/reports" method="post">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<select id="report-type" class="form-select" name="report_type" disabled>
|
||||||
|
<option value="benchmark">Benchmark</option>
|
||||||
|
<option value="test">Test</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<select id="report-benchmarks" class="form-select" name="report_choice">
|
||||||
|
<% benchmarks.each do |b| %>
|
||||||
|
<option value="<%= b.id %>"><%= b.name %></option>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 mb-3">
|
||||||
|
<select id="report-tests" class="col-12 form-select" name="report_compare[]" multiple>
|
||||||
|
<% tests.each do |t| %>
|
||||||
|
<option value="<%= t.id %>"><%= t.name %></option>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 mb-3">
|
||||||
|
<button id="reports-button" class="btn btn-primary">Generate</button>
|
||||||
|
<button id="reports-download" class="btn btn-primary" disabled>Download</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<canvas id="benchmark-chart" width="100%" height="25"></canvas>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- load the chart.js library -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js" charset="utf-8"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js" charset="utf-8"></script>
|
||||||
|
<!-- load chart functionality -->
|
||||||
|
<script src="/js/reports.js" charset="utf-8"></script>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>Add new test</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<form class="col-12" action="/test/add" method="post">
|
||||||
|
<div class="row mb-0 mb-md-3">
|
||||||
|
<div class="col-12 col-md-6 mb-3 mb-md-0">
|
||||||
|
<label for="test_name">Test name</label>
|
||||||
|
<input id="test_name" class="form-control" type="text" name="test_name" placeholder="My hardware test (01/99)">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-6 mb-3 mb-md-0">
|
||||||
|
<label for="test_hardware">Hardware to test</label>
|
||||||
|
<select id="test_hardware" class="form-select" name="test_hardware">
|
||||||
|
<% for h in hardware %>
|
||||||
|
<option value="<%= h.id %>"><%= h.name %></option>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-0 mb-md-3">
|
||||||
|
<div class="col-12 col-md-4 mb-3 mb-md-0">
|
||||||
|
<label for="test_benchmarks">Benchmarks</label>
|
||||||
|
<select id="test_benchmarks" class="form-select" name="test_benchmarks[]" multiple>
|
||||||
|
<% for b in benchmarks %>
|
||||||
|
<% for bp in b.benchmark_profiles %>
|
||||||
|
<option value="<%= bp.id %>"><%= bp.display_name %></option>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-8 mb-3 mb-md-0">
|
||||||
|
<label for="test_description">Test description</label>
|
||||||
|
<textarea id="test_description" class="form-control" name="test_description" placeholder="This is my test for a hardware..."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<input class="btn btn-primary w-100" type="submit" value="Create Test">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>Editing: <%= test.name %></h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<form class="col-12" action="/test/<%= test.id %>/edit" method="post">
|
||||||
|
<div class="row mb-0 mb-md-3">
|
||||||
|
<div class="col-12 col-md-6 mb-3 mb-md-0">
|
||||||
|
<label for="test_name">Test name</label>
|
||||||
|
<input id="test_name" class="form-control" type="text" name="test_name" placeholder="My hardware test (01/99)" value="<%= test.name %>">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-6 mb-3 mb-md-0">
|
||||||
|
<label for="test_hardware">Hardware to test</label>
|
||||||
|
<select id="test_hardware" class="form-select" name="test_hardware">
|
||||||
|
<% for h in hardware %>
|
||||||
|
<option value="<%= h.id %>" <% if h.id == test.hardware.id %>selected<% end %>><%= h.name %></option>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-0 mb-md-3">
|
||||||
|
<div class="col-12 col-md-4 mb-3 mb-md-0">
|
||||||
|
<label for="test_benchmarks">Benchmarks</label>
|
||||||
|
<select id="test_benchmarks" class="form-select" name="test_benchmarks[]" multiple>
|
||||||
|
<% for b in benchmarks %>
|
||||||
|
<% for bp in b.benchmark_profiles %>
|
||||||
|
<option value="<%= bp.id %>" <% if test.benchmark?(bp.id) %>selected<% end %>><%= bp.display_name %></option>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-8 mb-3 mb-md-0">
|
||||||
|
<label for="test_description">Test description</label>
|
||||||
|
<textarea id="test_description" class="form-control" name="test_description" placeholder="This is my test for a hardware..."><%= test.description %></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<input class="btn btn-primary w-100" type="submit" value="Submit Changes">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>List of tests</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<p>
|
||||||
|
<a href="/test/add">Add new test</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<% if tests.length > 0 %>
|
||||||
|
<div class="col-12">
|
||||||
|
<table class="table table-hover table-responsive">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Test name</th>
|
||||||
|
<th># of benchmarks</th>
|
||||||
|
<th>Date added</th>
|
||||||
|
<th>Date modified</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% tests.each do |t| %>
|
||||||
|
<tr>
|
||||||
|
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
||||||
|
<td><%= t.benchmark_profiles.length %></td>
|
||||||
|
<td><%= date_format(t.created_at) %></td>
|
||||||
|
<td><%= date_format(t.updated_at) %></td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<div class="col-12">
|
||||||
|
<p>I'm sorry, there doesn't appear to be any tests added yet. Check again later!</p>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1><%= test.name %></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<p><a href="/test/<%= test.id %>/edit">Edit</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<p>Hardware tested: <a href="/hardware/<%= test.hardware.id %>"><%= test.hardware.name %></a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
<p><%= test.description %></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<form action="/result/add" method="post">
|
||||||
|
<input type="hidden" name="result_test" value="<%= test.id %>">
|
||||||
|
<input type="hidden" name="result_referrer" value="test">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-5 mb-3 mb-md-0">
|
||||||
|
<label for="result_benchmark">Add benchmark result:</label>
|
||||||
|
<select class="form-select" id="result_benchmark" name="result_benchmark">
|
||||||
|
<% test.benchmark_profiles.each do |b| %>
|
||||||
|
<option value="<%= b.id %>"><%= b.display_name %></option>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-4 col-md-2">
|
||||||
|
<label for="result_average">Average score:</label>
|
||||||
|
<input id="result_average" class="form-control" type="text" name="result_average" value="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-4 col-md-2">
|
||||||
|
<label for="result_minimum">Minimum score:</label>
|
||||||
|
<input id="result_minimum" class="form-control" type="text" name="result_minimum" value="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-4 col-md-2 mb-3 mb-md-0">
|
||||||
|
<label for="result_maximum">Maximum score:</label>
|
||||||
|
<input id="result_maximum" class="form-control" type="text" name="result_maximum" value="">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-md-1 d-flex align-items-stretch mb-3 mb-md-0">
|
||||||
|
<input class="btn btn-primary w-100" type="submit" value="Submit">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h4>Benchmark results for this test:</h4>
|
||||||
|
|
||||||
|
<table id="results-table" class="table table-hover table-responsive" data-test-id="<%= test.id %>">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Benchmark name</th>
|
||||||
|
<th>Scoring type</th>
|
||||||
|
<th># results</th>
|
||||||
|
<th>Average</th>
|
||||||
|
<th>Minimum</th>
|
||||||
|
<th>Maximum</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% test.benchmark_profiles.each do |bp| %>
|
||||||
|
<tr data-benchmark-id="<%= bp.id %>"></tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- load test data fetching functionality -->
|
||||||
|
<script src="/js/test.js" charset="utf-8"></script>
|
||||||
Reference in New Issue
Block a user