Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve test performance #3052

Merged
merged 28 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
59a0097
add test-prof
bmesuere Aug 30, 2021
1c05c89
Make institution optional in the user factory
bmesuere Aug 30, 2021
f1aba5d
Make programming language optional for exercise factory
bmesuere Aug 31, 2021
43d6f20
Add fixture for a default judge
bmesuere Aug 31, 2021
980608c
Add fixture for a default repo
bmesuere Aug 31, 2021
7ac9974
add user fixtures
bmesuere Aug 31, 2021
1eeaa49
simplify submission factory
bmesuere Aug 31, 2021
208e109
use user and exercise fixtures when generating submissions
bmesuere Aug 31, 2021
78b0bec
add course fixture
bmesuere Aug 31, 2021
2d6bfd8
optimize activity test
bmesuere Sep 1, 2021
fdbf5db
optimize activity status test
bmesuere Sep 1, 2021
e6dcc75
optimize annotation test
bmesuere Sep 1, 2021
19de66e
rubocop
bmesuere Sep 1, 2021
a2d23f3
optimize api_token test
bmesuere Sep 1, 2021
9e85809
optimize course test
bmesuere Sep 1, 2021
146af27
optimize evaluation exercise test
bmesuere Sep 1, 2021
15afd1f
optimize evaluation test
bmesuere Sep 1, 2021
2a1dd5f
optimize exercise test
bmesuere Sep 1, 2021
0f75a1b
optimize institution test
bmesuere Sep 1, 2021
f5ead85
optimize repo test
bmesuere Sep 1, 2021
11c6eb6
optimize submission test
bmesuere Sep 1, 2021
951e9f6
optimize user tests
bmesuere Sep 1, 2021
eff4bb0
optimize activities controller test
bmesuere Sep 2, 2021
2368447
optimize annotations controller test
bmesuere Sep 2, 2021
1f28bfb
optimize courses controller tests
bmesuere Sep 2, 2021
136e4d4
opzitmize e* controller tests
bmesuere Sep 2, 2021
5f7b2f2
optimize the rest of the controller tests
bmesuere Sep 2, 2021
208691b
add info to the readme on how to run tests
bmesuere Sep 2, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ group :test do
gem 'codecov', '~> 0.6.0', require: false
gem 'minitest-ci', '~> 3.4.0'
gem 'simplecov', '~> 0.21.2', require: false
gem 'test-prof', '~> 1.0.7'
end

group :development do
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ GEM
activesupport (>= 3)
attr_required (>= 0.0.5)
httpclient (>= 2.4)
test-prof (1.0.7)
thor (1.1.0)
tilt (2.0.10)
tzinfo (2.0.4)
Expand Down Expand Up @@ -535,6 +536,7 @@ DEPENDENCIES
spring (~> 2.1.1)
spring-watcher-listen (~> 2.0.1)
stackprof (~> 0.2.17)
test-prof (~> 1.0.7)
tzinfo-data
uglifier (>= 4.1.20)
web-console (~> 4.1.0)
Expand Down
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ If you want to help with development, issues tagged with the [student label](htt
...
GRANT ALL ON dodona_test-3.* TO 'dodona';
```
4. Create and seed the database with `rails db:setup`. (If something goes wrong with the database, you can use `rails db:reset` to drop, rebuild and reseed the database.)
4. Create and seed the database with `rails db:setup`. (If something goes wrong with the database, you can use `rails db:reset` to drop, rebuild and reseed the database.)
If the error "Could not initialize python judge" arises, use `SKIP_PYTHON_JUDGE=true rails db:setup`
5. [Start the server](#starting-the-server). The simplest way is with `rails s`. Dodona [will be available on a subdomain of localhost](#localhost-subdomain): http://dodona.localhost:3000.
6. Because CAS authentication does not work in development, you can log in by going to these pages (only works with the seed database form step 4)
Expand Down Expand Up @@ -89,3 +89,18 @@ If this does not work out of the box you can add the following lines to your `/e
127.0.0.1 dodona.localhost
127.0.0.1 sandbox.localhost
```

### Running linters and tests

To lint the code, run `rubocop` for Ruby and `yarn lint` for JavaScript.

We have tests in JavaScript, Ruby, and system tests:

* For JavaScript, run `yarn test`
* For the system tests, run `bundle exec rails test:system`
* For the ruby tests, run `bundle exec rails test`

**Tips**
* Use the `PARALLEL_WORKERS` ENV var to specify the number of threads to use.
* Use `TestProf` to profile the ruby tests
* Use `bundle exec rails test filename` to run a single test file, use `bundle exec rails test filename:linenumber` to run a specific test
81 changes: 42 additions & 39 deletions test/controllers/activities_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ class ActivitiesControllerTest < ActionDispatch::IntegrationTest
extend CRUDTest

def setup
@instance = create(:exercise, :description_html)
@user = create(:zeus)
@instance = exercises(:python_exercise)
@user = users(:zeus)
sign_in @user
end

Expand Down Expand Up @@ -79,7 +79,7 @@ def setup
test 'should show activity info' do
stub_all_activities!
# Attach exercise to courses to test sorting
create_list(:course, 5).each { |s| s.series << create(:series, exercises: [@instance]) }
create_list(:course, 2).each { |s| s.series << create(:series, exercises: [@instance]) }
get info_activity_url(@instance)
assert_response :success
end
Expand Down Expand Up @@ -168,6 +168,7 @@ def setup
end

test 'should get media with token on sandbox_host' do
@instance = create(:exercise, :description_html)
sign_out :user
Exercise.any_instance.stubs(:media_path).returns(Pathname.new('public'))
@instance.update access: :private
Expand All @@ -191,17 +192,16 @@ def setup
end

test 'should get activities by type' do
cp = create :content_page
ex = @instance
start_exercises = Activity.exercises.count
start_content = Activity.content_pages.count
get activities_url(format: :json, type: ContentPage.name)
assert_equal 1, JSON.parse(response.body).count
assert_equal cp.id, JSON.parse(response.body)[0]['id']
assert_equal start_content, JSON.parse(response.body).count
get activities_url(format: :json, type: Exercise.name)
assert_equal 1, JSON.parse(response.body).count
assert_equal ex.id, JSON.parse(response.body)[0]['id']
assert_equal start_exercises, JSON.parse(response.body).count
end

test 'should get activities with certain description languages available' do
@instance = create(:exercise, :description_html)
# @instance has a Dutch and Englisch description
get activities_url(format: :json, description_languages: ['en'])
assert_equal 1, JSON.parse(response.body).count
Expand Down Expand Up @@ -231,18 +231,19 @@ def setup
test 'should get activities filtered by judge' do
judge = @instance.judge
get activities_url(format: :json, judge_id: judge.id)
assert_equal 1, JSON.parse(response.body).count
assert_equal Activity.where(judge: judge).count, JSON.parse(response.body).count
assert_equal @instance.id, JSON.parse(response.body)[0]['id']

get activities_url(format: :json, judge_id: Judge.all.last.id + 1)
assert_equal 0, JSON.parse(response.body).count
end

test 'should get available activities for series' do
start_exercises = Activity.exercises.count
course = create :course, usable_repositories: [@instance.repository]
other_exercise = create :exercise
series_exercise = create :exercise, repository: @instance.repository
create :exercise # Other exercise that should never show up
create :exercise, :generated_repo # Other exercise that should never show up
series = create :series, course: course, exercises: [series_exercise]
admin = create :staff, administrating_courses: [course], repositories: [other_exercise.repository]

Expand All @@ -257,7 +258,7 @@ def setup
assert result_exercises.any? { |ex| ex['id'] == @instance.id }, 'should contain exercise usable by course'
assert result_exercises.any? { |ex| ex['id'] == other_exercise.id }, 'should contain exercise usable by repo admin'
assert result_exercises.any? { |ex| ex['id'] == series_exercise.id }, 'should also contain exercises already used by series'
assert_equal 3, result_exercises.count, 'should only contain available exercises'
assert_equal start_exercises + 2, result_exercises.count, 'should only contain available exercises'
end

test 'should get available activities for course with labels' do
Expand Down Expand Up @@ -371,17 +372,17 @@ def assert_response_contains_activity(activity, msg = nil)
end

test 'should list all activities within series' do
exercises = create_list :exercise, 10, repository: @instance.repository
exercises_in_series = exercises.take(5)
exercises = create_list :exercise, 2, repository: @instance.repository
exercises_in_series = exercises
series = create :series, exercises: exercises_in_series
create :series, activities: create_list(:exercise, 5)
create :series, activities: create_list(:exercise, 2)
series.course.usable_repositories << @instance.repository

get series_activities_url(series, format: :json)

assert_response :success
exercises_response = JSON.parse response.body
assert_equal 5, exercises_response.count
assert_equal 2, exercises_response.count

exercise_response_ids = exercises_response.map do |ex|
ex['id']
Expand All @@ -406,7 +407,7 @@ class ActivitiesPermissionControllerTest < ActionDispatch::IntegrationTest
setup do
# stub file access
Exercise.any_instance.stubs(:description_localized).returns("it's something")
@user = create :user
@user = users(:student)
sign_in @user
end

Expand All @@ -415,7 +416,7 @@ def show_activity
end

test 'user should be able to see activity' do
@instance = create :exercise
@instance = exercises(:python_exercise)
show_activity
assert_response :success
end
Expand All @@ -434,7 +435,7 @@ def show_activity
end

test 'admin should be able to see invalid activity' do
sign_in create(:staff)
sign_in users(:staff)
@instance = create :exercise, :nameless
show_activity
assert_response :success
Expand All @@ -449,7 +450,7 @@ def show_activity

test 'unauthenticated user should be able to see public activity' do
sign_out :user
@instance = create :exercise
@instance = exercises(:python_exercise)
show_activity
assert_response :success
end
Expand Down Expand Up @@ -493,7 +494,7 @@ def show_activity
end

test 'should get activity media because record is ok' do
@instance = create(:exercise, :description_html)
@instance = exercises(:python_exercise)
Exercise.any_instance.stubs(:media_path).returns(Pathname.new('public'))

get("#{activity_url(@instance)}/media/icon.png")
Expand All @@ -503,7 +504,7 @@ def show_activity
end

test 'should get activity media because user has submissions' do
@instance = create(:exercise, :description_html)
@instance = exercises(:python_exercise)
Exercise.any_instance.stubs(:ok?).returns(false)
create :submission, exercise: @instance, user: @user
Exercise.any_instance.stubs(:media_path).returns(Pathname.new('public'))
Expand Down Expand Up @@ -532,7 +533,7 @@ def show_activity
end

test 'should get redirected from activity media to root_url because user has no submissions and activity is not ok' do
@instance = create(:exercise, :description_html)
@instance = exercises(:python_exercise)
Exercise.any_instance.stubs(:ok?).returns(false)
Exercise.any_instance.stubs(:media_path).returns(Pathname.new('public'))

Expand All @@ -542,7 +543,7 @@ def show_activity
end

test 'should get redirected from exercise media to sign_in_url because user is not signed in' do
@instance = create(:exercise, :description_html)
@instance = exercises(:python_exercise)
Exercise.any_instance.stubs(:ok?).returns(false)
Exercise.any_instance.stubs(:media_path).returns(Pathname.new('public'))
sign_out @user
Expand All @@ -561,7 +562,7 @@ def show_activity

test 'should access public activity media on default host with token' do
sign_out :user
@instance = create(:exercise, :description_html)
@instance = exercises(:python_exercise)
Exercise.any_instance.stubs(:media_path).returns(Pathname.new('public'))
get(activity_url(@instance) + "media/icon.png?token=#{@instance.access_token}")

Expand All @@ -584,31 +585,33 @@ def create_exercises_return_valid
end

test 'exercise overview should not include closed, hidden or invalid exercises' do
start_activities = Activity.count
visible = create_exercises_return_valid

get activities_url, params: { format: :json }

exercises = JSON.parse response.body
assert_equal 1, exercises.length
assert_equal start_activities + 1, exercises.length
assert_equal visible.id, exercises.first['id']
end

test 'exercise overview should include everything for admin' do
start = Exercise.count
create_exercises_return_valid
sign_out :user
sign_in create(:zeus)
sign_in users(:zeus)

get activities_url, params: { format: :json }

exercises = JSON.parse response.body
assert_equal 3, exercises.length
assert_equal 3, exercises.length - start
end

test 'exercise solved in other course should not take into account solutions from different course' do
ex = create_exercises_return_valid
s1 = create :series
s1 = create :series, :generated_course
s1.exercises << ex
s2 = create :series
s2 = create :series, :generated_course
s2.exercises << ex
s1.course.enrolled_members << @user
s2.course.enrolled_members << @user
Expand All @@ -632,9 +635,9 @@ def create_exercises_return_valid

test 'reading activity read in other course should not take into account read state from different course' do
ra = create :content_page
s1 = create :series
s1 = create :series, :generated_course
s1.content_pages << ra
s2 = create :series
s2 = create :series, :generated_course
s2.content_pages << ra
s1.course.enrolled_members << @user
s2.course.enrolled_members << @user
Expand Down Expand Up @@ -688,14 +691,14 @@ class ExerciseDescriptionTest < ActionDispatch::IntegrationTest
What is the airspeed of an unladen swallow?
DESC

@exercise = create :exercise, :valid, description_format: 'md'
@exercise = exercises(:python_exercise)
Exercise.any_instance.stubs(:description_localized).returns(desciption_md)
Exercise.any_instance.stubs(:update_config)
stub_status(Exercise.any_instance, 'ok')
end

test 'iframe to exercise description should be present in the page' do
sign_in create :user
sign_in users(:student)
get activity_url(@exercise).concat('/')

assert_includes response.body, description_activity_url(@exercise, token: @exercise.access_token)
Expand All @@ -714,8 +717,8 @@ class ExerciseDescriptionTest < ActionDispatch::IntegrationTest
end

test 'exercise page within series should contain extra navigation' do
course = create :course
exercise = create :exercise
course = courses(:course1)
exercise = exercises(:python_exercise)
other_exercise = create :exercise
series = create :series, course: course, exercises: [exercise, other_exercise]

Expand All @@ -726,8 +729,8 @@ class ExerciseDescriptionTest < ActionDispatch::IntegrationTest
end

test 'exercise page without series should not contain extra navigation' do
course = create :course
exercise = create :exercise
course = courses(:course1)
exercise = exercises(:python_exercise)
other_exercise = create :exercise
create :series, course: course, exercises: [exercise, other_exercise]

Expand All @@ -738,7 +741,7 @@ class ExerciseDescriptionTest < ActionDispatch::IntegrationTest
end

test 'json representation of exercise should contain the sandbox and access token in its description url' do
exercise = create :exercise
exercise = exercises(:python_exercise)

get activity_url(exercise), params: { format: :json }

Expand Down
Loading