diff --git a/tests/constants/time.py b/tests/constants/time.py new file mode 100644 index 00000000..2c01ab26 --- /dev/null +++ b/tests/constants/time.py @@ -0,0 +1,9 @@ +from CTFd.constants import RawEnum + + +class FreezeTimes(str, RawEnum): + NOT_STARTED = "2017-10-3" # Tuesday, October 3, 2017 + STARTED = "2017-10-5" # Thursday, October 5, 2017 + ENDED = "2017-10-7" # Saturday, October 7, 2017 + START = "1507089600" # Wednesday, October 4, 2017 12:00:00 AM GMT-04:00 DST + END = "1507262400" # Friday, October 6, 2017 12:00:00 AM GMT-04:00 DST diff --git a/tests/helpers.py b/tests/helpers.py index 07572ed4..6ff2ae67 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -4,10 +4,12 @@ import random import string import uuid from collections import namedtuple +from contextlib import contextmanager from unittest.mock import Mock, patch import requests from flask.testing import FlaskClient +from freezegun import freeze_time from sqlalchemy.engine.url import make_url from sqlalchemy_utils import drop_database from werkzeug.datastructures import Headers @@ -40,6 +42,8 @@ from CTFd.models import ( UserComments, Users, ) +from CTFd.utils import set_config +from tests.constants.time import FreezeTimes text_type = str binary_type = bytes @@ -61,6 +65,57 @@ class CTFdTestClient(FlaskClient): return super(CTFdTestClient, self).open(*args, **kwargs) +class ctftime: + @contextmanager + def init(): + """ + This context manager can be used to setup start and end dates for a test CTFd + """ + try: + set_config("start", FreezeTimes.START) + set_config("end", FreezeTimes.END) + yield + finally: + set_config("start", None) + set_config("end", None) + + @contextmanager + def not_started(): + """ + This context manager sets the current time to before the start date of the test CTFd + """ + try: + freezer = freeze_time(FreezeTimes.NOT_STARTED) + frozen_time = freezer.start() + yield frozen_time + finally: + freezer.stop() + + @contextmanager + def started(): + """ + This context manager sets the current time to the start date of the test CTFd + """ + try: + freezer = freeze_time(FreezeTimes.STARTED) + frozen_time = freezer.start() + yield frozen_time + finally: + freezer.stop() + + @contextmanager + def ended(): + """ + This context manager sets the current time to after the end date of the test CTFd + """ + try: + freezer = freeze_time(FreezeTimes.ENDED) + frozen_time = freezer.start() + yield frozen_time + finally: + freezer.stop() + + def create_ctfd( ctf_name="CTFd", ctf_description="CTF description", diff --git a/tests/utils/test_ctftime.py b/tests/utils/test_ctftime.py index 5e21764c..3884c87e 100644 --- a/tests/utils/test_ctftime.py +++ b/tests/utils/test_ctftime.py @@ -1,10 +1,8 @@ -from freezegun import freeze_time - from CTFd.models import Solves -from CTFd.utils import set_config from CTFd.utils.dates import ctf_ended, ctf_started from tests.helpers import ( create_ctfd, + ctftime, destroy_ctfd, gen_challenge, gen_flag, @@ -17,29 +15,24 @@ def test_ctftime_prevents_accessing_challenges_before_ctf(): """Test that the ctftime function prevents users from accessing challenges before the ctf""" app = create_ctfd() with app.app_context(): - set_config( - "start", "1507089600" - ) # Wednesday, October 4, 2017 12:00:00 AM GMT-04:00 DST - set_config( - "end", "1507262400" - ) # Friday, October 6, 2017 12:00:00 AM GMT-04:00 DST - register_user(app) - chal = gen_challenge(app.db) - chal_id = chal.id - gen_flag(app.db, challenge_id=chal.id, content=u"flag") + with ctftime.init(): + register_user(app) + chal = gen_challenge(app.db) + chal_id = chal.id + gen_flag(app.db, challenge_id=chal.id, content=u"flag") - with freeze_time("2017-10-3"): # CTF has not started yet. - client = login_as_user(app) - r = client.get("/challenges") - assert r.status_code == 403 + with ctftime.not_started(): + client = login_as_user(app) + r = client.get("/challenges") + assert r.status_code == 403 - with client.session_transaction() as sess: - data = {"key": "flag", "nonce": sess.get("nonce")} - r = client.get("/api/v1/challenges/{}".format(chal_id), data=data) - data = r.get_data(as_text=True) - assert r.status_code == 403 - solve_count = app.db.session.query(app.db.func.count(Solves.id)).first()[0] - assert solve_count == 0 + with client.session_transaction() as sess: + data = {"key": "flag", "nonce": sess.get("nonce")} + r = client.get("/api/v1/challenges/{}".format(chal_id), data=data) + data = r.get_data(as_text=True) + assert r.status_code == 403 + solve_count = app.db.session.query(app.db.func.count(Solves.id)).first()[0] + assert solve_count == 0 destroy_ctfd(app) @@ -47,32 +40,27 @@ def test_ctftime_allows_accessing_challenges_during_ctf(): """Test that the ctftime function allows accessing challenges during the ctf""" app = create_ctfd() with app.app_context(): - set_config( - "start", "1507089600" - ) # Wednesday, October 4, 2017 12:00:00 AM GMT-04:00 DST - set_config( - "end", "1507262400" - ) # Friday, October 6, 2017 12:00:00 AM GMT-04:00 DST - register_user(app) - chal = gen_challenge(app.db) - chal_id = chal.id - gen_flag(app.db, challenge_id=chal.id, content=u"flag") + with ctftime.init(): + register_user(app) + chal = gen_challenge(app.db) + chal_id = chal.id + gen_flag(app.db, challenge_id=chal.id, content=u"flag") - with freeze_time("2017-10-5"): - client = login_as_user(app) - r = client.get("/challenges") - assert r.status_code == 200 + with ctftime.started(): + client = login_as_user(app) + r = client.get("/challenges") + assert r.status_code == 200 - with client.session_transaction() as sess: - data = { - "submission": "flag", - "challenge_id": chal_id, - "nonce": sess.get("nonce"), - } - r = client.post("/api/v1/challenges/attempt", data=data) - assert r.status_code == 200 - solve_count = app.db.session.query(app.db.func.count(Solves.id)).first()[0] - assert solve_count == 1 + with client.session_transaction() as sess: + data = { + "submission": "flag", + "challenge_id": chal_id, + "nonce": sess.get("nonce"), + } + r = client.post("/api/v1/challenges/attempt", data=data) + assert r.status_code == 200 + solve_count = app.db.session.query(app.db.func.count(Solves.id)).first()[0] + assert solve_count == 1 destroy_ctfd(app) @@ -80,32 +68,28 @@ def test_ctftime_prevents_accessing_challenges_after_ctf(): """Test that the ctftime function prevents accessing challenges after the ctf""" app = create_ctfd() with app.app_context(): - set_config( - "start", "1507089600" - ) # Wednesday, October 4, 2017 12:00:00 AM GMT-04:00 DST - set_config( - "end", "1507262400" - ) # Friday, October 6, 2017 12:00:00 AM GMT-04:00 DST - register_user(app) - chal = gen_challenge(app.db) - chal_id = chal.id - gen_flag(app.db, challenge_id=chal.id, content=u"flag") + with ctftime.init(): - with freeze_time("2017-10-7"): - client = login_as_user(app) - r = client.get("/challenges") - assert r.status_code == 403 + register_user(app) + chal = gen_challenge(app.db) + chal_id = chal.id + gen_flag(app.db, challenge_id=chal.id, content=u"flag") - with client.session_transaction() as sess: - data = { - "submission": "flag", - "challenge_id": chal_id, - "nonce": sess.get("nonce"), - } - r = client.post("/api/v1/challenges/attempt", data=data) - assert r.status_code == 403 - solve_count = app.db.session.query(app.db.func.count(Solves.id)).first()[0] - assert solve_count == 0 + with ctftime.ended(): + client = login_as_user(app) + r = client.get("/challenges") + assert r.status_code == 403 + + with client.session_transaction() as sess: + data = { + "submission": "flag", + "challenge_id": chal_id, + "nonce": sess.get("nonce"), + } + r = client.post("/api/v1/challenges/attempt", data=data) + assert r.status_code == 403 + solve_count = app.db.session.query(app.db.func.count(Solves.id)).first()[0] + assert solve_count == 0 destroy_ctfd(app) @@ -118,22 +102,17 @@ def test_ctf_started(): with app.app_context(): assert ctf_started() is True - set_config( - "start", "1507089600" - ) # Wednesday, October 4, 2017 12:00:00 AM GMT-04:00 DST - set_config( - "end", "1507262400" - ) # Friday, October 6, 2017 12:00:00 AM GMT-04:00 DST + with ctftime.init(): - with freeze_time("2017-10-3"): - ctf_started() - assert ctf_started() is False + with ctftime.not_started(): + ctf_started() + assert ctf_started() is False - with freeze_time("2017-10-5"): - assert ctf_started() is True + with ctftime.started(): + assert ctf_started() is True - with freeze_time("2017-10-7"): - assert ctf_started() is True + with ctftime.ended(): + assert ctf_started() is True destroy_ctfd(app) @@ -144,20 +123,14 @@ def test_ctf_ended(): app = create_ctfd() with app.app_context(): assert ctf_ended() is False + with ctftime.init(): - set_config( - "start", "1507089600" - ) # Wednesday, October 4, 2017 12:00:00 AM GMT-04:00 DST - set_config( - "end", "1507262400" - ) # Friday, October 6, 2017 12:00:00 AM GMT-04:00 DST + with ctftime.not_started(): + assert ctf_ended() is False - with freeze_time("2017-10-3"): - assert ctf_ended() is False + with ctftime.started(): + assert ctf_ended() is False - with freeze_time("2017-10-5"): - assert ctf_ended() is False - - with freeze_time("2017-10-7"): - assert ctf_ended() is True + with ctftime.ended(): + assert ctf_ended() is True destroy_ctfd(app)