Compare commits
41 Commits
v0.1.1
...
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 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -63,5 +63,7 @@ data/
|
|||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
# Compiled assets
|
# Compiled assets
|
||||||
public/css/
|
public/*/
|
||||||
public/js/
|
|
||||||
|
# Ignore production configuration files to protect against credential leaks
|
||||||
|
config/production.yaml
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
require: rubocop-sequel
|
plugins:
|
||||||
|
- rubocop-rspec
|
||||||
|
- rubocop-sequel
|
||||||
|
|
||||||
AllCops:
|
AllCops:
|
||||||
NewCops: enable
|
NewCops: enable
|
||||||
|
|||||||
@@ -1,11 +1,32 @@
|
|||||||
pipeline:
|
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:
|
style:
|
||||||
image: ruby:3.4
|
image: ruby:3.4
|
||||||
|
env:
|
||||||
|
RACK_ENV: testing
|
||||||
commands:
|
commands:
|
||||||
- 'gem install rake'
|
- gem install rake
|
||||||
- 'bundle config set --local path "vendor/bundle"'
|
- bundle config set --local path "vendor/bundle"
|
||||||
- 'bundle install'
|
- rake test:lint
|
||||||
- 'rake test:rubocop'
|
|
||||||
|
|
||||||
gitea_release:
|
gitea_release:
|
||||||
image: plugins/gitea-release
|
image: plugins/gitea-release
|
||||||
@@ -15,5 +36,5 @@ pipeline:
|
|||||||
base_url: https://git.metaunix.net
|
base_url: https://git.metaunix.net
|
||||||
title: "${CI_COMMIT_TAG}"
|
title: "${CI_COMMIT_TAG}"
|
||||||
when:
|
when:
|
||||||
event: tag
|
event:
|
||||||
|
- tag
|
||||||
|
|||||||
@@ -1,16 +1,27 @@
|
|||||||
FROM ruby:3.4
|
FROM ruby:3.4-slim
|
||||||
|
|
||||||
RUN gem install bundler
|
# 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
|
WORKDIR /usr/src/game-data
|
||||||
|
|
||||||
COPY Gemfile Gemfile.l*ck ./
|
# 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
|
||||||
|
|
||||||
RUN bundle check || bundle install
|
# 3. Copy Gemfile first to leverage layer caching
|
||||||
|
COPY Gemfile Gemfile.lock ./
|
||||||
RUN gem install rake
|
RUN bundle install
|
||||||
|
|
||||||
|
# 4. Copy the application code
|
||||||
COPY . ./
|
COPY . ./
|
||||||
|
|
||||||
ENTRYPOINT ["bash", "entrypoints/dev.sh"]
|
# 5. Make sure your entrypoint script is executable
|
||||||
|
RUN chmod +x entrypoints/dev.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["bash", "entrypoints/dev.sh"]
|
||||||
|
|||||||
11
Gemfile
11
Gemfile
@@ -1,7 +1,7 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
gem 'sinatra', '~> 3.2'
|
gem 'sinatra', '~> 4.1'
|
||||||
gem 'sinatra-contrib', '~> 3.2'
|
gem 'sinatra-contrib', '~> 4.1'
|
||||||
gem 'puma', '~> 6.6'
|
gem 'puma', '~> 6.6'
|
||||||
|
|
||||||
gem 'sequel', '~> 5.92'
|
gem 'sequel', '~> 5.92'
|
||||||
@@ -15,5 +15,12 @@ group :development, :test do
|
|||||||
|
|
||||||
# rubocop and extensions for code style
|
# rubocop and extensions for code style
|
||||||
gem 'rubocop'
|
gem 'rubocop'
|
||||||
|
gem 'rubocop-rspec'
|
||||||
gem 'rubocop-sequel'
|
gem 'rubocop-sequel'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
group :test do
|
||||||
|
gem 'rspec'
|
||||||
|
gem 'rack-test'
|
||||||
|
gem 'database_cleaner-sequel'
|
||||||
|
end
|
||||||
|
|||||||
55
Gemfile.lock
55
Gemfile.lock
@@ -4,6 +4,11 @@ GEM
|
|||||||
ast (2.4.3)
|
ast (2.4.3)
|
||||||
base64 (0.3.0)
|
base64 (0.3.0)
|
||||||
bigdecimal (3.2.2)
|
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-gnu)
|
||||||
ffi (1.17.2-aarch64-linux-musl)
|
ffi (1.17.2-aarch64-linux-musl)
|
||||||
ffi (1.17.2-arm-linux-gnu)
|
ffi (1.17.2-arm-linux-gnu)
|
||||||
@@ -33,10 +38,16 @@ GEM
|
|||||||
puma (6.6.0)
|
puma (6.6.0)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.8.1)
|
racc (1.8.1)
|
||||||
rack (2.2.17)
|
rack (3.2.0)
|
||||||
rack-protection (3.2.0)
|
rack-protection (4.1.1)
|
||||||
base64 (>= 0.1.0)
|
base64 (>= 0.1.0)
|
||||||
rack (~> 2.2, >= 2.2.4)
|
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)
|
rainbow (3.1.1)
|
||||||
rb-fsevent (0.11.2)
|
rb-fsevent (0.11.2)
|
||||||
rb-inotify (0.11.1)
|
rb-inotify (0.11.1)
|
||||||
@@ -44,6 +55,19 @@ GEM
|
|||||||
regexp_parser (2.10.0)
|
regexp_parser (2.10.0)
|
||||||
rerun (0.14.0)
|
rerun (0.14.0)
|
||||||
listen (~> 3.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)
|
rubocop (1.76.1)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (~> 3.17.0.2)
|
language_server-protocol (~> 3.17.0.2)
|
||||||
@@ -58,6 +82,9 @@ GEM
|
|||||||
rubocop-ast (1.45.1)
|
rubocop-ast (1.45.1)
|
||||||
parser (>= 3.3.7.2)
|
parser (>= 3.3.7.2)
|
||||||
prism (~> 1.4)
|
prism (~> 1.4)
|
||||||
|
rubocop-rspec (3.6.0)
|
||||||
|
lint_roller (~> 1.1)
|
||||||
|
rubocop (~> 1.72, >= 1.72.1)
|
||||||
rubocop-sequel (0.4.1)
|
rubocop-sequel (0.4.1)
|
||||||
lint_roller (~> 1.1)
|
lint_roller (~> 1.1)
|
||||||
rubocop (>= 1.72.1, < 2)
|
rubocop (>= 1.72.1, < 2)
|
||||||
@@ -65,16 +92,18 @@ GEM
|
|||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
sequel (5.93.0)
|
sequel (5.93.0)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
sinatra (3.2.0)
|
sinatra (4.1.1)
|
||||||
|
logger (>= 1.6.0)
|
||||||
mustermann (~> 3.0)
|
mustermann (~> 3.0)
|
||||||
rack (~> 2.2, >= 2.2.4)
|
rack (>= 3.0.0, < 4)
|
||||||
rack-protection (= 3.2.0)
|
rack-protection (= 4.1.1)
|
||||||
|
rack-session (>= 2.0.0, < 3)
|
||||||
tilt (~> 2.0)
|
tilt (~> 2.0)
|
||||||
sinatra-contrib (3.2.0)
|
sinatra-contrib (4.1.1)
|
||||||
multi_json (>= 0.0.2)
|
multi_json (>= 0.0.2)
|
||||||
mustermann (~> 3.0)
|
mustermann (~> 3.0)
|
||||||
rack-protection (= 3.2.0)
|
rack-protection (= 4.1.1)
|
||||||
sinatra (= 3.2.0)
|
sinatra (= 4.1.1)
|
||||||
tilt (~> 2.0)
|
tilt (~> 2.0)
|
||||||
sqlite3 (2.7.0-aarch64-linux-gnu)
|
sqlite3 (2.7.0-aarch64-linux-gnu)
|
||||||
sqlite3 (2.7.0-aarch64-linux-musl)
|
sqlite3 (2.7.0-aarch64-linux-musl)
|
||||||
@@ -104,14 +133,18 @@ PLATFORMS
|
|||||||
x86_64-linux-musl
|
x86_64-linux-musl
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
database_cleaner-sequel
|
||||||
logger
|
logger
|
||||||
puma (~> 6.6)
|
puma (~> 6.6)
|
||||||
|
rack-test
|
||||||
rerun
|
rerun
|
||||||
|
rspec
|
||||||
rubocop
|
rubocop
|
||||||
|
rubocop-rspec
|
||||||
rubocop-sequel
|
rubocop-sequel
|
||||||
sequel (~> 5.92)
|
sequel (~> 5.92)
|
||||||
sinatra (~> 3.2)
|
sinatra (~> 4.1)
|
||||||
sinatra-contrib (~> 3.2)
|
sinatra-contrib (~> 4.1)
|
||||||
sqlite3 (~> 2.6)
|
sqlite3 (~> 2.6)
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
|
|||||||
46
README.md
46
README.md
@@ -1,3 +1,7 @@
|
|||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
# Game Data
|
# Game Data
|
||||||
|
|
||||||
Web-based tool to store and organize PC hardware gaming benchmarks.
|
Web-based tool to store and organize PC hardware gaming benchmarks.
|
||||||
@@ -7,28 +11,58 @@ Web-based tool to store and organize PC hardware gaming benchmarks.
|
|||||||
The goals of this project are to:
|
The goals of this project are to:
|
||||||
|
|
||||||
* Record benchmarking results from multiple devices - e.g. log from a laptop or a phone.
|
* Record benchmarking results from multiple devices - e.g. log from a laptop or a phone.
|
||||||
* Group results into tests - it's good practice to run a benchmark multiple times for accuracy.
|
* 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.
|
* Create comparisons of hardware tests to compare performance.
|
||||||
* Generate graphs of hardware comparisons for usage in videos and articles.
|
* Generate graphs of hardware comparisons for usage in videos and articles.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
Game Data runs on Ruby, and takes advantage of Bundler to manage code dependencies and Rake to run various tasks for maintaining the app. You can install them globally like so:
|
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`
|
Debian/Ubuntu: `apt install -y ruby ruby-bundler rake`
|
||||||
|
RedHat and clones: `dnf install -y ruby rubygem-bundler rubygem-rake`
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
**TBD**
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
Install dependencies via bundler:
|
### 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`
|
`bundle install`
|
||||||
|
|
||||||
Perform database migrations:
|
2. Perform database migrations:
|
||||||
|
|
||||||
`rake db:migrate`
|
`rake db:migrate`
|
||||||
|
|
||||||
Run the server in development with auto-reloading:
|
3. Run the server in development with auto-reloading:
|
||||||
|
|
||||||
`rake server:dev`
|
`rake server:dev`
|
||||||
|
|
||||||
If everything is running successfully you can open your browser and go to https://localhost:9292.
|
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.
|
||||||
|
|||||||
22
Rakefile
22
Rakefile
@@ -3,18 +3,22 @@ require 'bundler/setup'
|
|||||||
namespace :db do
|
namespace :db do
|
||||||
desc 'Run migrations'
|
desc 'Run migrations'
|
||||||
task :migrate, [:version] do |t, args|
|
task :migrate, [:version] do |t, args|
|
||||||
require "sequel/core"
|
require 'sequel/core'
|
||||||
|
# load configuration
|
||||||
|
require_relative 'src/config'
|
||||||
|
conf = Config.new()
|
||||||
|
|
||||||
Sequel.extension :migration
|
Sequel.extension :migration
|
||||||
version = args[:version].to_i if args[:version]
|
version = args[:version].to_i if args[:version]
|
||||||
Sequel.connect('sqlite://data/gamedata.db') do |db|
|
Sequel.connect(adapter: conf.get('database.adapter'), database: conf.get('database.database')) do |db|
|
||||||
Sequel::Migrator.run(db, "db/migrations", target: version)
|
Sequel::Migrator.run(db, 'db/migrations', target: version)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :server do
|
namespace :server do
|
||||||
task :start do
|
task :start do
|
||||||
ENV['APP_ENV'] = 'production'
|
ENV['RACK_ENV'] = 'production'
|
||||||
system("puma")
|
system("puma")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -24,8 +28,12 @@ namespace :server do
|
|||||||
end
|
end
|
||||||
|
|
||||||
namespace :test do
|
namespace :test do
|
||||||
task :rubocop do
|
task :unit do
|
||||||
system("rubocop src/")
|
ENV['RACK_ENV'] = 'testing'
|
||||||
|
system("rspec")
|
||||||
|
end
|
||||||
|
|
||||||
|
task :lint do
|
||||||
|
system("rubocop src/ spec/")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
BIN
assets/img/app-logo.png
Normal file
BIN
assets/img/app-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/img/favicon.png
Normal file
BIN
assets/img/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1008 KiB |
@@ -1,3 +1,48 @@
|
|||||||
$ ->
|
$ ->
|
||||||
# run foundation scripts
|
# let us know when javascript is running.
|
||||||
console.log('Ready.')
|
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,
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
$ ->
|
$ ->
|
||||||
chartInstance = null
|
chartInstance = null
|
||||||
|
|
||||||
|
$('#report-benchmarks').on 'change', (e) ->
|
||||||
|
$('#report-tests option').prop('selected', false)
|
||||||
|
|
||||||
$('#reports-download').on 'click', (e) ->
|
$('#reports-download').on 'click', (e) ->
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
canvas = $('#benchmark-chart')[0]
|
canvas = $('#benchmark-chart')[0]
|
||||||
@@ -64,21 +67,14 @@ $ ->
|
|||||||
resultRes = await fetch("/api/v1/result/list?#{resultSearchParams}")
|
resultRes = await fetch("/api/v1/result/list?#{resultSearchParams}")
|
||||||
resultData = await resultRes.json()
|
resultData = await resultRes.json()
|
||||||
|
|
||||||
avg_total = 0
|
resultAverage = averageResults(resultData)
|
||||||
min_total = 0
|
|
||||||
max_total = 0
|
|
||||||
|
|
||||||
for result in resultData
|
|
||||||
avg_total += result.avg_score
|
|
||||||
min_total += result.min_score if result.min_score
|
|
||||||
max_total += result.max_score if result.max_score
|
|
||||||
|
|
||||||
data.labels.push(testData.name)
|
data.labels.push(testData.name)
|
||||||
data.datasets[0].data.push(avg_total / resultData.length)
|
data.datasets[0].data.push(resultAverage.avgScore)
|
||||||
console.log(data.datasets[0].data)
|
console.log(data.datasets[0].data)
|
||||||
switch benchmarkData.scoring
|
switch benchmarkData.scoring
|
||||||
when 'fps', 'ms'
|
when 'fps', 'ms'
|
||||||
data.datasets[1].data.push(min_total / resultData.length)
|
data.datasets[1].data.push(resultAverage.minScore)
|
||||||
catch error
|
catch error
|
||||||
console.error 'An error occurred while fetching benchmark results.', error
|
console.error 'An error occurred while fetching benchmark results.', error
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,7 @@ fetchTestBenchmarkResults = (testId, benchmarkId) ->
|
|||||||
resultRes = await fetch("/api/v1/result/list?#{resultSearchParams}")
|
resultRes = await fetch("/api/v1/result/list?#{resultSearchParams}")
|
||||||
resultData = await resultRes.json()
|
resultData = await resultRes.json()
|
||||||
|
|
||||||
avg_total = 0
|
resultAverage = averageResults(resultData)
|
||||||
min_total = 0
|
|
||||||
max_total = 0
|
|
||||||
|
|
||||||
for result in resultData
|
|
||||||
avg_total += result.avg_score
|
|
||||||
min_total += result.min_score
|
|
||||||
max_total += result.max_score
|
|
||||||
|
|
||||||
tableRow = $("#results-table tr[data-benchmark-id=#{benchmarkId}]")
|
tableRow = $("#results-table tr[data-benchmark-id=#{benchmarkId}]")
|
||||||
|
|
||||||
@@ -29,16 +22,18 @@ fetchTestBenchmarkResults = (testId, benchmarkId) ->
|
|||||||
tableRow.append('<td>' + resultData.length + '</td>')
|
tableRow.append('<td>' + resultData.length + '</td>')
|
||||||
|
|
||||||
if resultData.length != 0
|
if resultData.length != 0
|
||||||
tableRow.append('<td>' + (avg_total / resultData.length) + '</td>')
|
tableRow.append('<td>' + resultAverage.avgScore + '</td>')
|
||||||
|
|
||||||
|
if benchmarkData.scoring == 'fps'
|
||||||
|
tableRow.append('<td>' + resultAverage.minScore + '</td>')
|
||||||
|
tableRow.append('<td>' + resultAverage.maxScore + '</td>')
|
||||||
else
|
else
|
||||||
tableRow.append('<td>N/a</td>')
|
tableRow.append('<td>N/a</td>')
|
||||||
|
tableRow.append('<td>N/a</td>')
|
||||||
if min_total != 0
|
|
||||||
tableRow.append('<td>' + (min_total / resultData.length) + '</td>')
|
|
||||||
tableRow.append('<td>' + (max_total / resultData.length) + '</td>')
|
|
||||||
else
|
else
|
||||||
tableRow.append('<td>N/a</td>')
|
tableRow.append('<td>N/a</td>')
|
||||||
tableRow.append('<td>N/a</td>')
|
tableRow.append('<td>N/a</td>')
|
||||||
|
tableRow.append('<td>N/a</td>')
|
||||||
catch error
|
catch error
|
||||||
console.error 'An error occurred while fetching benchmark results.', error
|
console.error 'An error occurred while fetching benchmark results.', error
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,20 @@ body
|
|||||||
table
|
table
|
||||||
border: 1px solid #666
|
border: 1px solid #666
|
||||||
|
|
||||||
|
a
|
||||||
|
transition: color 220ms ease-in-out
|
||||||
|
|
||||||
#wrapper
|
#wrapper
|
||||||
background: white
|
background: white
|
||||||
padding: 1.5rem 2rem
|
padding: 1.5rem 2rem
|
||||||
border: 1px solid #bbb
|
border: 1px solid #bbb
|
||||||
border-radius: 8px
|
border-radius: 8px
|
||||||
|
|
||||||
|
#main-nav
|
||||||
|
li
|
||||||
|
a
|
||||||
|
font-size: 1.25rem
|
||||||
|
|
||||||
|
#site-title
|
||||||
|
img
|
||||||
|
max-height: 40px
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
# Load application config
|
# Load application config
|
||||||
require_relative 'src/config.rb'
|
|
||||||
$conf = Config.new(File.join(__dir__, 'config/defaults.yaml'))
|
|
||||||
|
|
||||||
root = ::File.dirname(__FILE__)
|
root = ::File.dirname(__FILE__)
|
||||||
require ::File.join( root, 'src', 'server' )
|
require ::File.join( root, 'src', 'server' )
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
database:
|
server:
|
||||||
adapter: 'sqlite'
|
host: '0.0.0.0'
|
||||||
database: 'data/gamedata.db'
|
port: '9292'
|
||||||
|
|
||||||
testing:
|
testing:
|
||||||
minimum_results_required: 3
|
minimum_results_required: 3
|
||||||
|
|||||||
3
config/development.yaml
Normal file
3
config/development.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
database:
|
||||||
|
adapter: 'sqlite'
|
||||||
|
database: 'data/gamedata.db'
|
||||||
@@ -3,7 +3,9 @@ directory app_dir
|
|||||||
|
|
||||||
environment ENV.fetch('RACK_ENV', 'development')
|
environment ENV.fetch('RACK_ENV', 'development')
|
||||||
|
|
||||||
bind 'tcp://0.0.0.0:9292'
|
require_relative '../src/config'
|
||||||
|
conf = Config.new()
|
||||||
|
|
||||||
|
bind "tcp://#{conf.get('server.host')}:#{conf.get('server.port')}"
|
||||||
workers 2
|
workers 2
|
||||||
threads 1, 5
|
threads 1, 5
|
||||||
|
|
||||||
|
|||||||
3
config/testing.yaml
Normal file
3
config/testing.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
database:
|
||||||
|
adapter: 'sqlite'
|
||||||
|
database: 'data/gamedata_testing.db'
|
||||||
97
db/migrations/0004_add_benchmarksettings_table.rb
Normal file
97
db/migrations/0004_add_benchmarksettings_table.rb
Normal file
@@ -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
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
if [ ! -f ./data/gamedata.db ]; then
|
# Run the migrations to make sure the DB is up-to-date
|
||||||
rake db:migrate
|
echo 'Checking database status...'
|
||||||
fi
|
rake db:migrate
|
||||||
|
|
||||||
|
# Start the HTTP server
|
||||||
|
echo 'Starting development server...'
|
||||||
rake server:dev
|
rake server:dev
|
||||||
|
|||||||
@@ -20,16 +20,23 @@ function compileCoffee() {
|
|||||||
.pipe(gulp.dest('public/js', { sourcemaps: '.' }));
|
.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
|
// Watch files for changes
|
||||||
function watchFiles(cb) {
|
function watchFiles(cb) {
|
||||||
gulp.watch('assets/styles/**/*.sass', compileSass);
|
gulp.watch('assets/styles/**/*.sass', compileSass);
|
||||||
gulp.watch('assets/scripts/**/*.coffee', compileCoffee);
|
gulp.watch('assets/scripts/**/*.coffee', compileCoffee);
|
||||||
|
gulp.watch('assets/img/**/*', copyImages)
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chain all asset builds together
|
// Chain all asset builds together
|
||||||
function buildAssets() {
|
function buildAssets() {
|
||||||
return gulp.parallel(compileSass, compileCoffee);
|
return gulp.parallel(compileSass, compileCoffee, copyImages);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform initial build then watch
|
// Perform initial build then watch
|
||||||
|
|||||||
137
spec/controllers/benchmark_controller_spec.rb
Normal file
137
spec/controllers/benchmark_controller_spec.rb
Normal file
@@ -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
|
||||||
132
spec/controllers/hardware_controller_spec.rb
Normal file
132
spec/controllers/hardware_controller_spec.rb
Normal file
@@ -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
|
||||||
25
spec/controllers/index_controller_spec.rb
Normal file
25
spec/controllers/index_controller_spec.rb
Normal file
@@ -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
|
||||||
21
spec/controllers/reports_controller_spec.rb
Normal file
21
spec/controllers/reports_controller_spec.rb
Normal file
@@ -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
|
||||||
165
spec/controllers/test_controller_spec.rb
Normal file
165
spec/controllers/test_controller_spec.rb
Normal file
@@ -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
|
||||||
27
spec/models/benchmark_model_spec.rb
Normal file
27
spec/models/benchmark_model_spec.rb
Normal file
@@ -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
|
||||||
25
spec/models/hardware_model_spec.rb
Normal file
25
spec/models/hardware_model_spec.rb
Normal file
@@ -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
|
||||||
36
spec/models/test_model_spec.rb
Normal file
36
spec/models/test_model_spec.rb
Normal file
@@ -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
|
||||||
35
spec/spec_helper.rb
Normal file
35
spec/spec_helper.rb
Normal file
@@ -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
|
||||||
@@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
module AppInfo
|
module AppInfo
|
||||||
|
|
||||||
VERSION = '0.1.1'
|
VERSION = '0.2.1'
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ require 'yaml'
|
|||||||
class Config
|
class Config
|
||||||
|
|
||||||
DEFAULT_CONFIG = 'config/defaults.yaml'
|
DEFAULT_CONFIG = 'config/defaults.yaml'
|
||||||
|
ENVIRONMENT_CONFIG = ENV.fetch('RACK_ENV', 'development')
|
||||||
|
|
||||||
def initialize(config_path)
|
def initialize(config_path = "config/#{ENVIRONMENT_CONFIG}.yaml")
|
||||||
@data = YAML.load_file(DEFAULT_CONFIG)
|
@data = YAML.load_file(DEFAULT_CONFIG)
|
||||||
|
|
||||||
# merge in user-defined configuration if it exists
|
# merge in user-defined configuration if it exists
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
# frozen_string_literal: true
|
# 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
|
# /api/v1 routes
|
||||||
class GameData < Sinatra::Base
|
class APIv1Controller < BaseController
|
||||||
|
|
||||||
get '/api/v1/benchmark/details' do
|
get '/api/v1/benchmark/details' do
|
||||||
benchmark_id = params[:benchmark_id]
|
benchmark_id = params[:benchmark_id]
|
||||||
15
src/controllers/base_controller.rb
Normal file
15
src/controllers/base_controller.rb
Normal file
@@ -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
|
||||||
@@ -1,9 +1,16 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/benchmark'
|
||||||
|
|
||||||
# /benchmark routes
|
# /benchmark routes
|
||||||
class GameData < Sinatra::Base
|
class BenchmarkController < BaseController
|
||||||
|
|
||||||
get '/benchmark' do
|
get '/benchmark' do
|
||||||
|
redirect('/benchmark/list')
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/benchmark/list' do
|
||||||
benchmarks = Benchmark.reverse(:updated_at).limit(10).all()
|
benchmarks = Benchmark.reverse(:updated_at).limit(10).all()
|
||||||
|
|
||||||
erb :'benchmark/index', locals: {
|
erb :'benchmark/index', locals: {
|
||||||
@@ -1,9 +1,17 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/hardware'
|
||||||
|
require_relative '../models/benchmark'
|
||||||
|
|
||||||
# /hardware routes
|
# /hardware routes
|
||||||
class GameData < Sinatra::Base
|
class HardwareController < BaseController
|
||||||
|
|
||||||
get '/hardware' do
|
get '/hardware' do
|
||||||
|
redirect('/hardware/list')
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/hardware/list' do
|
||||||
hardware = Hardware.reverse(:updated_at).limit(10).all()
|
hardware = Hardware.reverse(:updated_at).limit(10).all()
|
||||||
|
|
||||||
erb :'hardware/index', locals: {
|
erb :'hardware/index', locals: {
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/test'
|
||||||
|
require_relative '../models/benchmark_profile'
|
||||||
|
|
||||||
# / (top-level) routes
|
# / (top-level) routes
|
||||||
class GameData < Sinatra::Base
|
class IndexController < BaseController
|
||||||
|
|
||||||
get '/' do
|
get '/' do
|
||||||
tests = Test.reverse(:updated_at).limit(10).all()
|
tests = Test.reverse(:updated_at).limit(10).all()
|
||||||
@@ -1,7 +1,14 @@
|
|||||||
# frozen_string_literal: true
|
# 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
|
# /reports routes
|
||||||
class GameData < Sinatra::Base
|
class ReportsController < BaseController
|
||||||
|
|
||||||
get '/report' do
|
get '/report' do
|
||||||
benchmarks = Benchmark.order(:name).all()
|
benchmarks = Benchmark.order(:name).all()
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/result'
|
||||||
|
|
||||||
# /result routes
|
# /result routes
|
||||||
class GameData < Sinatra::Base
|
class ResultController < BaseController
|
||||||
|
|
||||||
post '/result/add' do
|
post '/result/add' do
|
||||||
result_minimum = params[:result_minimum] if params.key?(:result_minimum)
|
result_minimum = params[:result_minimum] if params.key?(:result_minimum)
|
||||||
@@ -9,7 +12,7 @@ class GameData < Sinatra::Base
|
|||||||
|
|
||||||
Result.create(
|
Result.create(
|
||||||
test_id: params[:result_test],
|
test_id: params[:result_test],
|
||||||
benchmark_id: params[:result_benchmark],
|
benchmark_profile_id: params[:result_benchmark],
|
||||||
avg_score: params[:result_average],
|
avg_score: params[:result_average],
|
||||||
min_score: result_minimum,
|
min_score: result_minimum,
|
||||||
max_score: result_maximum
|
max_score: result_maximum
|
||||||
@@ -1,9 +1,18 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'base_controller'
|
||||||
|
require_relative '../models/benchmark'
|
||||||
|
require_relative '../models/hardware'
|
||||||
|
require_relative '../models/test'
|
||||||
|
|
||||||
# /test routes
|
# /test routes
|
||||||
class GameData < Sinatra::Base
|
class TestController < BaseController
|
||||||
|
|
||||||
get '/test' do
|
get '/test' do
|
||||||
|
redirect('/test/list')
|
||||||
|
end
|
||||||
|
|
||||||
|
get '/test/list' do
|
||||||
tests = Test.reverse(:updated_at).limit(10).all()
|
tests = Test.reverse(:updated_at).limit(10).all()
|
||||||
|
|
||||||
erb :'test/index', locals: {
|
erb :'test/index', locals: {
|
||||||
@@ -33,7 +42,7 @@ class GameData < Sinatra::Base
|
|||||||
benchmarks = Array(params[:test_benchmarks])
|
benchmarks = Array(params[:test_benchmarks])
|
||||||
# associate the benchmarks to the test
|
# associate the benchmarks to the test
|
||||||
benchmarks.each do |b|
|
benchmarks.each do |b|
|
||||||
tst.add_benchmark(b)
|
tst.add_benchmark_profile(b)
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect "/test/#{tst.id}"
|
redirect "/test/#{tst.id}"
|
||||||
@@ -65,9 +74,22 @@ class GameData < Sinatra::Base
|
|||||||
|
|
||||||
tst.update(
|
tst.update(
|
||||||
name: params[:test_name],
|
name: params[:test_name],
|
||||||
type: params[:test_type]
|
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}"
|
redirect "/test/#{tst.id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative 'appinfo'
|
||||||
|
|
||||||
# Helpers - view helper functions
|
# Helpers - view helper functions
|
||||||
module Helpers
|
module Helpers
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
# Benchmark - database model for PC benchmarks
|
# Benchmark - database model for PC benchmarks
|
||||||
class Benchmark < Sequel::Model
|
class Benchmark < Sequel::Model
|
||||||
|
|
||||||
many_to_many :tests
|
one_to_many :benchmark_profiles
|
||||||
one_to_many :results
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
14
src/models/benchmark_profile.rb
Normal file
14
src/models/benchmark_profile.rb
Normal file
@@ -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
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require_relative 'hardware'
|
|
||||||
require_relative 'benchmark'
|
|
||||||
require_relative 'result'
|
|
||||||
require_relative 'test'
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
class Result < Sequel::Model
|
class Result < Sequel::Model
|
||||||
|
|
||||||
many_to_one :test
|
many_to_one :test
|
||||||
many_to_one :benchmark
|
many_to_one :benchmark_profile
|
||||||
|
|
||||||
def formatted_score
|
def formatted_score
|
||||||
return @avg_score
|
return @avg_score
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ class Test < Sequel::Model
|
|||||||
|
|
||||||
one_to_many :result
|
one_to_many :result
|
||||||
many_to_one :hardware
|
many_to_one :hardware
|
||||||
many_to_many :benchmarks
|
many_to_many :benchmark_profiles
|
||||||
|
|
||||||
|
def benchmark?(benchmark_id)
|
||||||
|
return benchmark_profiles_dataset.where(Sequel[:benchmark_profiles][:id] => benchmark_id).any?
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require_relative 'index'
|
|
||||||
require_relative 'hardware'
|
|
||||||
require_relative 'benchmark'
|
|
||||||
require_relative 'reports'
|
|
||||||
require_relative 'result'
|
|
||||||
require_relative 'test'
|
|
||||||
|
|
||||||
require_relative 'api1'
|
|
||||||
38
src/server.rb
Executable file → Normal file
38
src/server.rb
Executable file → Normal file
@@ -1,18 +1,32 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'sinatra/base'
|
require 'sinatra/base'
|
||||||
require 'sinatra/json'
|
|
||||||
require 'sequel'
|
require 'sequel'
|
||||||
require 'sqlite3'
|
require 'sqlite3'
|
||||||
|
|
||||||
require_relative 'appinfo'
|
require_relative 'config'
|
||||||
|
|
||||||
|
# Load configuration from environment config file
|
||||||
|
$conf = Config.new()
|
||||||
|
|
||||||
# Load the Sequel timestamps plugin
|
# Load the Sequel timestamps plugin
|
||||||
Sequel::Model.plugin(:timestamps)
|
Sequel::Model.plugin(:timestamps)
|
||||||
# Initialize Sequel gem for database actions
|
# Initialize Sequel gem for database actions
|
||||||
DB = Sequel.connect(adapter: $conf.get('database.adapter'), database: $conf.get('database.database'))
|
DB = Sequel.connect(adapter: $conf.get('database.adapter'), database: $conf.get('database.database'))
|
||||||
|
|
||||||
# Base app
|
# 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
|
class GameData < Sinatra::Base
|
||||||
|
|
||||||
enable :sessions
|
enable :sessions
|
||||||
@@ -21,16 +35,12 @@ class GameData < Sinatra::Base
|
|||||||
enable :static
|
enable :static
|
||||||
set :public_folder, File.join(__dir__, '/../public')
|
set :public_folder, File.join(__dir__, '/../public')
|
||||||
|
|
||||||
# Register view helpers
|
use IndexController
|
||||||
require_relative 'helpers'
|
use HardwareController
|
||||||
helpers Helpers
|
use BenchmarkController
|
||||||
|
use TestController
|
||||||
# Set up our view engine
|
use ResultController
|
||||||
set :views, File.join(settings.root, '/../views')
|
use ReportsController
|
||||||
|
use APIv1Controller
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Load routes
|
|
||||||
require_relative 'routes/init'
|
|
||||||
# Load models
|
|
||||||
require_relative 'models/init'
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label for="benchmark_description">Benchmark description</label>
|
<label for="benchmark_description">Benchmark description</label>
|
||||||
<textarea id="benchmark_description" class="form-control" name="benchmark_description">Enter a description/notes here.</textarea>
|
<textarea id="benchmark_description" class="form-control" name="benchmark_description" placeholder="Enter a description/notes here."></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label for="benchmark_description">Benchmark description</label>
|
<label for="benchmark_description">Benchmark description</label>
|
||||||
<textarea id="benchmark_description" class="form-control" name="benchmark_description"><%= benchmark.description %></textarea>
|
<textarea id="benchmark_description" class="form-control" name="benchmark_description" placeholder="Enter a description/notes here."><%= benchmark.description %></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -21,29 +21,31 @@
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h3 class="mb-3">Tests using this benchmark:</h3>
|
<h3 class="mb-3">Profiles created for this benchmark:</h3>
|
||||||
|
|
||||||
<% if benchmark.tests.length > 0 %>
|
<% if benchmark.benchmark_profiles.length > 0 %>
|
||||||
<table class="table table-hover table-responsive">
|
<table class="table table-hover table-responsive">
|
||||||
<thead class="table-light">
|
<thead class="table-light">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Test title</th>
|
<th>Profile Label</th>
|
||||||
<th>Benchmarks</th>
|
<th>Tests Linked</th>
|
||||||
|
<th>Created at</th>
|
||||||
<th>Last updated</th>
|
<th>Last updated</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% benchmark.tests.each do |t| %>
|
<% benchmark.benchmark_profiles.each do |bp| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
<td><%= bp.display_name %></td>
|
||||||
<td><%= t.benchmarks.length %></td>
|
<td><%= bp.tests.length %></td>
|
||||||
<td><%= t.updated_at %></td>
|
<td><%= bp.created_at %></td>
|
||||||
|
<td><%= bp.updated_at %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p>There are no tests associated with this benchmark.</p>
|
<p>There are no profiles associated with this benchmark.</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,16 +8,16 @@
|
|||||||
<table class="table table-hover table-responsive">
|
<table class="table table-hover table-responsive">
|
||||||
<thead class="table-light">
|
<thead class="table-light">
|
||||||
<tr>
|
<tr>
|
||||||
<th>Test name</th>
|
<th data-sort="name">Test name</th>
|
||||||
<th># Benchmarks</th>
|
<th data-sort="benchmark-count"># Benchmarks</th>
|
||||||
<th>Last Updated</th>
|
<th data-sort="updated'">Last Updated</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% tests.each do |t| %>
|
<% tests.each do |t| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
||||||
<td><%= t.benchmarks.length %></td>
|
<td><%= t.benchmark_profiles.length %></td>
|
||||||
<td><%= t.updated_at %></td>
|
<td><%= t.updated_at %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<link rel="shortcut icon" href="/img/favicon.png">
|
||||||
<title><%= title %> | Game Data</title>
|
<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="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/css/bootstrap.min.css">
|
||||||
<link rel="stylesheet" href="/css/rimmington.css">
|
<link rel="stylesheet" href="/css/rimmington.css">
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<div id="main-nav" class="navbar navbar-expand-md bg-dark border-bottom border-body mb-3" data-bs-theme="dark">
|
<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">
|
<div class="container-fluid">
|
||||||
<a class="navbar-brand mb-0 h1" href="#">Game Data</a>
|
<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">
|
<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>
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h1>Generate report</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<form class="col-12" action="/reports" method="post">
|
<form class="col-12" action="/reports" method="post">
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
|
|||||||
@@ -28,7 +28,9 @@
|
|||||||
<label for="test_benchmarks">Benchmarks</label>
|
<label for="test_benchmarks">Benchmarks</label>
|
||||||
<select id="test_benchmarks" class="form-select" name="test_benchmarks[]" multiple>
|
<select id="test_benchmarks" class="form-select" name="test_benchmarks[]" multiple>
|
||||||
<% for b in benchmarks %>
|
<% for b in benchmarks %>
|
||||||
<option value="<%= b.id %>"><%= b.name %></option>
|
<% for bp in b.benchmark_profiles %>
|
||||||
|
<option value="<%= bp.id %>"><%= bp.display_name %></option>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,7 +28,9 @@
|
|||||||
<label for="test_benchmarks">Benchmarks</label>
|
<label for="test_benchmarks">Benchmarks</label>
|
||||||
<select id="test_benchmarks" class="form-select" name="test_benchmarks[]" multiple>
|
<select id="test_benchmarks" class="form-select" name="test_benchmarks[]" multiple>
|
||||||
<% for b in benchmarks %>
|
<% for b in benchmarks %>
|
||||||
<option value="<%= b.id %>"><%= b.name %></option>
|
<% for bp in b.benchmark_profiles %>
|
||||||
|
<option value="<%= bp.id %>" <% if test.benchmark?(bp.id) %>selected<% end %>><%= bp.display_name %></option>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -41,7 +43,7 @@
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<input class="btn btn-primary w-100" type="submit" value="Create Test">
|
<input class="btn btn-primary w-100" type="submit" value="Submit Changes">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<% tests.each do |t| %>
|
<% tests.each do |t| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
<td><a href="/test/<%= t.id %>"><%= t.name %></a></td>
|
||||||
<td><%= t.benchmarks.length %></td>
|
<td><%= t.benchmark_profiles.length %></td>
|
||||||
<td><%= date_format(t.created_at) %></td>
|
<td><%= date_format(t.created_at) %></td>
|
||||||
<td><%= date_format(t.updated_at) %></td>
|
<td><%= date_format(t.updated_at) %></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
<div class="col-12 col-md-5 mb-3 mb-md-0">
|
<div class="col-12 col-md-5 mb-3 mb-md-0">
|
||||||
<label for="result_benchmark">Add benchmark result:</label>
|
<label for="result_benchmark">Add benchmark result:</label>
|
||||||
<select class="form-select" id="result_benchmark" name="result_benchmark">
|
<select class="form-select" id="result_benchmark" name="result_benchmark">
|
||||||
<% test.benchmarks.each do |b| %>
|
<% test.benchmark_profiles.each do |b| %>
|
||||||
<option value="<%= b.id %>"><%= b.name %></option>
|
<option value="<%= b.id %>"><%= b.display_name %></option>
|
||||||
<% end %>
|
<% end %>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -71,8 +71,8 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% test.benchmarks.each do |benchmark| %>
|
<% test.benchmark_profiles.each do |bp| %>
|
||||||
<tr data-benchmark-id="<%= benchmark.id %>"></tr>
|
<tr data-benchmark-id="<%= bp.id %>"></tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
Reference in New Issue
Block a user