Skip to content

Commit

Permalink
Add database.py tests and refactoring
Browse files Browse the repository at this point in the history
- Remove test methods that only check function return types

- Create resources folder for common test data like test rss feeds

- Fix database.py query bugs

- Add database folder for database related tests

- Refactor common database fixtures into the database conftest file

- Refactor comments in database.py

- Refactor queries in database.py to have better style and sanitization

- Add comments and examples of the presentation time stamps

- Remove unused functions from database.py

- Add httpretty mock tests for database.py

- Add a database schema upgrade test

- Add tests that check multiple scenarios of each method in database.py

- Replace string % operators with calls to format for nonlog string formatting

- Remove several try/finally statements and replaced them with 'with's

- Fix an exception logging statement which referred to an out of scope value

- Add failure and presentation equality and inequality comparison functions

- Add example of parameterized test with fixtures

- Add fixtures based on summer camp 2010 and 2011 stored data

Related Freeseer#484
Related Freeseer#667
Related Freeseer#670
  • Loading branch information
Stephen Romansky committed Dec 19, 2014
1 parent 82f800b commit 2da4e03
Show file tree
Hide file tree
Showing 16 changed files with 1,028 additions and 316 deletions.
1 change: 1 addition & 0 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ httpretty
mock
pep8==1.4.6
pytest-cov==1.6
pytest-httpretty==0.2.0
pytest==2.5.2
Sphinx<=1.2.3
392 changes: 217 additions & 175 deletions src/freeseer/framework/database.py

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/freeseer/framework/failure.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ def __init__(self, talkID, comment, indicator, release=False):
self.indicator = indicator
self.release = release

def __eq__(self, obj):
return self.__dict__ == obj.__dict__

def __ne__(self, obj):
return not self == obj


class Report():
def __init__(self, presentation, failure):
Expand Down
34 changes: 33 additions & 1 deletion src/freeseer/framework/presentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,28 @@

from os import path

from PyQt4.QtCore import QDate
from PyQt4.QtCore import QDateTime


# TODO: Add a print presentation method? print self.__dict__
# TODO: Write a database record to Presentation method
class Presentation(object):
'''
This class is responsible for encapsulate data about presentations
and its database related operations
'''
def __init__(self, title, speaker="", description="", category="", event="Default", room="Default", date="", startTime="", endTime=""):

# TODO: Are Default variable necessary if they are all empty-string values?
DEFAULT_ROOM = ''
DEFAULT_DATE = ''
DEFAULT_TIME = ''

# TODO: Confirm Presentation.date is or is not a QDate object.
# TODO: Confirm Presentation.startTime should store a QDateTime object or a QTime object.
# TODO: Confirm Presentation.endTime should store a QDateTime object or a QTime object.
def __init__(self, title, speaker='', description='', category='', event='', room='',
date='', startTime='', endTime=''):
'''
Initialize a presentation instance
'''
Expand All @@ -44,6 +59,23 @@ def __init__(self, title, speaker="", description="", category="", event="Defaul
self.startTime = startTime
self.endTime = endTime

if not self.room:
self.room = self.DEFAULT_ROOM

# Set the date, startTime, or endTime if they are null timestamp values
if self.date == QDate():
self.date = self.DEFAULT_DATE
if self.startTime == QDateTime():
self.startTime = self.DEFAULT_TIME
if self.endTime == QDateTime():
self.endTime = self.DEFAULT_TIME

def __eq__(self, obj):
return self.__dict__ == obj.__dict__

def __ne__(self, obj):
return not self == obj


class PresentationFile(Presentation):

Expand Down
2 changes: 1 addition & 1 deletion src/freeseer/frontend/configtool/configtool.py
Original file line number Diff line number Diff line change
Expand Up @@ -750,7 +750,7 @@ def show_plugin_widget_dialog(self, widget, name):
self.dialog.closeButton = QtGui.QPushButton("Close")
self.dialog_layout.addWidget(self.dialog.closeButton)
self.connect(self.dialog.closeButton, QtCore.SIGNAL('clicked()'), self.dialog.close)
self.dialog.setWindowTitle(u'{} Setup'.format(name))
self.dialog.setWindowTitle('{} Setup'.format(name))
self.dialog.setModal(True)
self.dialog.show()

Expand Down
8 changes: 4 additions & 4 deletions src/freeseer/frontend/record/record.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,8 @@ def record(self):
if self.current_event and self.current_room:
starttime = QtCore.QDateTime().currentDateTime()
stoptime = starttime.addSecs(900)
talkid = self.db.get_talk_between_time(self.current_event, self.current_room,
starttime.toString(), stoptime.toString())
talkid = self.db.get_talk_between_dates(self.current_event, self.current_room,
starttime.toString(), stoptime.toString())

if talkid is not None:
for i in range(self.mainWidget.talkComboBox.count()):
Expand Down Expand Up @@ -638,8 +638,8 @@ def show_report_widget(self):
self.reportWidget.speakerLabel2.setText(p.speaker)
self.reportWidget.eventLabel2.setText(p.event)
self.reportWidget.roomLabel2.setText(p.room)
self.reportWidget.startTimeLabel2.setText(p.startTime)
self.reportWidget.endTimeLabel2.setText(p.endTime)
self.reportWidget.startTimeLabel2.setText(p.startTime.time().toString())
self.reportWidget.endTimeLabel2.setText(p.endTime.time().toString())

# Get existing report if there is one.
talk_id = self.current_presentation_id()
Expand Down
2 changes: 1 addition & 1 deletion src/freeseer/frontend/reporteditor/reporteditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def add_talk(self):
"", # level
unicode(self.addTalkWidget.eventLineEdit.text()),
unicode(self.addTalkWidget.roomLineEdit.text()),
unicode(datetime.toString()),
datetime.date(),
unicode(self.addTalkWidget.endTimeEdit.text()))

# Do not add talks if they are empty strings
Expand Down
12 changes: 6 additions & 6 deletions src/freeseer/frontend/talkeditor/talkeditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,9 @@ def retranslate(self):

def load_presentations_model(self):
# Load Presentation Model
# FIXME: The raw databse values are being loaded into the view. This means the date, startTime, and
# endTime are showing the raw QDate(Time) values. There should be a layer that converts between the
# frontend values and the backend.
self.presentationModel = self.db.get_presentations_model()
self.proxy = QSortFilterProxyModel()
self.proxy.setSourceModel(self.presentationModel)
Expand Down Expand Up @@ -395,9 +398,6 @@ def update_talk(self):

def create_presentation(self, talkDetailsWidget):
"""Creates and returns an instance of Presentation using data from the input fields"""
date = talkDetailsWidget.dateEdit.date()
startTime = talkDetailsWidget.startTimeEdit.time()
endTime = talkDetailsWidget.endTimeEdit.time()

title = unicode(talkDetailsWidget.titleLineEdit.text()).strip()
if title:
Expand All @@ -408,9 +408,9 @@ def create_presentation(self, talkDetailsWidget):
unicode(talkDetailsWidget.categoryLineEdit.text()).strip(),
unicode(talkDetailsWidget.eventLineEdit.text()).strip(),
unicode(talkDetailsWidget.roomLineEdit.text()).strip(),
unicode(date.toString(Qt.ISODate)),
unicode(startTime.toString(Qt.ISODate)),
unicode(endTime.toString(Qt.ISODate)))
talkDetailsWidget.dateEdit.date(),
talkDetailsWidget.startTimeEdit.time().toString('hh:mm ap'),
talkDetailsWidget.endTimeEdit.time().toString('hh:mm ap'))

def show_new_talk_popup(self):
"""Displays a modal dialog with a talk details view
Expand Down
7 changes: 4 additions & 3 deletions src/freeseer/plugins/importer/csv_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ def get_presentations(self, fname):
'Time': unicode(row.get('Time', ''), 'utf-8'), # Legacy csv time field
'Date': unicode(row.get('Date', ''), 'utf-8'),
'StartTime': unicode(row.get('StartTime', ''), 'utf-8'),
'EndTime': unicode(row.get('EndTime', ''), 'utf-8')
'EndTime': unicode(row.get('EndTime', ''), 'utf-8'),
'Problem': unicode(row.get('Problem', ''), 'utf-8'), # optional value from report csv
'Error': unicode(row.get('Error', ''), 'utf-8') # optional value from report csv
}

presentations.append(talk)

except IOError:
log.exception("CSV: File %s not found", csv_file)
log.exception("CSV: File %s not found", fname)

return presentations
Empty file.
146 changes: 146 additions & 0 deletions src/freeseer/tests/framework/database/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# freeseer - vga/presentation capture software
#
# Copyright (C) 2014 Free and Open Source Software Learning Centre
# http://fosslc.org
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

# For support, questions, suggestions or any other inquiries, visit:
# http://wiki.github.com/Freeseer/freeseer/

import pytest
from PyQt4 import QtCore

from freeseer.framework.config.profile import Profile
from freeseer.framework.presentation import Presentation


@pytest.fixture
def db(tmpdir):
"""Return a new empty QtDBConnector"""
profile = Profile(str(tmpdir), 'testing')
return profile.get_database()


@pytest.fixture
def fake_presentation():
"""Returns a presentation object with fake data. Also demonstrates how to construct time values for presentations"""
today = QtCore.QDate().currentDate() # today
# TODO: The currentDateTime object sets milliseconds. Convert it back to a string then to a QDateTime object again
# to get rid of milliseconds. There has got to be a better solution...
current_time = QtCore.QDateTime.fromString(QtCore.QDateTime().currentDateTime().toString()) # yyyy-mm-ddThh:mm:ss
return Presentation(
title='MITM presentation attacks',
speaker='Alice and Eve',
description='Field survey of current MITM presentation attacks.',
category='Security category',
event='testing event',
room='1300',
date=today,
startTime=current_time.addSecs(60 * 5),
endTime=current_time.addSecs(60 * 10)
)


@pytest.fixture
def presentation_sc2010():
"""Presentation object from the Summercamp2010 rss feed."""
return Presentation(
title='Managing map data in a database',
speaker='Andrew Ross',
description='''This talk will provide a brief introduction to geospatial technologies. It will focus on '''
'''managing map data with a relational database. Managing map data with a database provides the atomicity, '''
'''security, access that is difficult to achieve otherwise. It also provides powerful techniques for querying'''
''' spatial aware data which can enable new insights.''',
category='Intermediate',
event='Summercamp2010',
room='Rom AB113',
date=QtCore.QDate.fromString('2010-05-14T10:45', QtCore.Qt.ISODate),
startTime=QtCore.QDateTime.fromString('2010-05-14T10:45', 'yyyy-MM-ddThh:mm')
)


@pytest.fixture
def presentation_sc2011_maxwell_rss():
"""Creates a presentation from the summercamp2011 csv file"""
return Presentation(
title='Building NetBSD',
speaker='David Maxwell',
description='''People who are interested in learning about operating systems have a lot of topics to absorb,'''
''' but the very first barrier that gets in people's way is that you need to be able to build the software. '''
'''If you can't build it, you can't make changes. If building it is painful, you'll find other things to do '''
'''with your time.\n'''
'''\tThe NetBSD Project has a build system that goes far beyond what many other projects implement. Come to '''
'''this talk about learn about\n'''
'''\tbuild.sh and the features available that make multi-architecture and embedded development environments '''
'''a breeze with NetBSD.\n'''
'''\tNetBSD website: http://www.NetBSD.org/''',
event='SC2011',
category='Beginner',
room='',
date=QtCore.QDate.fromString('2011-08-17T20:29', QtCore.Qt.ISODate),
startTime=QtCore.QDateTime.fromString('2011-08-17T20:29', 'yyyy-MM-ddThh:mm')
)


@pytest.fixture
def presentation_sc2011_maxwell_csv():
"""Creates a presentation from the summercamp2011 csv file"""
return Presentation(
title='Building NetBSD',
speaker='David Maxwell',
description='''People who are interested in learning about operating systems have a lot of topics to absorb,'''
''' but the very first barrier that gets in people's way is that you need to be able to build the software. '''
'''If you can't build it, you can't make changes. If building it is painful, you'll find other things to do '''
'''with your time.\n'''
'''\tThe NetBSD Project has a build system that goes far beyond what many other projects implement. Come to '''
'''this talk about learn about\n'''
'''\tbuild.sh and the features available that make multi-architecture and embedded development environments '''
'''a breeze with NetBSD.\n'''
'''\tNetBSD website: http://www.NetBSD.org/''',
event='SC2011',
category='Beginner',
room='None',
date=QtCore.QDate.fromString('2011-08-17T20:29', QtCore.Qt.ISODate),
startTime=QtCore.QDateTime.fromString('2011-08-17T20:29', 'yyyy-MM-ddThh:mm').time().toString('hh:mm ap')
)


@pytest.fixture
def presentation_sc2011_dixon():
"""Presentation from the Summercamp2011 csv file"""
return Presentation(
title='Lecture Broadcast and Capture using BigBlueButton',
speaker='Fred Dixon',
description='''BigBlueButton is an open source web conferencing system for distance education. It's goal is '''
'''to enable remote students to have a high-quality learning experience. The #1 requested feature we've had '''
'''over the last year is to integrate record and playback of a session.\n'''
'''\n'''
'''\t\n'''
'''\tFred Dixon and Richard Alam, two of the BigBlueButton committers, will describe the architecture and '''
'''implementation of record and playback as well as demonstrate the integration with Moodle to show how an '''
'''educational institution can use BigBlueButton to setup virtual classrooms, record lectures, and provide '''
'''students access to the recorded content from within the Moodle interface.\n'''
'''\n'''
'''\tWe will also demonstrate an prototype integration with popcorn.js (Mozilla project) using it as a '''
'''playback client for the recorded content.''',
event='SC2011',
category='Intermediate',
room='',
date='',
startTime=''
)
Loading

0 comments on commit 2da4e03

Please sign in to comment.