Пример #1
0
    def setUp(self):
        # make an in-memory sqlite database to use during testing
        self.connection = Connection_wrapper(
            sqlite.connect(":memory:",
                           detect_types=sqlite.PARSE_DECLTYPES,
                           check_same_thread=False))
        self.cache = Stub_cache()
        cursor = self.connection.cursor()
        cursor.execute(Stub_object.sql_create_table())

        self.database = Database(self.connection, self.cache)
Пример #2
0
def main(args):
    import cherrypy
    from config import Common

    cherrypy.config.update(Common.settings)
    desktop = False

    if args and "-d" in args:
        from config import Development
        settings = Development.settings
        args.remove("-d")
    elif args and "-l" in args:
        from config import Desktop
        settings = Desktop.settings
        desktop = True
        args.remove("-l")
    else:
        from config import Production
        settings = Production.settings

    cherrypy.config.update(settings)

    database = Database(
        host=cherrypy.config.configMap[u"global"].get(u"luminotes.db_host"),
        ssl_mode=cherrypy.config.configMap[u"global"].get(
            u"luminotes.db_ssl_mode"),
        data_dir=".",
    )
    ranker = Thread_maker(database, *args)
    def setUp(self):
        # make an in-memory sqlite database to use during testing
        self.connection = Connection_wrapper(
            sqlite.connect(":memory:",
                           detect_types=sqlite.PARSE_DECLTYPES,
                           check_same_thread=False))
        self.cache = Stub_cache()
        cursor = self.connection.cursor()
        cursor.execute(Stub_object.sql_create_table())

        self.fake_files = {
        }  # map of fake filename (full path) to fake file contents
        self.database = Database(self.connection, self.cache)
        self.upgrader = Schema_upgrader(self.database,
                                        glob=self.glob,
                                        read_file=self.read_file)
Пример #4
0
  def setUp( self ):
    self.database = Database(
      Connection_wrapper( sqlite.connect( ":memory:", detect_types = sqlite.PARSE_DECLTYPES, check_same_thread = False ) ),
      cache = Stub_cache(),
    )
    self.database.execute_script( file( "model/schema.sqlite" ).read(), commit = True )

    self.username = u"mulder"
    self.password = u"trustno1"
    self.email_address = u"*****@*****.**"
    self.user = User.create( self.database.next_id( User ), self.username, self.password, self.email_address )
    self.database.save( self.user, commit = False )

    self.trash = Notebook.create( self.database.next_id( Notebook ), u"trash" )
    self.database.save( self.trash, commit = False )
    self.notebook = Notebook.create( self.database.next_id( Notebook ), u"notebook", self.trash.object_id, user_id = self.user.object_id )
    self.database.save( self.notebook, commit = False )

    note_id = self.database.next_id( Note )
    self.note1 = Note.create( note_id, u"<h3>my title</h3>blah", notebook_id = self.notebook.object_id, startup = True, user_id = self.user.object_id )
    self.database.save( self.note1, commit = False )

    note_id = self.database.next_id( Note )
    self.note2 = Note.create( note_id, u"<h3>other title</h3>whee", notebook_id = self.notebook.object_id, user_id = self.user.object_id )
    self.database.save( self.note2, commit = False )
Пример #5
0
def main(args):
    import cherrypy
    from config import Common

    cherrypy.config.update(Common.settings)

    if args and "-d" in args:
        from config import Development
        settings = Development.settings
    elif args and "-l" in args:
        from config import Desktop
        settings = Desktop.settings
    else:
        from config import Production
        settings = Production.settings

    cherrypy.config.update(settings)

    database = Database(
        host=cherrypy.config.configMap[u"global"].get(u"luminotes.db_host"),
        ssl_mode=cherrypy.config.configMap[u"global"].get(
            u"luminotes.db_ssl_mode"),
        data_dir=".",
    )
    initializer = Updater(database, cherrypy.config.configMap)
Пример #6
0
  def setUp( self ):
    # make an in-memory sqlite database to use during testing
    self.connection = Connection_wrapper( sqlite.connect( ":memory:", detect_types = sqlite.PARSE_DECLTYPES, check_same_thread = False ) )
    self.cache = Stub_cache()
    cursor = self.connection.cursor()
    cursor.execute( Stub_object.sql_create_table() )

    self.database = Database( self.connection, self.cache )
Пример #7
0
    def setUp(self):
        self.database = Database(
            Connection_wrapper(
                sqlite.connect(":memory:",
                               detect_types=sqlite.PARSE_DECLTYPES,
                               check_same_thread=False)),
            cache=Stub_cache(),
        )
        self.database.execute_script(file("model/schema.sqlite").read(),
                                     commit=True)

        self.username = u"mulder"
        self.password = u"trustno1"
        self.email_address = u"*****@*****.**"
        self.user = User.create(self.database.next_id(User), self.username,
                                self.password, self.email_address)
        self.database.save(self.user, commit=False)

        self.trash = Notebook.create(self.database.next_id(Notebook), u"trash")
        self.database.save(self.trash, commit=False)
        self.notebook = Notebook.create(self.database.next_id(Notebook),
                                        u"notebook",
                                        self.trash.object_id,
                                        user_id=self.user.object_id)
        self.database.save(self.notebook, commit=False)

        note_id = self.database.next_id(Note)
        self.note1 = Note.create(note_id,
                                 u"<h3>my title</h3>blah",
                                 notebook_id=self.notebook.object_id,
                                 startup=True,
                                 user_id=self.user.object_id)
        self.database.save(self.note1, commit=False)

        note_id = self.database.next_id(Note)
        self.note2 = Note.create(note_id,
                                 u"<h3>other title</h3>whee",
                                 notebook_id=self.notebook.object_id,
                                 user_id=self.user.object_id)
        self.database.save(self.note2, commit=False)
Пример #8
0
def main(args=None):
    nuke = False

    import cherrypy
    from config import Common

    cherrypy.config.update(Common.settings)
    desktop = False

    if args and "-d" in args:
        from config import Development
        settings = Development.settings
    elif args and "-l" in args:
        from config import Desktop
        settings = Desktop.settings
        desktop = True
    else:
        from config import Production
        settings = Production.settings

    cherrypy.config.update(settings)

    if args and ("-n" in args or "--nuke" in args):
        nuke = True
        print "This will nuke the contents of the database before initializing it with default data. Continue (y/n)? ",
        confirmation = sys.stdin.readline().strip()
        print

        if confirmation.lower()[0] != 'y':
            print "Exiting without touching the database."
            return

    print "Initializing the database with default data."
    host = cherrypy.config[u"luminotes.db_host"]  # TODO : this fails
    database = Database(
        host=host,
        ssl_mode=cherrypy.config[u"luminotes.db_ssl_mode"],
        data_dir=".",
    )
    #initializer = Initializer( database, host, cherrypy.config.configMap, desktop, nuke )
    initializer = Initializer(database, host, cherrypy.config, desktop, nuke)
Пример #9
0
def main(args):
    import cherrypy
    from config import Common

    cherrypy.config.update(Common.settings)

    if args and "-d" in args:
        from config import Development
        settings = Development.settings
    else:
        from config import Production
        settings = Production.settings

    cherrypy.config.update(settings)

    database = Database(
        host=cherrypy.config.configMap[u"global"].get(u"luminotes.db_host"),
        ssl_mode=cherrypy.config.configMap[u"global"].get(
            u"luminotes.db_ssl_mode"),
        data_dir=".",
    )

    class Stub_root(object):
        def __init__(self, database):
            self.database = database

    cherrypy.root = Stub_root(database)
    sessions = Session_storage()
    session_count = 0

    for session_filename in os.listdir(u"session/"):
        pickled_data = file(u"session/%s" % session_filename).read()
        (data, expiration_time) = pickle.loads(pickled_data)
        session_id = data[u"_id"]

        sessions.save(session_id, data, expiration_time)
        session_count += 1

    print "converted %d sessions" % session_count
Пример #10
0
class Test_export_html(object):
    def setUp(self):
        self.database = Database(
            Connection_wrapper(
                sqlite.connect(":memory:", detect_types=sqlite.PARSE_DECLTYPES, check_same_thread=False)
            ),
            cache=Stub_cache(),
        )
        self.database.execute_script(file("model/schema.sqlite").read(), commit=True)

        self.username = u"mulder"
        self.password = u"trustno1"
        self.email_address = u"*****@*****.**"
        self.user = User.create(self.database.next_id(User), self.username, self.password, self.email_address)
        self.database.save(self.user, commit=False)

        self.trash = Notebook.create(self.database.next_id(Notebook), u"trash")
        self.database.save(self.trash, commit=False)
        self.notebook = Notebook.create(
            self.database.next_id(Notebook), u"notebook", self.trash.object_id, user_id=self.user.object_id
        )
        self.database.save(self.notebook, commit=False)

        note_id = self.database.next_id(Note)
        self.note1 = Note.create(
            note_id,
            u"<h3>my title</h3>blah",
            notebook_id=self.notebook.object_id,
            startup=True,
            user_id=self.user.object_id,
        )
        self.database.save(self.note1, commit=False)

        note_id = self.database.next_id(Note)
        self.note2 = Note.create(
            note_id, u"<h3>other title</h3>whee", notebook_id=self.notebook.object_id, user_id=self.user.object_id
        )
        self.database.save(self.note2, commit=False)

    def test_export_html(self):
        note3 = Note.create("55", u"<h3>blah</h3>foo", notebook_id=self.notebook.object_id)
        self.database.save(note3)
        response_headers = {}
        expected_notes = (self.note1, self.note2, note3)

        result = invoke("export", "html", self.database, self.notebook, expected_notes, response_headers)

        # response headers should be unchanged
        assert response_headers == {}

        notes = result.get("notes")
        assert len(notes) == len(expected_notes)

        # assert that the notes are in the expected order
        for (note, expected_note) in zip(notes, expected_notes):
            assert note.object_id == expected_note.object_id
            assert note.revision == expected_note.revision
            assert note.title == expected_note.title
            assert note.contents == expected_note.contents
            assert note.notebook_id == expected_note.notebook_id
            assert note.startup == expected_note.startup
            assert note.deleted_from_id == expected_note.deleted_from_id
            assert note.rank == expected_note.rank
            assert note.user_id == expected_note.user_id
            assert note.creation == expected_note.creation
Пример #11
0
  def setUp( self ):
    # trick tested methods into using a fake SMTP server
    Stub_smtp.reset()
    smtplib.SMTP = Stub_smtp

    from controller.Root import Root
    cherrypy.lowercase_api = True
    self.database = Database(
      Connection_wrapper( sqlite.connect( ":memory:", detect_types = sqlite.PARSE_DECLTYPES, check_same_thread = False ) ),
      cache = Stub_cache(),
    )
    self.database.execute_script( file( "model/schema.sqlite" ).read(), commit = True )

    self.settings = {
      u"global": {
        u"server.environment": "production",
        u"session_filter.on": True,
        u"session_filter.storage_type": u"ram",
        u"encoding_filter.on": True,
        u"encoding_filter.encoding": "utf-8",
        u"decoding_filter.on": True,
        u"decoding_filter.encoding": "utf-8",
        u"server.log_to_screen": False,
        u"luminotes.http_url" : u"http://luminotes.com",
        u"luminotes.https_url" : u"https://luminotes.com",
        u"luminotes.http_proxy_ip" : u"127.0.0.1",
        u"luminotes.https_proxy_ip" : u"127.0.0.2",
        u"luminotes.support_email": "*****@*****.**",
        u"luminotes.payment_email": "*****@*****.**",
        u"luminotes.rate_plans": [
          {
            u"name": u"super",
            u"storage_quota_bytes": 1337 * 10,
            u"notebook_collaboration": False,
            u"user_admin": False,
            u"included_users": 1,
            u"fee": 1.99,
            u"yearly_fee": 19.90,
            u"button": u"[subscribe here user %s!] button (modify=%s)",
            u"yearly_button": u"[yearly subscribe here user %s!] button (modify=%s)",
          },
          {
            u"name": "extra super",
            u"storage_quota_bytes": 31337 * 1000,
            u"notebook_collaboration": True,
            u"user_admin": True,
            u"included_users": 3,
            u"fee": 9.00,
            u"yearly_fee": 90.00,
            u"button": u"[or here user %s!] button (modify=%s)",
            u"yearly_button": u"[yearly or here user %s!] button (modify=%s)",
          },
        ],
        "luminotes.download_products": [
          {
            "name": "local desktop extravaganza",
            "designed_for": "individuals",
            "storage_quota_bytes": None,
            "included_users": 1,
            "notebook_sharing": False,
            "notebook_collaboration": False,
            "user_admin": False,
            "fee": "30.00",
            "item_number": "5000",
            "filename": "test.exe",
            "button": u"",
          },
        ],
      },
      u"/files/download": {
        u"stream_response": True,
        u"encoding_filter.on": False,
      },
      u"/files/download_product": {
        u"stream_response": True,
        u"encoding_filter.on": False,
      },
      u"/notebooks/export_csv": {
        u"stream_response": True,
        u"encoding_filter.on": False,
      },
      u"/files/progress": {
        u"stream_response": True,
      },
    }

    cherrypy.root = Root( self.database, self.settings, suppress_exceptions = True )
    cherrypy.config.update( self.settings )
    cherrypy.server.start( init_only = True, server_class = None )

    # since we only want to test the controller, use the stub view for all exposed methods
    import controller.Expose
    Stub_view.result = None
    controller.Expose.view_override = Stub_view
Пример #12
0
class Test_controller( object ):
  def __init__( self ):
    from model.User import User
    from model.Group import Group
    from model.Notebook import Notebook
    from model.Note import Note
    from model.Invite import Invite
    from model.User_revision import User_revision
    from model.File import File

  def setUp( self ):
    # trick tested methods into using a fake SMTP server
    Stub_smtp.reset()
    smtplib.SMTP = Stub_smtp

    from controller.Root import Root
    cherrypy.lowercase_api = True
    self.database = Database(
      Connection_wrapper( sqlite.connect( ":memory:", detect_types = sqlite.PARSE_DECLTYPES, check_same_thread = False ) ),
      cache = Stub_cache(),
    )
    self.database.execute_script( file( "model/schema.sqlite" ).read(), commit = True )

    self.settings = {
      u"global": {
        u"server.environment": "production",
        u"session_filter.on": True,
        u"session_filter.storage_type": u"ram",
        u"encoding_filter.on": True,
        u"encoding_filter.encoding": "utf-8",
        u"decoding_filter.on": True,
        u"decoding_filter.encoding": "utf-8",
        u"server.log_to_screen": False,
        u"luminotes.http_url" : u"http://luminotes.com",
        u"luminotes.https_url" : u"https://luminotes.com",
        u"luminotes.http_proxy_ip" : u"127.0.0.1",
        u"luminotes.https_proxy_ip" : u"127.0.0.2",
        u"luminotes.support_email": "*****@*****.**",
        u"luminotes.payment_email": "*****@*****.**",
        u"luminotes.rate_plans": [
          {
            u"name": u"super",
            u"storage_quota_bytes": 1337 * 10,
            u"notebook_collaboration": False,
            u"user_admin": False,
            u"included_users": 1,
            u"fee": 1.99,
            u"yearly_fee": 19.90,
            u"button": u"[subscribe here user %s!] button (modify=%s)",
            u"yearly_button": u"[yearly subscribe here user %s!] button (modify=%s)",
          },
          {
            u"name": "extra super",
            u"storage_quota_bytes": 31337 * 1000,
            u"notebook_collaboration": True,
            u"user_admin": True,
            u"included_users": 3,
            u"fee": 9.00,
            u"yearly_fee": 90.00,
            u"button": u"[or here user %s!] button (modify=%s)",
            u"yearly_button": u"[yearly or here user %s!] button (modify=%s)",
          },
        ],
        "luminotes.download_products": [
          {
            "name": "local desktop extravaganza",
            "designed_for": "individuals",
            "storage_quota_bytes": None,
            "included_users": 1,
            "notebook_sharing": False,
            "notebook_collaboration": False,
            "user_admin": False,
            "fee": "30.00",
            "item_number": "5000",
            "filename": "test.exe",
            "button": u"",
          },
        ],
      },
      u"/files/download": {
        u"stream_response": True,
        u"encoding_filter.on": False,
      },
      u"/files/download_product": {
        u"stream_response": True,
        u"encoding_filter.on": False,
      },
      u"/notebooks/export_csv": {
        u"stream_response": True,
        u"encoding_filter.on": False,
      },
      u"/files/progress": {
        u"stream_response": True,
      },
    }

    cherrypy.root = Root( self.database, self.settings, suppress_exceptions = True )
    cherrypy.config.update( self.settings )
    cherrypy.server.start( init_only = True, server_class = None )

    # since we only want to test the controller, use the stub view for all exposed methods
    import controller.Expose
    Stub_view.result = None
    controller.Expose.view_override = Stub_view

  def tearDown( self ):
    self.database.close()
    cherrypy.server.stop()

  def http_get( self, http_path, headers = None, session_id = None, pretend_https = False ):
    """
    Perform an HTTP GET with the given path on the test server. Return the result dict as returned
    by the invoked method.
    """
    if headers is None:
      headers = []

    if session_id:
      headers.append( ( u"Cookie", "session_id=%s" % session_id ) ) # will break if unicode is used for the value

    if pretend_https:
      proxy_ip = self.settings[ "global" ].get( u"luminotes.https_proxy_ip" )
    else:
      proxy_ip = self.settings[ "global" ].get( u"luminotes.http_proxy_ip" )

    request = cherrypy.server.request( ( proxy_ip, 1234 ), u"127.0.0.5" )
    response = request.run( "GET %s HTTP/1.0" % str( http_path ), headers = headers, rfile = StringIO() )
    session_id = response.simple_cookie.get( u"session_id" )
    if session_id: session_id = session_id.value

    try:
      if Stub_view.result is not None:
        result = Stub_view.result
        Stub_view.result = None
      else:
        result = dict(
          status = response.status,
          headers = response.headers,
          body = response.body,
        )

      result[ u"session_id" ] = session_id
      return result
    finally:
      request.close()

  def http_post( self, http_path, form_args, headers = None, session_id = None ):
    """
    Perform an HTTP POST with the given path on the test server, sending the provided form_args
    dict. Return the result dict as returned by the invoked method.
    """
    from urllib import urlencode
    if isinstance( form_args, dict ):
      form_args = form_args.items()
    post_data = urlencode(
      [ ( k, isinstance( v, unicode ) and v.encode( "utf-8" ) or v ) for ( k, v ) in form_args ]
    )

    if headers is None:
      headers = []

    headers.extend( [
      ( u"Content-Type", u"application/x-www-form-urlencoded" ),
      ( u"Content-Length", unicode( len( post_data ) ) ),
    ] )

    if session_id:
      headers.append( ( u"Cookie", "session_id=%s" % session_id ) ) # will break if unicode is used for the value

    request = cherrypy.server.request( ( u"127.0.0.1", 1234 ), u"127.0.0.5" )
    response = request.run( "POST %s HTTP/1.0" % str( http_path ), headers = headers, rfile = StringIO( post_data ) )
    session_id = response.simple_cookie.get( u"session_id" )
    if session_id: session_id = session_id.value

    try:
      if Stub_view.result is not None:
        result = Stub_view.result
        Stub_view.result = None
      else:
        result = dict(
          status = response.status,
          headers = response.headers,
          body = response.body,
        )

      result[ u"session_id" ] = session_id
      return result
    finally:
      request.close()

  def http_upload( self, http_path, form_args, filename, file_data, content_type, simulate_cancel = False, headers = None, session_id = None ):
    """
    Perform an HTTP POST with the given path on the test server, sending the provided form_args
    and file_data as a multipart form file upload. Return the result dict as returned by the
    invoked method.
    """
    boundary = "boundarygoeshere"
    post_data = [ "--%s\n" % boundary ]

    for ( name, value ) in form_args.items():
      post_data.append( 'Content-Disposition: form-data; name="%s"\n\n%s\n--%s\n' % (
        str( name ), str( value ), boundary
      ) )

    post_data.append( 'Content-Disposition: form-data; name="upload"; filename="%s"\n' % (
      filename.encode( "utf8" )
    ) )
    post_data.append( "Content-Type: %s\nContent-Transfer-Encoding: binary\n\n%s\n--%s--\n" % (
      content_type, file_data, boundary
    ) )

    if headers is None:
      headers = []

    post_data = "".join( post_data )
    headers.append( ( "Content-Type", "multipart/form-data; boundary=%s" % boundary ) )

    if "Content-Length" not in [ name for ( name, value ) in headers ]:
      headers.append( ( "Content-Length", str( len( post_data ) ) ) )

    if session_id:
      headers.append( ( u"Cookie", "session_id=%s" % session_id ) ) # will break if unicode is used for the value

    if simulate_cancel:
      file_wrapper = Truncated_StringIO( post_data )
    else:
      file_wrapper = Wrapped_StringIO( post_data )

    request = cherrypy.server.request( ( u"127.0.0.1", 1234 ), u"127.0.0.5" )
    response = request.run( "POST %s HTTP/1.0" % str( http_path ), headers = headers, rfile = file_wrapper )
    session_id = response.simple_cookie.get( u"session_id" )
    if session_id: session_id = session_id.value

    try:
      if Stub_view.result is not None:
        result = Stub_view.result
        Stub_view.result = None
      else:
        result = dict(
          status = response.status,
          headers = response.headers,
          body = response.body,
        )

      result[ u"session_id" ] = session_id
      return result
    finally:
      request.close()
Пример #13
0
    def setUp(self):
        # trick tested methods into using a fake SMTP server
        Stub_smtp.reset()
        smtplib.SMTP = Stub_smtp

        from controller.Root import Root
        cherrypy.lowercase_api = True
        self.database = Database(
            Connection_wrapper(
                sqlite.connect(":memory:",
                               detect_types=sqlite.PARSE_DECLTYPES,
                               check_same_thread=False)),
            cache=Stub_cache(),
        )
        self.database.execute_script(file("model/schema.sqlite").read(),
                                     commit=True)

        self.settings = {
            u"global": {
                u"server.environment":
                "production",
                u"session_filter.on":
                True,
                u"session_filter.storage_type":
                u"ram",
                u"encoding_filter.on":
                True,
                u"encoding_filter.encoding":
                "utf-8",
                u"decoding_filter.on":
                True,
                u"decoding_filter.encoding":
                "utf-8",
                u"server.log_to_screen":
                False,
                u"luminotes.http_url":
                u"http://luminotes.com",
                u"luminotes.https_url":
                u"https://luminotes.com",
                u"luminotes.http_proxy_ip":
                u"127.0.0.1",
                u"luminotes.https_proxy_ip":
                u"127.0.0.2",
                u"luminotes.support_email":
                "*****@*****.**",
                u"luminotes.payment_email":
                "*****@*****.**",
                u"luminotes.rate_plans": [
                    {
                        u"name":
                        u"super",
                        u"storage_quota_bytes":
                        1337 * 10,
                        u"notebook_collaboration":
                        False,
                        u"user_admin":
                        False,
                        u"included_users":
                        1,
                        u"fee":
                        1.99,
                        u"yearly_fee":
                        19.90,
                        u"button":
                        u"[subscribe here user %s!] button (modify=%s)",
                        u"yearly_button":
                        u"[yearly subscribe here user %s!] button (modify=%s)",
                    },
                    {
                        u"name":
                        "extra super",
                        u"storage_quota_bytes":
                        31337 * 1000,
                        u"notebook_collaboration":
                        True,
                        u"user_admin":
                        True,
                        u"included_users":
                        3,
                        u"fee":
                        9.00,
                        u"yearly_fee":
                        90.00,
                        u"button":
                        u"[or here user %s!] button (modify=%s)",
                        u"yearly_button":
                        u"[yearly or here user %s!] button (modify=%s)",
                    },
                ],
                "luminotes.download_products": [
                    {
                        "name": "local desktop extravaganza",
                        "designed_for": "individuals",
                        "storage_quota_bytes": None,
                        "included_users": 1,
                        "notebook_sharing": False,
                        "notebook_collaboration": False,
                        "user_admin": False,
                        "fee": "30.00",
                        "item_number": "5000",
                        "filename": "test.exe",
                        "button": u"",
                    },
                ],
            },
            u"/files/download": {
                u"stream_response": True,
                u"encoding_filter.on": False,
            },
            u"/files/download_product": {
                u"stream_response": True,
                u"encoding_filter.on": False,
            },
            u"/notebooks/export_csv": {
                u"stream_response": True,
                u"encoding_filter.on": False,
            },
            u"/files/progress": {
                u"stream_response": True,
            },
        }

        cherrypy.root = Root(self.database,
                             self.settings,
                             suppress_exceptions=True)
        cherrypy.config.update(self.settings)
        cherrypy.server.start(init_only=True, server_class=None)

        # since we only want to test the controller, use the stub view for all exposed methods
        import controller.Expose
        Stub_view.result = None
        controller.Expose.view_override = Stub_view
Пример #14
0
class Test_database( object ):
  def setUp( self ):
    # make an in-memory sqlite database to use during testing
    self.connection = Connection_wrapper( sqlite.connect( ":memory:", detect_types = sqlite.PARSE_DECLTYPES, check_same_thread = False ) )
    self.cache = Stub_cache()
    cursor = self.connection.cursor()
    cursor.execute( Stub_object.sql_create_table() )

    self.database = Database( self.connection, self.cache )

  def tearDown( self ):
    self.database.close()

  def test_save_and_load( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    original_revision = basic_obj.revision

    self.database.save( basic_obj )
    obj = self.database.load( Stub_object, basic_obj.object_id )

    assert obj.object_id == basic_obj.object_id
    assert obj.revision.replace( tzinfo = utc ) == original_revision
    assert obj.value == basic_obj.value

  def test_save_and_load_without_commit( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    original_revision = basic_obj.revision

    self.database.save( basic_obj, commit = False )
    self.connection.rollback() # if commit wasn't called, this should back out the save
    obj = self.database.load( Stub_object, basic_obj.object_id )

    assert obj == None

  def test_save_and_load_with_explicit_commit( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    original_revision = basic_obj.revision

    self.database.save( basic_obj, commit = False )
    self.database.commit()
    self.connection.rollback() # should have no effect because of the call to commit
    obj = self.database.load( Stub_object, basic_obj.object_id )

    assert obj.object_id == basic_obj.object_id
    assert obj.revision.replace( tzinfo = utc ) == original_revision
    assert obj.value == basic_obj.value

  def test_select_one( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    original_revision = basic_obj.revision

    self.database.save( basic_obj )
    obj = self.database.select_one( Stub_object, Stub_object.sql_load( basic_obj.object_id ) )

    assert obj.object_id == basic_obj.object_id
    assert obj.revision.replace( tzinfo = utc ) == original_revision
    assert obj.value == basic_obj.value

  def test_select_datetime( self ):
    # this revision (with .504099) happens to test for a bug caused by floating point rounding errors
    original_revision = "2008-01-01 01:00:42.504099+00:00"
    basic_obj = Stub_object( object_id = "5", revision = original_revision, value = 1 )

    self.database.save( basic_obj )
    obj = self.database.select_one( Stub_object, Stub_object.sql_load( basic_obj.object_id ) )

    assert obj.object_id == basic_obj.object_id
    assert str( obj.revision.replace( tzinfo = utc ) ) == original_revision
    assert obj.value == basic_obj.value

  def test_select_datetime_with_many_fractional_digits( self ):
    original_revision = "2008-01-01 01:00:42.5032429489284+00:00"
    basic_obj = Stub_object( object_id = "5", revision = original_revision, value = 1 )

    self.database.save( basic_obj )
    obj = self.database.select_one( Stub_object, Stub_object.sql_load( basic_obj.object_id ) )

    assert obj.object_id == basic_obj.object_id
    assert str( obj.revision.replace( tzinfo = utc ) ) == "2008-01-01 01:00:42.503242+00:00"
    assert obj.value == basic_obj.value

  def test_select_datetime_with_zero_fractional_seconds( self ):
    original_revision = "2008-01-01 01:00:42.0+00:00"
    basic_obj = Stub_object( object_id = "5", revision = original_revision, value = 1 )

    self.database.save( basic_obj )
    obj = self.database.select_one( Stub_object, Stub_object.sql_load( basic_obj.object_id ) )

    assert obj.object_id == basic_obj.object_id
    assert str( obj.revision.replace( tzinfo = utc ) ) == "2008-01-01 01:00:42+00:00"
    assert obj.value == basic_obj.value

  def test_select_one_tuple( self ):
    obj = self.database.select_one( tuple, Stub_object.sql_tuple() )

    assert len( obj ) == 2
    assert obj[ 0 ] == 1
    assert obj[ 1 ] == 2

  def test_select_many( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    original_revision = basic_obj.revision
    basic_obj2 = Stub_object( object_id = "6", value = 2 )
    original_revision2 = basic_obj2.revision

    self.database.save( basic_obj )
    self.database.save( basic_obj2 )
    objs = self.database.select_many( Stub_object, Stub_object.sql_load_em_all() )

    assert len( objs ) == 2
    assert objs[ 0 ].object_id == basic_obj.object_id
    assert objs[ 0 ].revision.replace( tzinfo = utc ) == original_revision
    assert objs[ 0 ].value == basic_obj.value
    assert objs[ 1 ].object_id == basic_obj2.object_id
    assert objs[ 1 ].revision.replace( tzinfo = utc ) == original_revision2
    assert objs[ 1 ].value == basic_obj2.value

  def test_select_many_tuples( self ):
    objs = self.database.select_many( tuple, Stub_object.sql_tuple() )

    assert len( objs ) == 1
    assert len( objs[ 0 ] ) == 2
    assert objs[ 0 ][ 0 ] == 1
    assert objs[ 0 ][ 1 ] == 2

  def test_select_many_with_no_matches( self ):
    objs = self.database.select_many( Stub_object, Stub_object.sql_load_em_all() )

    assert len( objs ) == 0

  def test_save_and_load_revision( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    original_revision = basic_obj.revision

    self.database.save( basic_obj )
    basic_obj.value = 2

    self.database.save( basic_obj )
    obj = self.database.load( Stub_object, basic_obj.object_id )

    assert obj.object_id == basic_obj.object_id
    assert obj.revision.replace( tzinfo = utc ) == basic_obj.revision
    assert obj.value == basic_obj.value

    revised = self.database.load( Stub_object, basic_obj.object_id, revision = original_revision )

    assert revised.object_id == basic_obj.object_id
    assert revised.value == 1
    assert revised.revision.replace( tzinfo = utc ) == original_revision

  def test_execute( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    original_revision = basic_obj.revision

    self.database.execute( basic_obj.sql_create() )
    obj = self.database.load( Stub_object, basic_obj.object_id )

    assert obj.object_id == basic_obj.object_id
    assert obj.revision.replace( tzinfo = utc ) == original_revision
    assert obj.value == basic_obj.value

  def test_execute_without_commit( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    original_revision = basic_obj.revision

    self.database.execute( basic_obj.sql_create(), commit = False )
    self.connection.rollback()
    obj = self.database.load( Stub_object, basic_obj.object_id )

    assert obj == None

  def test_execute_with_explicit_commit( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    original_revision = basic_obj.revision

    self.database.execute( basic_obj.sql_create(), commit = False )
    self.database.commit()
    obj = self.database.load( Stub_object, basic_obj.object_id )

    assert obj.object_id == basic_obj.object_id
    assert obj.revision.replace( tzinfo = utc ) == original_revision
    assert obj.value == basic_obj.value

  def test_load_unknown( self ):
    basic_obj = Stub_object( object_id = "5", value = 1 )
    obj = self.database.load( Stub_object, basic_obj.object_id )

    assert obj == None

  def test_next_id( self ):
    next_id = self.database.next_id( Stub_object )
    assert next_id
    assert self.database.load( Stub_object, next_id )
    prev_ids = [ next_id ]

    next_id = self.database.next_id( Stub_object )
    assert next_id
    assert next_id not in prev_ids
    assert self.database.load( Stub_object, next_id )
    prev_ids.append( next_id )

    next_id = self.database.next_id( Stub_object )
    assert next_id
    assert next_id not in prev_ids
    assert self.database.load( Stub_object, next_id )

  def test_next_id_without_commit( self ):
    next_id = self.database.next_id( Stub_object, commit = False )
    self.connection.rollback()
    assert self.database.load( Stub_object, next_id ) == None

  def test_next_id_with_explicit_commit( self ):
    next_id = self.database.next_id( Stub_object, commit = False )
    self.database.commit()
    assert next_id
    assert self.database.load( Stub_object, next_id )

  def test_synchronize( self ):
    def make_objects():
      for i in range( 50 ):
        object_id = self.database.next_id( Stub_object )
        basic_obj = Stub_object( object_id, value = 1 )
        original_revision = basic_obj.revision

        self.database.execute( basic_obj.sql_create() )
        obj = self.database.load( Stub_object, basic_obj.object_id )

        assert obj.object_id == basic_obj.object_id
        delta = abs( obj.revision.replace( tzinfo = utc ) - original_revision )
        assert delta <= timedelta( seconds = 0.000001 )
        assert obj.value == basic_obj.value

        object_id = self.database.next_id( Stub_object )

    # if synchronization (locking) is working properly, then these two threads should be able to run
    # simultaneously without error. without locking, SQLite will raise
    thread1 = Thread( target = make_objects )
    thread2 = Thread( target = make_objects )
    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()

  def test_backend( self ):
    assert self.database.backend == Persistent.SQLITE_BACKEND
Пример #15
0
def main(args):
    database = Database(cache={})
    ranker = Dumper(database)
Пример #16
0
class Test_export_html(object):
    def setUp(self):
        self.database = Database(
            Connection_wrapper(
                sqlite.connect(":memory:",
                               detect_types=sqlite.PARSE_DECLTYPES,
                               check_same_thread=False)),
            cache=Stub_cache(),
        )
        self.database.execute_script(file("model/schema.sqlite").read(),
                                     commit=True)

        self.username = u"mulder"
        self.password = u"trustno1"
        self.email_address = u"*****@*****.**"
        self.user = User.create(self.database.next_id(User), self.username,
                                self.password, self.email_address)
        self.database.save(self.user, commit=False)

        self.trash = Notebook.create(self.database.next_id(Notebook), u"trash")
        self.database.save(self.trash, commit=False)
        self.notebook = Notebook.create(self.database.next_id(Notebook),
                                        u"notebook",
                                        self.trash.object_id,
                                        user_id=self.user.object_id)
        self.database.save(self.notebook, commit=False)

        note_id = self.database.next_id(Note)
        self.note1 = Note.create(note_id,
                                 u"<h3>my title</h3>blah",
                                 notebook_id=self.notebook.object_id,
                                 startup=True,
                                 user_id=self.user.object_id)
        self.database.save(self.note1, commit=False)

        note_id = self.database.next_id(Note)
        self.note2 = Note.create(note_id,
                                 u"<h3>other title</h3>whee",
                                 notebook_id=self.notebook.object_id,
                                 user_id=self.user.object_id)
        self.database.save(self.note2, commit=False)

    def test_export_html(self):
        note3 = Note.create("55",
                            u"<h3>blah</h3>foo",
                            notebook_id=self.notebook.object_id)
        self.database.save(note3)
        response_headers = {}
        expected_notes = (self.note1, self.note2, note3)

        result = invoke(
            "export",
            "html",
            self.database,
            self.notebook,
            expected_notes,
            response_headers,
        )

        # response headers should be unchanged
        assert response_headers == {}

        notes = result.get("notes")
        assert len(notes) == len(expected_notes)

        # assert that the notes are in the expected order
        for (note, expected_note) in zip(notes, expected_notes):
            assert note.object_id == expected_note.object_id
            assert note.revision == expected_note.revision
            assert note.title == expected_note.title
            assert note.contents == expected_note.contents
            assert note.notebook_id == expected_note.notebook_id
            assert note.startup == expected_note.startup
            assert note.deleted_from_id == expected_note.deleted_from_id
            assert note.rank == expected_note.rank
            assert note.user_id == expected_note.user_id
            assert note.creation == expected_note.creation
Пример #17
0
class Test_schema_upgrader(object):
    def setUp(self):
        # make an in-memory sqlite database to use during testing
        self.connection = Connection_wrapper(
            sqlite.connect(":memory:",
                           detect_types=sqlite.PARSE_DECLTYPES,
                           check_same_thread=False))
        self.cache = Stub_cache()
        cursor = self.connection.cursor()
        cursor.execute(Stub_object.sql_create_table())

        self.fake_files = {
        }  # map of fake filename (full path) to fake file contents
        self.database = Database(self.connection, self.cache)
        self.upgrader = Schema_upgrader(self.database,
                                        glob=self.glob,
                                        read_file=self.read_file)

    def tearDown(self):
        self.database.close()

    def glob(self, glob_pattern):
        """
    A fake glob function that doesn't use the filesystem.
    """
        re_pattern = re.compile(glob_pattern.replace("*", "[^/]*"))

        return [
            filename for filename in self.fake_files.keys()
            if re_pattern.search(filename)
        ]

    def read_file(self, filename):
        """
    A fake read file function that doesn't use the filesystem.
    """
        contents = self.fake_files.get(filename)

        if not contents:
            raise IOError()

        return contents

    def test_upgrade_schema(self, to_version=None):
        if not to_version:
            to_version = u"5.7.11"

        self.fake_files = {
            u"model/delta/5.6.7.sqlite":
            u"create table new_table ( foo text ); insert into new_table values ( 'hi' );",
            u"model/delta/5.6.8.sqlite":
            u"insert into new_table values ( 'bye' );",
            u"model/delta/5.6.10.sqlite":
            u"alter table new_table add column bar text;",
            u"model/delta/5.7.11.sqlite":
            u"insert into new_table values ( 'whee', 'stuff' );",
            u"model/delta/5.7.18.sqlite":
            u"insert into new_table values ( 'more', 'things' );",
        }

        self.upgrader.upgrade_schema(to_version)

        result = self.database.select_many(tuple, u"select * from new_table;")
        if to_version == u"5.7.11":
            assert result == [(u"hi", None), (u"bye", None), ("whee", "stuff")]
        else:
            assert result == [(u"hi", None), (u"bye", None), ("whee", "stuff"),
                              ("more", "things")]

        result = self.database.select_many(tuple,
                                           u"select * from schema_version;")
        if to_version == u"5.7.11":
            assert result == [(5, 7, 11)]
        else:
            assert result == [(5, 7, 18)]

    def test_upgrade_schema_with_schema_version_table(self):
        self.database.execute(
            u"create table schema_version ( major numeric, minor numeric, \"release\" numeric );"
        )
        self.database.execute(
            u"insert into schema_version values ( 0, 0, 0 );")
        self.test_upgrade_schema()

    def test_upgrade_schema_with_schema_version_table_and_starting_version(
            self):
        self.database.execute(
            u"create table schema_version ( major numeric, minor numeric, \"release\" numeric );"
        )
        self.database.execute(
            u"insert into schema_version values ( 5, 6, 6 );")

        self.fake_files[
            u"model/delta/5.6.1.sqlite"] = u"this is not valid sql and should not be executed anyway;"
        self.fake_files[u"model/delta/5.6.6.sqlite"] = u"also invalid;"

        self.test_upgrade_schema()

    def test_upgrade_schema_with_schema_version_table_and_target_version_without_schema(
            self):
        self.database.execute(
            u"create table schema_version ( major numeric, minor numeric, \"release\" numeric );"
        )
        self.database.execute(
            u"insert into schema_version values ( 0, 0, 0 );")
        self.test_upgrade_schema(to_version=u"5.7.20")

    def test_upgrade_schema_with_schema_version_table_and_starting_version_and_target_version_without_schema(
            self):
        self.database.execute(
            u"create table schema_version ( major numeric, minor numeric, \"release\" numeric );"
        )
        self.database.execute(
            u"insert into schema_version values ( 5, 6, 6 );")
        self.test_upgrade_schema(to_version=u"5.7.20")

    def test_upgrade_schema_with_future_ending_version(self):
        self.fake_files = {
            u"model/delta/5.6.7.sqlite":
            u"create table new_table ( foo text ); insert into new_table values ( 'hi' );",
            u"model/delta/5.6.8.sqlite":
            u"insert into new_table values ( 'bye' );",
            u"model/delta/5.6.10.sqlite":
            u"alter table new_table add column bar text;",
            u"model/delta/5.7.11.sqlite":
            u"insert into new_table values ( 'whee', 'stuff' );",
            u"model/delta/5.7.18.sqlite":
            u"insert into new_table values ( 'more', 'and more' );",
        }

        self.upgrader.upgrade_schema(u"5.8.55")

        result = self.database.select_many(tuple, u"select * from new_table;")
        assert result == [(u"hi", None), (u"bye", None), ("whee", "stuff"),
                          ("more", "and more")]

        result = self.database.select_many(tuple,
                                           u"select * from schema_version;")
        assert result == [(5, 7, 18)]

    def test_upgrade_schema_twice(self):
        self.test_upgrade_schema()

        # the second upgrade should have no effect, because at this point it's already upgraded
        self.test_upgrade_schema()

    def test_upgrade_schema_with_filename_with_invalid_version(self):
        # the filename, not composed of all-integer parts, should be skipped
        self.fake_files[
            u"model/delta/5.6.9b.sqlite"] = u"this is not valid sql and should not be executed anyway;"

        self.test_upgrade_schema()

    def test_upgrade_schema_default_to_start_version_of_1_5_4(self):
        # test that if no schema_version table exists, then the starting version is assumed to be 1.5.4
        self.fake_files = {
            u"model/delta/1.5.3.sqlite":
            u"invalid sql;",
            u"model/delta/1.5.4.sqlite":
            u"should not be invoked;",
            u"model/delta/1.5.5.sqlite":
            u"create table new_table ( foo text ); insert into new_table values ( 'hi' );",
            u"model/delta/1.5.6.sqlite":
            u"insert into new_table values ( 'bye' );",
        }

        self.upgrader.upgrade_schema(u"1.5.6")

        result = self.database.select_many(tuple, u"select * from new_table;")
        assert result == [
            (u"hi", ),
            (u"bye", ),
        ]

        result = self.database.select_many(tuple,
                                           u"select * from schema_version;")
        assert result == [(1, 5, 6)]

    def test_apply_schema_delta(self):
        self.database.execute(
            u"create table schema_version ( major numeric, minor numeric, \"release\" numeric );"
        )
        self.database.execute(
            u"insert into schema_version values ( 0, 0, 0 );")

        self.fake_files = {
            u"model/delta/5.6.5.sqlite":
            u"insert into new_table values ( 'should not show up' );",
            u"model/delta/5.6.7.sqlite":
            u"create table new_table ( foo text ); insert into new_table values ( 'hi' );",
            u"model/delta/5.7.18.sqlite":
            u"insert into new_table values ( 'should not be present' );",
        }

        self.upgrader.apply_schema_delta((5, 6, 7),
                                         u"model/delta/5.6.7.sqlite")

        result = self.database.select_many(unicode,
                                           u"select * from new_table;")
        assert result == [u"hi"]

        result = self.database.select_many(tuple,
                                           u"select * from schema_version;")
        assert result == [(5, 6, 7)]

    @raises(IOError)
    def test_apply_schema_delta_with_unknown_file(self):
        self.upgrader.apply_schema_delta((5, 6, 7),
                                         u"model/delta/5.6.7.sqlite")

    def test_version_string_to_tuple(self):
        version = self.upgrader.version_string_to_tuple("2.5.13")

        assert len(version) == 3
        assert version[0] == 2
        assert version[1] == 5
        assert version[2] == 13

    def test_version_string_to_tuple_with_extension(self):
        version = self.upgrader.version_string_to_tuple("2.5.13.sqlite")

        assert len(version) == 3
        assert version[0] == 2
        assert version[1] == 5
        assert version[2] == 13

    @raises(ValueError)
    def test_version_string_to_tuple_with_too_many_parts(self):
        version = self.upgrader.version_string_to_tuple("3.14.159.26.5")

    @raises(ValueError)
    def test_version_string_to_tuple_with_too_few_parts(self):
        version = self.upgrader.version_string_to_tuple("3.14")

    @raises(ValueError)
    def test_version_string_to_tuple_with_non_integer_part(self):
        version = self.upgrader.version_string_to_tuple("2.5b.13")

    @raises(ValueError)
    def test_version_string_to_tuple_with_empty_part(self):
        version = self.upgrader.version_string_to_tuple("2..13")
Пример #18
0
class Test_controller(object):
    def __init__(self):
        from model.User import User
        from model.Group import Group
        from model.Notebook import Notebook
        from model.Note import Note
        from model.Invite import Invite
        from model.User_revision import User_revision
        from model.File import File

    def setUp(self):
        # trick tested methods into using a fake SMTP server
        Stub_smtp.reset()
        smtplib.SMTP = Stub_smtp

        from controller.Root import Root
        cherrypy.lowercase_api = True
        self.database = Database(
            Connection_wrapper(
                sqlite.connect(":memory:",
                               detect_types=sqlite.PARSE_DECLTYPES,
                               check_same_thread=False)),
            cache=Stub_cache(),
        )
        self.database.execute_script(file("model/schema.sqlite").read(),
                                     commit=True)

        self.settings = {
            u"global": {
                u"server.environment":
                "production",
                u"session_filter.on":
                True,
                u"session_filter.storage_type":
                u"ram",
                u"encoding_filter.on":
                True,
                u"encoding_filter.encoding":
                "utf-8",
                u"decoding_filter.on":
                True,
                u"decoding_filter.encoding":
                "utf-8",
                u"server.log_to_screen":
                False,
                u"luminotes.http_url":
                u"http://luminotes.com",
                u"luminotes.https_url":
                u"https://luminotes.com",
                u"luminotes.http_proxy_ip":
                u"127.0.0.1",
                u"luminotes.https_proxy_ip":
                u"127.0.0.2",
                u"luminotes.support_email":
                "*****@*****.**",
                u"luminotes.payment_email":
                "*****@*****.**",
                u"luminotes.rate_plans": [
                    {
                        u"name":
                        u"super",
                        u"storage_quota_bytes":
                        1337 * 10,
                        u"notebook_collaboration":
                        False,
                        u"user_admin":
                        False,
                        u"included_users":
                        1,
                        u"fee":
                        1.99,
                        u"yearly_fee":
                        19.90,
                        u"button":
                        u"[subscribe here user %s!] button (modify=%s)",
                        u"yearly_button":
                        u"[yearly subscribe here user %s!] button (modify=%s)",
                    },
                    {
                        u"name":
                        "extra super",
                        u"storage_quota_bytes":
                        31337 * 1000,
                        u"notebook_collaboration":
                        True,
                        u"user_admin":
                        True,
                        u"included_users":
                        3,
                        u"fee":
                        9.00,
                        u"yearly_fee":
                        90.00,
                        u"button":
                        u"[or here user %s!] button (modify=%s)",
                        u"yearly_button":
                        u"[yearly or here user %s!] button (modify=%s)",
                    },
                ],
                "luminotes.download_products": [
                    {
                        "name": "local desktop extravaganza",
                        "designed_for": "individuals",
                        "storage_quota_bytes": None,
                        "included_users": 1,
                        "notebook_sharing": False,
                        "notebook_collaboration": False,
                        "user_admin": False,
                        "fee": "30.00",
                        "item_number": "5000",
                        "filename": "test.exe",
                        "button": u"",
                    },
                ],
            },
            u"/files/download": {
                u"stream_response": True,
                u"encoding_filter.on": False,
            },
            u"/files/download_product": {
                u"stream_response": True,
                u"encoding_filter.on": False,
            },
            u"/notebooks/export_csv": {
                u"stream_response": True,
                u"encoding_filter.on": False,
            },
            u"/files/progress": {
                u"stream_response": True,
            },
        }

        cherrypy.root = Root(self.database,
                             self.settings,
                             suppress_exceptions=True)
        cherrypy.config.update(self.settings)
        cherrypy.server.start(init_only=True, server_class=None)

        # since we only want to test the controller, use the stub view for all exposed methods
        import controller.Expose
        Stub_view.result = None
        controller.Expose.view_override = Stub_view

    def tearDown(self):
        self.database.close()
        cherrypy.server.stop()

    def http_get(self,
                 http_path,
                 headers=None,
                 session_id=None,
                 pretend_https=False):
        """
    Perform an HTTP GET with the given path on the test server. Return the result dict as returned
    by the invoked method.
    """
        if headers is None:
            headers = []

        if session_id:
            headers.append(
                (u"Cookie", "session_id=%s" %
                 session_id))  # will break if unicode is used for the value

        if pretend_https:
            proxy_ip = self.settings["global"].get(u"luminotes.https_proxy_ip")
        else:
            proxy_ip = self.settings["global"].get(u"luminotes.http_proxy_ip")

        request = cherrypy.server.request((proxy_ip, 1234), u"127.0.0.5")
        response = request.run("GET %s HTTP/1.0" % str(http_path),
                               headers=headers,
                               rfile=StringIO())
        session_id = response.simple_cookie.get(u"session_id")
        if session_id: session_id = session_id.value

        try:
            if Stub_view.result is not None:
                result = Stub_view.result
                Stub_view.result = None
            else:
                result = dict(
                    status=response.status,
                    headers=response.headers,
                    body=response.body,
                )

            result[u"session_id"] = session_id
            return result
        finally:
            request.close()

    def http_post(self, http_path, form_args, headers=None, session_id=None):
        """
    Perform an HTTP POST with the given path on the test server, sending the provided form_args
    dict. Return the result dict as returned by the invoked method.
    """
        from urllib import urlencode
        if isinstance(form_args, dict):
            form_args = form_args.items()
        post_data = urlencode([(k, isinstance(v, unicode) and v.encode("utf-8")
                                or v) for (k, v) in form_args])

        if headers is None:
            headers = []

        headers.extend([
            (u"Content-Type", u"application/x-www-form-urlencoded"),
            (u"Content-Length", unicode(len(post_data))),
        ])

        if session_id:
            headers.append(
                (u"Cookie", "session_id=%s" %
                 session_id))  # will break if unicode is used for the value

        request = cherrypy.server.request((u"127.0.0.1", 1234), u"127.0.0.5")
        response = request.run("POST %s HTTP/1.0" % str(http_path),
                               headers=headers,
                               rfile=StringIO(post_data))
        session_id = response.simple_cookie.get(u"session_id")
        if session_id: session_id = session_id.value

        try:
            if Stub_view.result is not None:
                result = Stub_view.result
                Stub_view.result = None
            else:
                result = dict(
                    status=response.status,
                    headers=response.headers,
                    body=response.body,
                )

            result[u"session_id"] = session_id
            return result
        finally:
            request.close()

    def http_upload(self,
                    http_path,
                    form_args,
                    filename,
                    file_data,
                    content_type,
                    simulate_cancel=False,
                    headers=None,
                    session_id=None):
        """
    Perform an HTTP POST with the given path on the test server, sending the provided form_args
    and file_data as a multipart form file upload. Return the result dict as returned by the
    invoked method.
    """
        boundary = "boundarygoeshere"
        post_data = ["--%s\n" % boundary]

        for (name, value) in form_args.items():
            post_data.append(
                'Content-Disposition: form-data; name="%s"\n\n%s\n--%s\n' %
                (str(name), str(value), boundary))

        post_data.append(
            'Content-Disposition: form-data; name="upload"; filename="%s"\n' %
            (filename.encode("utf8")))
        post_data.append(
            "Content-Type: %s\nContent-Transfer-Encoding: binary\n\n%s\n--%s--\n"
            % (content_type, file_data, boundary))

        if headers is None:
            headers = []

        post_data = "".join(post_data)
        headers.append(
            ("Content-Type", "multipart/form-data; boundary=%s" % boundary))

        if "Content-Length" not in [name for (name, value) in headers]:
            headers.append(("Content-Length", str(len(post_data))))

        if session_id:
            headers.append(
                (u"Cookie", "session_id=%s" %
                 session_id))  # will break if unicode is used for the value

        if simulate_cancel:
            file_wrapper = Truncated_StringIO(post_data)
        else:
            file_wrapper = Wrapped_StringIO(post_data)

        request = cherrypy.server.request((u"127.0.0.1", 1234), u"127.0.0.5")
        response = request.run("POST %s HTTP/1.0" % str(http_path),
                               headers=headers,
                               rfile=file_wrapper)
        session_id = response.simple_cookie.get(u"session_id")
        if session_id: session_id = session_id.value

        try:
            if Stub_view.result is not None:
                result = Stub_view.result
                Stub_view.result = None
            else:
                result = dict(
                    status=response.status,
                    headers=response.headers,
                    body=response.body,
                )

            result[u"session_id"] = session_id
            return result
        finally:
            request.close()
Пример #19
0
class Test_export_csv(object):
    def setUp(self):
        self.database = Database(
            Connection_wrapper(
                sqlite.connect(":memory:",
                               detect_types=sqlite.PARSE_DECLTYPES,
                               check_same_thread=False)),
            cache=Stub_cache(),
        )
        self.database.execute_script(file("model/schema.sqlite").read(),
                                     commit=True)

        self.username = u"mulder"
        self.password = u"trustno1"
        self.email_address = u"*****@*****.**"
        self.user = User.create(self.database.next_id(User), self.username,
                                self.password, self.email_address)
        self.database.save(self.user, commit=False)

        self.trash = Notebook.create(self.database.next_id(Notebook), u"trash")
        self.database.save(self.trash, commit=False)
        self.notebook = Notebook.create(self.database.next_id(Notebook),
                                        u"notebook",
                                        self.trash.object_id,
                                        user_id=self.user.object_id)
        self.database.save(self.notebook, commit=False)

        note_id = self.database.next_id(Note)
        self.note1 = Note.create(note_id,
                                 u"<h3>my title</h3>blah",
                                 notebook_id=self.notebook.object_id,
                                 startup=True,
                                 user_id=self.user.object_id)
        self.database.save(self.note1, commit=False)

        note_id = self.database.next_id(Note)
        self.note2 = Note.create(note_id,
                                 u"<h3>other title</h3>whee",
                                 notebook_id=self.notebook.object_id,
                                 user_id=self.user.object_id)
        self.database.save(self.note2, commit=False)

    def test_export_csv(self, note_contents=None, expected_contents=None):
        if not note_contents:
            note_contents = u"<h3>blah</h3>foo"

        note3 = Note.create(self.database.next_id(Note),
                            note_contents,
                            notebook_id=self.notebook.object_id,
                            user_id=self.user.object_id)
        self.database.save(note3)
        response_headers = {}
        expected_notes = (self.note1, self.note2, note3)

        result = invoke(
            "export",
            "csv",
            self.database,
            self.notebook,
            expected_notes,
            response_headers,
        )

        assert response_headers
        assert response_headers[u"Content-Type"] == u"text/csv;charset=utf-8"
        assert response_headers[
            u"Content-Disposition"] == 'attachment; filename=%s.csv' % self.notebook.friendly_id

        assert isinstance(result, types.GeneratorType)
        pieces = []

        for piece in result:
            pieces.append(piece)

        csv_data = "".join(pieces)
        reader = csv.reader(StringIO(csv_data))

        row = reader.next()
        expected_header = [
            u"contents", u"title", u"note_id", u"startup", u"username",
            u"revision_date"
        ]
        assert row == expected_header

        note_count = 0

        # assert that startup notes come first, then normal notes in descending revision order
        for row in reader:
            assert len(row) == len(expected_header)
            (contents, title, note_id, startup, username, revision_date) = row

            assert note_count < len(expected_notes)
            expected_note = expected_notes[note_count]

            assert expected_note
            if expected_contents and note_id == note3.object_id:
                assert contents.decode("utf8") == expected_contents.replace(
                    "\n", " ").strip()
            else:
                assert contents.decode(
                    "utf8") == expected_note.contents.replace("\n",
                                                              " ").strip()

            if expected_note.title:
                assert title.decode("utf8") == expected_note.title.strip()
            else:
                assert not title

            assert note_id.decode("utf8") == expected_note.object_id
            assert startup.decode(
                "utf8") == expected_note.startup and u"1" or "0"
            assert username.decode("utf8") == (expected_note.user_id
                                               and self.user.username or u"")
            assert revision_date.decode("utf8") == unicode(
                expected_note.revision)

            note_count += 1

        assert note_count == len(expected_notes)

    def test_export_csv_with_unicode(self):
        self.test_export_csv(note_contents=u"<h3>blah</h3>ümlaut.png")

    def test_export_csv_without_note_title(self):
        self.test_export_csv(note_contents=u"there's no title")

    def test_export_csv_with_trailing_newline_in_title(self):
        self.test_export_csv(note_contents=u"<h3>blah\n</h3>foo")

    def test_export_csv_with_trailing_newline_in_contents(self):
        self.test_export_csv(note_contents=u"<h3>blah</h3>foo\n")

    def test_export_csv_with_file_attachment_in_contents(self):
        self.test_export_csv(
            note_contents=
            u"<h3>blah</h3>foo<a href=\"/files/download?file_id=blah&quote_filename=False\">file</a>",
            expected_contents="<h3>blah</h3>foo<a>file</a>",
        )

    def test_export_csv_with_image_in_contents(self):
        self.test_export_csv(
            note_contents=
            u"<h3>blah</h3>foo<a href=\"/files/download?file_id=blah&quote_filename=False\"><img src=\"whee.png\" /></a>",
            expected_contents="<h3>blah</h3>foo<a></a>",
        )

    def test_export_csv_with_blank_username(self):
        self.user._User__username = None
        self.database.save(self.user)

        self.test_export_csv(note_contents=u"<h3>blah</h3>foo")
Пример #20
0
class Test_export_csv( object ):
  def setUp( self ):
    self.database = Database(
      Connection_wrapper( sqlite.connect( ":memory:", detect_types = sqlite.PARSE_DECLTYPES, check_same_thread = False ) ),
      cache = Stub_cache(),
    )
    self.database.execute_script( file( "model/schema.sqlite" ).read(), commit = True )

    self.username = u"mulder"
    self.password = u"trustno1"
    self.email_address = u"*****@*****.**"
    self.user = User.create( self.database.next_id( User ), self.username, self.password, self.email_address )
    self.database.save( self.user, commit = False )

    self.trash = Notebook.create( self.database.next_id( Notebook ), u"trash" )
    self.database.save( self.trash, commit = False )
    self.notebook = Notebook.create( self.database.next_id( Notebook ), u"notebook", self.trash.object_id, user_id = self.user.object_id )
    self.database.save( self.notebook, commit = False )

    note_id = self.database.next_id( Note )
    self.note1 = Note.create( note_id, u"<h3>my title</h3>blah", notebook_id = self.notebook.object_id, startup = True, user_id = self.user.object_id )
    self.database.save( self.note1, commit = False )

    note_id = self.database.next_id( Note )
    self.note2 = Note.create( note_id, u"<h3>other title</h3>whee", notebook_id = self.notebook.object_id, user_id = self.user.object_id )
    self.database.save( self.note2, commit = False )

  def test_export_csv( self, note_contents = None, expected_contents = None ):
    if not note_contents:
      note_contents = u"<h3>blah</h3>foo"

    note3 = Note.create( self.database.next_id( Note ), note_contents, notebook_id = self.notebook.object_id, user_id = self.user.object_id )
    self.database.save( note3 )
    response_headers = {}
    expected_notes = ( self.note1, self.note2, note3 )

    result = invoke(
      "export",
      "csv",
      self.database,
      self.notebook,
      expected_notes,
      response_headers,
    )

    assert response_headers
    assert response_headers[ u"Content-Type" ] == u"text/csv;charset=utf-8"
    assert response_headers[ u"Content-Disposition" ] == 'attachment; filename=%s.csv' % self.notebook.friendly_id

    assert isinstance( result, types.GeneratorType )
    pieces = []

    for piece in result:
      pieces.append( piece )

    csv_data = "".join( pieces )
    reader = csv.reader( StringIO( csv_data ) )

    row = reader.next()
    expected_header = [ u"contents", u"title", u"note_id", u"startup", u"username", u"revision_date" ]
    assert row == expected_header

    note_count = 0

    # assert that startup notes come first, then normal notes in descending revision order
    for row in reader:
      assert len( row ) == len( expected_header )
      ( contents, title, note_id, startup, username, revision_date ) = row

      assert note_count < len( expected_notes )
      expected_note = expected_notes[ note_count ]

      assert expected_note
      if expected_contents and note_id == note3.object_id:
        assert contents.decode( "utf8" ) == expected_contents.replace( "\n", " " ).strip()
      else:
        assert contents.decode( "utf8" ) == expected_note.contents.replace( "\n", " " ).strip()

      if expected_note.title:
        assert title.decode( "utf8" ) == expected_note.title.strip()
      else:
        assert not title

      assert note_id.decode( "utf8" ) == expected_note.object_id
      assert startup.decode( "utf8" ) == expected_note.startup and u"1" or "0"
      assert username.decode( "utf8" ) == ( expected_note.user_id and self.user.username or u"" )
      assert revision_date.decode( "utf8" ) == unicode( expected_note.revision )

      note_count += 1

    assert note_count == len( expected_notes )

  def test_export_csv_with_unicode( self ):
    self.test_export_csv( note_contents = u"<h3>blah</h3>ümlaut.png" )

  def test_export_csv_without_note_title( self ):
    self.test_export_csv( note_contents = u"there's no title" )

  def test_export_csv_with_trailing_newline_in_title( self ):
    self.test_export_csv( note_contents = u"<h3>blah\n</h3>foo" )

  def test_export_csv_with_trailing_newline_in_contents( self ):
    self.test_export_csv( note_contents = u"<h3>blah</h3>foo\n" )

  def test_export_csv_with_file_attachment_in_contents( self ):
    self.test_export_csv(
      note_contents = u"<h3>blah</h3>foo<a href=\"/files/download?file_id=blah&quote_filename=False\">file</a>",
      expected_contents = "<h3>blah</h3>foo<a>file</a>",
    )

  def test_export_csv_with_image_in_contents( self ):
    self.test_export_csv(
      note_contents = u"<h3>blah</h3>foo<a href=\"/files/download?file_id=blah&quote_filename=False\"><img src=\"whee.png\" /></a>",
      expected_contents = "<h3>blah</h3>foo<a></a>",
    )

  def test_export_csv_with_blank_username( self ):
    self.user._User__username = None
    self.database.save( self.user )

    self.test_export_csv( note_contents = u"<h3>blah</h3>foo" )
Пример #21
0
class Test_database(object):
    def setUp(self):
        # make an in-memory sqlite database to use during testing
        self.connection = Connection_wrapper(
            sqlite.connect(":memory:",
                           detect_types=sqlite.PARSE_DECLTYPES,
                           check_same_thread=False))
        self.cache = Stub_cache()
        cursor = self.connection.cursor()
        cursor.execute(Stub_object.sql_create_table())

        self.database = Database(self.connection, self.cache)

    def tearDown(self):
        self.database.close()

    def test_save_and_load(self):
        basic_obj = Stub_object(object_id="5", value=1)
        original_revision = basic_obj.revision

        self.database.save(basic_obj)
        obj = self.database.load(Stub_object, basic_obj.object_id)

        assert obj.object_id == basic_obj.object_id
        assert obj.revision.replace(tzinfo=utc) == original_revision
        assert obj.value == basic_obj.value

    def test_save_and_load_without_commit(self):
        basic_obj = Stub_object(object_id="5", value=1)
        original_revision = basic_obj.revision

        self.database.save(basic_obj, commit=False)
        self.connection.rollback(
        )  # if commit wasn't called, this should back out the save
        obj = self.database.load(Stub_object, basic_obj.object_id)

        assert obj == None

    def test_save_and_load_with_explicit_commit(self):
        basic_obj = Stub_object(object_id="5", value=1)
        original_revision = basic_obj.revision

        self.database.save(basic_obj, commit=False)
        self.database.commit()
        self.connection.rollback(
        )  # should have no effect because of the call to commit
        obj = self.database.load(Stub_object, basic_obj.object_id)

        assert obj.object_id == basic_obj.object_id
        assert obj.revision.replace(tzinfo=utc) == original_revision
        assert obj.value == basic_obj.value

    def test_select_one(self):
        basic_obj = Stub_object(object_id="5", value=1)
        original_revision = basic_obj.revision

        self.database.save(basic_obj)
        obj = self.database.select_one(
            Stub_object, Stub_object.sql_load(basic_obj.object_id))

        assert obj.object_id == basic_obj.object_id
        assert obj.revision.replace(tzinfo=utc) == original_revision
        assert obj.value == basic_obj.value

    def test_select_datetime(self):
        # this revision (with .504099) happens to test for a bug caused by floating point rounding errors
        original_revision = "2008-01-01 01:00:42.504099+00:00"
        basic_obj = Stub_object(object_id="5",
                                revision=original_revision,
                                value=1)

        self.database.save(basic_obj)
        obj = self.database.select_one(
            Stub_object, Stub_object.sql_load(basic_obj.object_id))

        assert obj.object_id == basic_obj.object_id
        assert str(obj.revision.replace(tzinfo=utc)) == original_revision
        assert obj.value == basic_obj.value

    def test_select_datetime_with_many_fractional_digits(self):
        original_revision = "2008-01-01 01:00:42.5032429489284+00:00"
        basic_obj = Stub_object(object_id="5",
                                revision=original_revision,
                                value=1)

        self.database.save(basic_obj)
        obj = self.database.select_one(
            Stub_object, Stub_object.sql_load(basic_obj.object_id))

        assert obj.object_id == basic_obj.object_id
        assert str(obj.revision.replace(
            tzinfo=utc)) == "2008-01-01 01:00:42.503242+00:00"
        assert obj.value == basic_obj.value

    def test_select_datetime_with_zero_fractional_seconds(self):
        original_revision = "2008-01-01 01:00:42.0+00:00"
        basic_obj = Stub_object(object_id="5",
                                revision=original_revision,
                                value=1)

        self.database.save(basic_obj)
        obj = self.database.select_one(
            Stub_object, Stub_object.sql_load(basic_obj.object_id))

        assert obj.object_id == basic_obj.object_id
        assert str(
            obj.revision.replace(tzinfo=utc)) == "2008-01-01 01:00:42+00:00"
        assert obj.value == basic_obj.value

    def test_select_one_tuple(self):
        obj = self.database.select_one(tuple, Stub_object.sql_tuple())

        assert len(obj) == 2
        assert obj[0] == 1
        assert obj[1] == 2

    def test_select_many(self):
        basic_obj = Stub_object(object_id="5", value=1)
        original_revision = basic_obj.revision
        basic_obj2 = Stub_object(object_id="6", value=2)
        original_revision2 = basic_obj2.revision

        self.database.save(basic_obj)
        self.database.save(basic_obj2)
        objs = self.database.select_many(Stub_object,
                                         Stub_object.sql_load_em_all())

        assert len(objs) == 2
        assert objs[0].object_id == basic_obj.object_id
        assert objs[0].revision.replace(tzinfo=utc) == original_revision
        assert objs[0].value == basic_obj.value
        assert objs[1].object_id == basic_obj2.object_id
        assert objs[1].revision.replace(tzinfo=utc) == original_revision2
        assert objs[1].value == basic_obj2.value

    def test_select_many_tuples(self):
        objs = self.database.select_many(tuple, Stub_object.sql_tuple())

        assert len(objs) == 1
        assert len(objs[0]) == 2
        assert objs[0][0] == 1
        assert objs[0][1] == 2

    def test_select_many_with_no_matches(self):
        objs = self.database.select_many(Stub_object,
                                         Stub_object.sql_load_em_all())

        assert len(objs) == 0

    def test_save_and_load_revision(self):
        basic_obj = Stub_object(object_id="5", value=1)
        original_revision = basic_obj.revision

        self.database.save(basic_obj)
        basic_obj.value = 2

        self.database.save(basic_obj)
        obj = self.database.load(Stub_object, basic_obj.object_id)

        assert obj.object_id == basic_obj.object_id
        assert obj.revision.replace(tzinfo=utc) == basic_obj.revision
        assert obj.value == basic_obj.value

        revised = self.database.load(Stub_object,
                                     basic_obj.object_id,
                                     revision=original_revision)

        assert revised.object_id == basic_obj.object_id
        assert revised.value == 1
        assert revised.revision.replace(tzinfo=utc) == original_revision

    def test_execute(self):
        basic_obj = Stub_object(object_id="5", value=1)
        original_revision = basic_obj.revision

        self.database.execute(basic_obj.sql_create())
        obj = self.database.load(Stub_object, basic_obj.object_id)

        assert obj.object_id == basic_obj.object_id
        assert obj.revision.replace(tzinfo=utc) == original_revision
        assert obj.value == basic_obj.value

    def test_execute_without_commit(self):
        basic_obj = Stub_object(object_id="5", value=1)
        original_revision = basic_obj.revision

        self.database.execute(basic_obj.sql_create(), commit=False)
        self.connection.rollback()
        obj = self.database.load(Stub_object, basic_obj.object_id)

        assert obj == None

    def test_execute_with_explicit_commit(self):
        basic_obj = Stub_object(object_id="5", value=1)
        original_revision = basic_obj.revision

        self.database.execute(basic_obj.sql_create(), commit=False)
        self.database.commit()
        obj = self.database.load(Stub_object, basic_obj.object_id)

        assert obj.object_id == basic_obj.object_id
        assert obj.revision.replace(tzinfo=utc) == original_revision
        assert obj.value == basic_obj.value

    def test_load_unknown(self):
        basic_obj = Stub_object(object_id="5", value=1)
        obj = self.database.load(Stub_object, basic_obj.object_id)

        assert obj == None

    def test_next_id(self):
        next_id = self.database.next_id(Stub_object)
        assert next_id
        assert self.database.load(Stub_object, next_id)
        prev_ids = [next_id]

        next_id = self.database.next_id(Stub_object)
        assert next_id
        assert next_id not in prev_ids
        assert self.database.load(Stub_object, next_id)
        prev_ids.append(next_id)

        next_id = self.database.next_id(Stub_object)
        assert next_id
        assert next_id not in prev_ids
        assert self.database.load(Stub_object, next_id)

    def test_next_id_without_commit(self):
        next_id = self.database.next_id(Stub_object, commit=False)
        self.connection.rollback()
        assert self.database.load(Stub_object, next_id) == None

    def test_next_id_with_explicit_commit(self):
        next_id = self.database.next_id(Stub_object, commit=False)
        self.database.commit()
        assert next_id
        assert self.database.load(Stub_object, next_id)

    def test_synchronize(self):
        def make_objects():
            for i in range(50):
                object_id = self.database.next_id(Stub_object)
                basic_obj = Stub_object(object_id, value=1)
                original_revision = basic_obj.revision

                self.database.execute(basic_obj.sql_create())
                obj = self.database.load(Stub_object, basic_obj.object_id)

                assert obj.object_id == basic_obj.object_id
                delta = abs(
                    obj.revision.replace(tzinfo=utc) - original_revision)
                assert delta <= timedelta(seconds=0.000001)
                assert obj.value == basic_obj.value

                object_id = self.database.next_id(Stub_object)

        # if synchronization (locking) is working properly, then these two threads should be able to run
        # simultaneously without error. without locking, SQLite will raise
        thread1 = Thread(target=make_objects)
        thread2 = Thread(target=make_objects)
        thread1.start()
        thread2.start()

        thread1.join()
        thread2.join()

    def test_backend(self):
        assert self.database.backend == Persistent.SQLITE_BACKEND
Пример #22
0
def main(options):
    change_to_main_dir()

    cherrypy.config.update(Common.settings)
    if options.development:
        from config import Development
        settings = Development.settings
    elif options.desktop:
        from config import Desktop
        settings = Desktop.settings
    else:
        from config import Production
        settings = Production.settings

    cherrypy.config.update(settings)

    # Don't launch web browser if -w flag is set
    if options.no_webbrowser:
        launch_browser = False
    else:
        launch_browser = cherrypy.config[u"luminotes.launch_browser"]

    socket.setdefaulttimeout(INITIAL_SOCKET_TIMEOUT_SECONDS)
    port_filename = cherrypy.config[u"luminotes.port_file"]
    socket_port = cherrypy.config[u"server.socket_port"]
    existing_socket_port = port_filename and os.path.exists(
        port_filename) and file(port_filename).read() or socket_port
    server_url = u"http://localhost:%s/" % existing_socket_port
    server_present = True

    # if requested, attempt to shutdown an existing server and exit
    if options.kill:
        try:
            urllib.urlopen("%sshutdown" % server_url)
        except urllib.URLError:
            pass
        sys.exit(0)

    # check to see if the server is already running
    try:
        urllib.urlopen("%sping" % server_url)
    except urllib.URLError:
        server_present = False

    if server_present is True:
        print "Luminotes server is already running. aborting"

        if launch_browser is True:
            webbrowser.open_new(server_url)

        sys.exit(0)

    server_url = u"http://127.0.0.1:%s/" % socket_port

    # remove the existing log files, if any
    try:
        log_access_file = cherrypy.config[u"server.log_access_file"]
        if log_access_file:
            os.remove(log_access_file)
    except OSError:
        pass

    try:
        log_file = cherrypy.config[u"server.log_file"]
        if log_file:
            os.remove(log_file)
    except OSError:
        pass

    socket.setdefaulttimeout(SOCKET_TIMEOUT_SECONDS)

    database = Database(
        host=cherrypy.config[u"luminotes.db_host"],
        ssl_mode=cherrypy.config[u"luminotes.db_ssl_mode"],
    )

    # if necessary, upgrade the database schema to match this current version of the code
    schema_upgrader = Schema_upgrader(database)
    schema_upgrader.upgrade_schema(to_version=VERSION)

    cherrypy.lowercase_api = True
    root = Root(database, cherrypy.config)
    cherrypy.tree.mount(root, '/', config=settings)

    cherrypy.engine.start_with_callback(
        callback, (log_access_file, log_file, server_url, port_filename,
                   socket_port, launch_browser))
    cherrypy.engine.block()
Пример #23
0
def main( args ):
  database = Database()
  ranker = Ranker( database )