Commits

Olemis Lang committed 1a177fc

TracGViz : Migrate testing framework to TracDutest package. Remove TODOs for 1.4.1

... looking forward to 1.4.2

Comments (0)

Files changed (4)

 .\#*
 # Temporary files used by the vim editor.
 .*.swp
+.*.swo
 # A hidden file created by the Mac OS X Finder.
 .DS_Store
 # Compiled Python scripts

trac-dev/gviz/TODO

 Outstanding tasks
 -----------------
 
-X Data provided by `GVizChagesetProvider` in columns `chg` 
-  and `target` needs to be exchanged.
-
-X Details about the latest changeset are shown by `GVizChagesetProvider` 
-  when only `since` and `until` parameters are specified.
-
-X Fix `TypeError` `unsupported operand type(s) for -: instance and datetime.datetime`
-  and `AttributeError` `datetime.datetime object has no attribute value`
-  on accessing ticket data without selecting specific IDs. It seems 
-  that the problem happens because of changes introduced in 
-  different implementations of TracXmlRpc plugin. The former happens 
-  if using version 1.0.6, whereas the later shows up if using version 
-  1.0.0 (but under different circumstances).
-
-X Add support for GViz queries in GViz TracLinks providers.
-
-X Implement a WikiMacro to embed the data exposed by instances of 
-  `IGVizDataProvider`.
-
-X Include GVizProviderListMacro.PROVIDER_DOC in a resource file.
-
-X Ensure that responses are UTF-8 encoded, unless otherwise stated.
-
-X Iterate over rows and values of `DataTable` instances.
-
-X Implement TSV Response Format encoder. 
-
-X Implement report creation from remote via XML-RPC protocol.
-
-X Do not show report SQL in `ReportRPC.get` if client is not granted 
-  `REPORT_SQL_VIEW` permission.
-
-X Fix convert relative URL into absolute in `ReportRPC.execute` only 
-  if needed.
-
-X Add in `dutest` the doctest suite having `setUp` and `tearDown`. 
-  Use it in RPC tests.
-
-X Write simple tests for RPC handlers implemented by TracGViz : 
-  `TimelineRPC`, `ReportRPC`.
-
-X Add support for adding and loading test data.
-
-X Use correct MIME type in TSV encoder.
-
-X GViz API QL: Allow to select the columns to be returned, their 
-  order, and labels.
-
-X GViz API QL: Add support for limitting the number of returned rows, 
-  as well as skipping a given number of first rows.
-
-X GViz API QL: Ensure that columns are always arranged in the same order (use 
-  GVizQL SELECT clause)
-
-X GViz API QL: Notify that the data source doesn't support the base 
-  table specified in `from` clause.
-
-X GViz API QL: Protect against pygments imports.
-
-X GViz API QL: Write tests for all supported GVizQL features.
-
-X Make the plugin easy-installable.
-
-X Add support for `HMAC` (`RFC 2104`) hash by using `hmac` module.
-
-X Render GViz provider list on accessing `/gviz` path.
-
-X Implement CSV and TSV encoders by using `csv` module.
-
-X Include helper to convert CSV attachments to GViz API JSON format.
-
-X Provide `dutest` as an external dependency.
-
-X Add data source and infrastructure to convert files containing 
-  tabular data in different formats to the JSON representation 
-  defined by Google Visualization API. The contents may be 
-  retrieved from anywhere (e.g. VCS, attachments, ...).
-
-X Include helper to convert CSV files under version control to GViz 
-  API JSON format.
-
-X Fix GViz providers index, broken using Trac=1.0
-
-X Bloodhound web UI enhancementX Bloodhound web UI enhancementss
-
-X Upgrade RPC providers for Trac=1.0 and Apache(TM) Bloodhound.
-
 ~ Write tests for data sources included in TracGViz 1.3.4 that are 
   not about version control.
 
 ~ Upgrade GViz providers for Trac=1.0 and Apache(TM) Bloodhound.
 
+- Migrate tracgviz.testing to a new package dutest-trac
+
+- Move `dutest` to `tests_require` rather than `install_requires`.
+
+- Typecasts in CSV to GViz MIME converter.
+
 - Use FSL to select files in GViz providers ?
 
 - Optimize `GVizSourceFileContents` by wrapping VCS file objects 

trac-dev/gviz/setup.py

     (1, 3, 2),
     (1, 3, 3),
     (1, 4, 1),
+    (1, 4, 2),
     ]
     
 latest = '.'.join(str(x) for x in versions[-1])
 PKG_INFO = {'tracgviz' : ('tracgviz',                     # Package dir
                             # Package data
                             ['templates/*', 'htdocs/*', 
-                      		    'messages/es/LC_MESSAGES/*', '../CHANGES', 
+                                  'messages/es/LC_MESSAGES/*', '../CHANGES', 
                               '../COPYRIGHT', '../NOTICE', '../README', 
                               '../TODO'],
                           ), 
                """
 
 setup(
-	name=DIST_NM,
-	version=latest,
-	description=DESC.split('\n', 1)[0],
-	author='Olemis Lang',
-	author_email='olemis@gmail.com',
-	maintainer='Olemis Lang',
-	maintainer_email='olemis@gmail.com',
-	url='https://opensvn.csie.org/traccgi/swlcu/wiki/En/Devel/%s' % (DIST_NM,),
-	download_url='http://pypi.python.org/packages/2.5/%s/%s/%s-%s-py2.5.egg' % \
-	                              (DIST_NM[0], DIST_NM, DIST_NM, latest,),
-	requires = ['trac', 'tracrpc', 'gviz_api', 'pygments', 'dutest'],
-        install_requires = [
-            'setuptools>=0.6b1',
-            'Trac>=0.11',
-            'Pygments>=1.0',
-            'dutest>=0.2.3',
-#            'TracXMLRPC<1.0.7',
-            'TracXMLRPC>=1.0.1',
-          ],
-	package_dir = dict([p, i[0]] for p, i in PKG_INFO.iteritems()),
-	packages = PKG_INFO.keys(),
-	package_data = dict([p, i[1]] for p, i in PKG_INFO.iteritems()),
-	include_package_data=True,
-	provides = ['%s (%s)' % (p, latest) for p in PKG_INFO.keys()],
-	obsoletes = ['%s (>=%s.0.0, <%s)' % (p, versions[-1][0], latest) \
-	              for p in PKG_INFO.keys()],
-	entry_points = ENTRY_POINTS,
-	classifiers = cats,
-	long_description= DESC
-	)
+    name=DIST_NM,
+    version=latest,
+    description=DESC.split('\n', 1)[0],
+    author='Olemis Lang',
+    author_email='olemis@gmail.com',
+    maintainer='Olemis Lang',
+    maintainer_email='olemis+trac@gmail.com',
+    url='https://dataviz.blood-hound.net/wiki/Packages/%s' % (DIST_NM,),
+    download_url='http://pypi.python.org/packages/2.6/%s/%s/%s-%s-py2.6.egg' % \
+                                  (DIST_NM[0], DIST_NM, DIST_NM, latest,),
+    requires = ['trac', 'tracrpc', 'gviz_api', 'pygments', 'dutest'],
+    install_requires = ['setuptools>=0.6b1',
+                        'Trac>=0.11',
+                        'Pygments>=1.0',
+#                       'TracXMLRPC<1.0.7',
+                        'TracXMLRPC>=1.0.1',
+                        'PyICU',],
+    tests_require = ['dutest>=0.2.4',
+                     'dutest-trac',],
+    package_dir = dict([p, i[0]] for p, i in PKG_INFO.iteritems()),
+    packages = PKG_INFO.keys(),
+    package_data = dict([p, i[1]] for p, i in PKG_INFO.iteritems()),
+    include_package_data=True,
+    provides = ['%s (%s)' % (p, latest) for p in PKG_INFO.keys()],
+    obsoletes = ['%s (>=%s.0.0, <%s)' % (p, versions[-1][0], latest) \
+                  for p in PKG_INFO.keys()],
+    entry_points = ENTRY_POINTS,
+    classifiers = cats,
+    long_description= DESC
+    )
+

trac-dev/gviz/tracgviz/testing/__init__.py

 
 __metaclass__ = type
 
-from trac.core import ComponentMeta
-from trac.db.api import _parse_db_str, DatabaseManager
-from trac.test import EnvironmentStub
-
 import os.path
 import sys
 import tempfile
 
-#------------------------------------------------------
-#    Trac environments used for testing purposes
-#------------------------------------------------------
-
-class EnvironmentStub(EnvironmentStub):
-  r"""Enhanced stub of the trac.env.Environment object for testing.
-  """
-
-  # Dont break lazy evaluation. Otherwise RPC calls misteriously fail.
-  @property
-  def _abs_href(self):
-    return self.abs_href
-
-  def enable_component(self, clsdef):
-    r"""Enable a plugin temporarily at testing time.
-    """
-    self.config.set('components', clsdef, 'enabled')
-    self.enabled.clear()
-    try:
-      del self._rules
-    except AttributeError:
-      pass
-
-  def disable_component(self, clsdef):
-    r"""Disable a plugin temporarily at testing time.
-    """
-    self.config.set('components', clsdef, 'disabled')
-    self.enabled.clear()
-    try:
-      del self._rules
-    except AttributeError:
-      pass
-
-  def rip_component(self, cls):
-    r"""Disable a plugin forever and RIP it using the super-laser beam.
-    """
-    self.disable_component(cls)
-    for reg in ComponentMeta._registry.itervalues():
-      try:
-        reg.remove(cls)
-      except ValueError :
-        pass
-
-  if not hasattr(EnvironmentStub, 'reset_db'):
-
-    # Copycat trac.test.EnvironmentStub.reset_db (Trac=0.11.5)
-    def reset_db(self, default_data=None):
-        r"""Remove all data from Trac tables, keeping the tables themselves.
-        :param default_data: after clean-up, initialize with default data
-        :return: True upon success
-        """
-        from trac import db_default
-
-        db = self.get_db_cnx()
-        db.rollback() # make sure there's no transaction in progress
-        cursor = db.cursor()
-
-        defdata = list(db_default.get_data(db))
-
-        for table, cols, vals in defdata:
-            cursor.execute("DELETE FROM %s" % (table,) )
-
-        # Delete tickets as well
-        cursor.execute("DELETE FROM ticket")
-        db.commit()
-
-        if default_data:
-            for table, cols, vals in defdata:
-                cursor.executemany("INSERT INTO %s (%s) VALUES (%s)"
-                                   % (table, ','.join(cols),
-                                      ','.join(['%s' for c in cols])),
-                                   vals)
-        else:
-            cursor.execute("INSERT INTO system (name, value) "
-                           "VALUES (%s, %s)",
-                           ('database_version', str(db_default.db_version)))
-        db.commit()
-
-#------------------------------------------------------
-#    Minimalistic testing framework for Trac
-#------------------------------------------------------
-
-from dutest import DocTestLoader, DocTestSuiteFixture
-from os.path import dirname
-from types import MethodType
-
-from util import dummy_request
-
-# Hide this module from tracebacks written into test results.
-__unittest = True
-
-class DocTestTracLoader(DocTestLoader):
-  r"""A generic XUnit loader that allows to load doctests written 
-  to check that Trac plugins behave as expected.
-  """
-  def set_env(self, env):
-    if self.extraglobs is None :
-      self.extraglobs = dict(env=env)
-    else :
-      self.extraglobs['env'] = env
-
-  env = property(lambda self : self.extraglobs.get('env'), set_env, \
-                  doc="""The Trac environment used in doctests.""")
-  del set_env
-
-  def __init__(self, dt_finder=None, globs=None, extraglobs=None, \
-                          load=None, default_data=False, enable=None, \
-                          **opts):
-    r"""Initialization. It basically works like `DocTestLoader`'s 
-    initializer but creates also the Trac environment used for 
-    testing purposes. The default behavior is to create an instance 
-    of `EnvironmentStub` class. Subclasses can add more specific 
-    keyword parameters in order to use them to create the 
-    environment. Next it loads (and | or) enables the components 
-    needed by the test suite.
-
-    The following variables are magically available at testing time. 
-    They can be used directly in doctests :
-
-    - req         A dummy request object setup for anonymous access.
-    - auth_req    A dummy request object setup like if user `murphy` was  
-                  accessing the site.
-    - env         the Trac environment used as a stub for testing 
-                  purposes (i.e. `self.env`).
-
-    @param dt_finder        see docs for `DocTestLoader.__init__` 
-                            method.
-    @param globs            see docs for `DocTestLoader.__init__` 
-                            method.
-    @param extraglobs       see docs for `DocTestLoader.__init__` 
-                            method.
-    @param load             a list of packages containing components 
-                            that will be loaded to ensure they are 
-                            available at testing time. It should be 
-                            the top level module in that package 
-                            (e.g. 'trac').
-    @param default_data     If true, populate the database with some 
-                            defaults. This parameter has to be 
-                            handled by `createTracEnv` method.
-    @param enable           a list of UNIX patterns specifying which 
-                            components need to be enabled by default 
-                            at testing time. This parameter should be 
-                            handled by `createTracEnv` method.
-    """
-    super(DocTestTracLoader, self).__init__(dt_finder, globs, \
-                                              extraglobs, **opts)
-    self.env = self.createTracEnv(default_data, enable, **opts)
-    self.load_components(load is None and self.default_packages or load)
-
-  # Load trac built-in components by default
-  default_packages = ['trac']
-
-  def createTracEnv(self, default_data=False, enable=None, **params):
-    r"""Create the Trac environment used for testing purposes. The 
-    default behavior is to create an instance of `EnvironmentStub` 
-    class. Subclasses can override this decision and add more specific 
-    keyword parameters in order to control environment creation in 
-    more detail. 
-
-    All parameters supplied at initialization time. By default they 
-    are ignored.
-    @param default_data     If True, populate the database with some 
-                            defaults.
-    @param enable           a list of UNIX patterns specifying which 
-                            components need to be enabled by default 
-                            at testing time.
-    @return                 the environment used for testing purpose.
-    """
-    return EnvironmentStub(default_data, enable)
-
-  def load_components(self, pkgs):
-    r"""Load some packages to ensure that the components they 
-    implement are available at testing time.
-    """
-    from trac.loader import load_components
-    for pkg in pkgs :
-      try :
-        __import__(pkg)
-      except ImportError :
-        pass                        # Skip pkg. What a shame !
-      else :
-        mdl = sys.modules[pkg]
-        load_components(self.env, dirname(dirname(mdl.__file__)))
-
-  class doctestSuiteClass(DocTestSuiteFixture):
-    r"""Prepare the global namespace before running all doctests 
-    in the suite. Reset the Trac environment.
-    """
-    username = 'murphy'
-
-    @property
-    def env(self):
-      r"""The Trac environment involved in this test. It is 
-      retrieved using the global namespace ;o).
-      """
-      return self.globalns['env']
-
-    def new_request(self, uname=None, args=None):
-      r"""Create and initialize a new request object.
-      """
-      req = dummy_request(self.env, uname)
-      if args is not None :
-        req.args = args
-      return req
-
-    def setUp(self):
-      r"""Include two (i.e. `req` anonymous and `auth_req` 
-      authenticated) request objects in the global namespace, before 
-      running the doctests. Besides, clean up environment data and 
-      include only default data.
-      """
-      globs = self.globalns
-      req = self.new_request(args=dict())
-      auth_req = self.new_request(uname=self.username, args=dict())
-      globs['req'] = req
-      globs['auth_req'] = auth_req
-      # TODO: If the source docstrings belong to a Trac component, 
-      #       then instantiate it and include in the global 
-      #       namespace.
-      self.env.reset_db(default_data=True)
-      self.setup_logging()
-
-    def setup_logging(self):
-      r"""Log events to temp file
-      """
-      logdir = tempfile.gettempdir()
-      logpath = os.path.join(logdir, 'trac-testing.log')
-      config = self.env.config
-      config.set('logging', 'log_file', logpath)
-      config.set('logging', 'log_type', 'file')
-      config.set('logging', 'log_level', 'DEBUG')
-      config.save()
-      self.env.setup_log()
-      self.env.log.info('%s test case: %s %s', '-' * 9, self._dt.name, '-' * 9)
-
-class RpcDirectProxy :
-  r"""A proxy used in tests to interact with RPC handlers just like 
-  if it were an ordinary object (i.e. without the need for supplying 
-  a request object explicitly in each method call).
-
-  It also asserts that the permissions necessary to execute a given 
-  method are satisfied by the request object
-  """
-  def __init__(self, rpcobj, req):
-    r"""Initialization.
-
-    @param rpcobj         the target RPC handler object.
-    @param req            a request object that will be supplied 
-                          in each call to the methods defined by 
-                          the target RPC handler (i.e. `rpcobj`).
-    """
-    self._rpcobj = rpcobj
-    self._req = req
-    self._perms = dict([m.im_func.__name__, p] \
-                              for p, _, m in rpcobj.xmlrpc_methods())
-  def __getattr__(self, attrnm):
-    r"""Control access to target RPC handler object, and assert that 
-    the right permissions have been granted to the user specified in 
-    the request.
-    """
-    try :
-      val = getattr(self._rpcobj, attrnm)
-    except AttributeError :
-      raise
-    else :
-      if isinstance(val, MethodType):
-        def rpcmethod(*args, **kwds):
-          try :
-            p = self._perms[attrnm]
-          except KeyError :
-            pass
-          else :
-            self._req.perm.require(p)
-          return val(self._req, *args, **kwds)
-        return rpcmethod
-      else :
-        return val
-
-class DocTestRpcLoader(DocTestTracLoader):
-  r"""Load doctests used to test Trac RPC handlers.
-  """
-  # Load trac built-in components and standard RPC handlers by default
-  default_packages = ['trac', 'tracrpc']
-
-  class doctestSuiteClass(DocTestTracLoader.doctestSuiteClass):
-    r"""Include the appropriate RPC handler in global namespace 
-    before running all test cases in the suite.
-    """
-
-    def ns_from_name(self):
-      r"""Extract the target namespace under test using the name
-      of the DocTest instance manipulated by the suite.
-      """
-      try :
-        return self._dt.name.split(':', 1)[0].split('|', 1)[-1]
-      except :
-        return None
-
-    def partial_setup(self):
-      r"""Perform partial setup due to some minor failure (e.g. 
-      namespace missing in test name).
-      """
-      globs = self.globalns
-      globs['rpcobj'] = globs['auth_rpcobj'] = None
-
-    def setup_rpc(self, rpcns):
-      r"""(Insert | update) the correct RPC handler in the global 
-      namespace.
-
-      @param rpc                  the RPC namespace used to load the 
-                                  RPC handler.
-      @throws RuntimeError        if the handler bound to the 
-                                  requested namespace cannot be found.
-      """
-      globs = self.globalns
-      for rpch in self.rpcsys.method_handlers :
-        self.env.log.debug('Matching RPC namespace %s %s', rpcns, \
-            rpch.xmlrpc_namespace() )
-        if rpch.xmlrpc_namespace() == rpcns :
-          globs['rpcobj'] = RpcDirectProxy(rpch, globs['req'])
-          globs['auth_rpcobj'] = RpcDirectProxy(rpch, globs['auth_req'])
-          break
-      else :
-        raise RuntimeError('Cannot load RPC handler for %s' % rpcns)
-
-    def setUp(self):
-      r"""Include the appropriate RPC handler in global namespace 
-      before running all test cases in the suite. In this case two 
-      objects are added to the global namespace :
-
-        - `rpcobj`          an instnnce of the RPC handler used to 
-                            perform anonymous requests.
-        - `auth_rpcobj`     an instance of the RPC handler used to 
-                            perform authenticated requests. The user 
-                            name is determined by `username` 
-                            attribute and defaults to `murphy`.
-      """
-      # Fail here if XmlRpcPlugin is not available. Thus 
-      # this fact will be reported as a failure and subsequent test 
-      # cases will be run anyway.
-      from tracrpc.api import XMLRPCSystem
-      self.rpcsys = XMLRPCSystem(self.env)
-
-      # Add request objects
-      DocTestTracLoader.doctestSuiteClass.setUp(self)
-
-      rpcns = self.ns_from_name()
-      if rpcns is None :
-        # TODO: If doctests belong to an RPC handler class then 
-        #       instantiate it. In the mean time ...
-        self.partial_setup()
-      else :
-        try :
-          self.setup_rpc(rpcns)
-        except RuntimeError :
-          self.partial_setup()
-
-#------------------------------------------------------
-#    Test artifacts used to test GViz providers
-#------------------------------------------------------
-
-class DocTestGVizLoader(DocTestRpcLoader):
-  r"""Load doctests used to test Trac GViz providers.
-  """
-  if not __name__.startswith('tracgviz.'):
-    # Load trac built-in components and standard RPC handlers 
-    # and GViz core system if used outside TracGViz package ;o).
-    default_packages = ['trac', 'tracrpc', 'tracgviz']
-
-  class doctestSuiteClass(DocTestTracLoader.doctestSuiteClass):
-    r"""Include the appropriate RPC handler in global namespace 
-    before running all test cases in the suite.
-    """
-    def setUp(self):
-      r"""Include the appropriate RPC handler and GViz provider in 
-      global namespace before running all test cases in the suite. 
-      In this case four objects are added to the global namespace :
-
-        - `rpcobj`          an instance of the RPC handler used to 
-                            perform anonymous requests.
-        - `auth_rpcobj`     an instance of the RPC handler used to 
-                            perform authenticated requests. The user 
-                            name is determined by `username` 
-                            attribute and defaults to `murphy`.
-        - `gvizobj`         an instance of the GViz provider used to 
-                            retrieve data just like if `anonymous` 
-                            user was accessing the site.
-        - `auth_gvizobj`    an instance of the GViz provider used to 
-                            retrieve data just like if an 
-                            authenticated user was accessing the site.
-                            The user name is determined by `username` 
-                            attribute and defaults to `murphy`.
-      """
-      # Fail here if either XmlRpcPlugin or TracGViz are not 
-      # available. Thus this fact will be reported as a failure and 
-      # subsequent test cases will be run anyway.
-      from tracrpc.api import XMLRPCSystem
-      self.rpcsys = XMLRPCSystem(self.env)
-      from tracgviz.api import TracGVizSystem
-      self.gvizsys = TracGVizSystem(self.env)
-
-      # Add request objects
-      DocTestTracLoader.doctestSuiteClass.setUp(self)
-
-      gvizns = self.ns_from_name()
-      if rpcns is None :
-        # TODO: If doctests belong to a GViz provider class then 
-        #       instantiate it. In the mean time ...
-        self.partial_setup()
-      else :
-        try :
-          rpcns = self.setup_gviz(gvizns)
-        except RuntimeError :
-          self.partial_setup()
-        else :
-          try :
-            self.setup_rpc(rpcns)
-          except RuntimeError :
-            DocTestRpcLoader.doctestSuiteClass.partial_setup(self)
-
-    def setup_gviz(self, gvizns):
-      r"""(Insert | update) the correct GViz provider in the global 
-      namespace.
-
-      @param gvizns               the namespace used to load the 
-                                  GViz provider.
-      @throws RuntimeError        if the provider bound to the 
-                                  requested namespace cannot be found.
-      """
-      globs = self.globalns
-      for p in self.gvizsys.providers :
-        if p.gviz_namespace() == gvizns :
-          globs['gvizobj'] = GVizDirectProxy(rpch, globs['req'])
-          globs['auth_gvizobj'] = GVizDirectProxy(rpch, globs['auth_req'])
-          break
-      else :
-        raise RuntimeError('Cannot load GViz provider for %s' % gvizns)
-
-    def partial_setup(self):
-      r"""Perform partial setup due to some minor failure (e.g. 
-      namespace missing in test name).
-      """
-      globs = self.globalns
-      globs.update([nm, None] for nm in ['rpcobj', 'auth_rpcobj', \
-                                          'gvizobj', 'auth_gvizobj'])
-
-class GVizDirectProxy:
-  r"""A proxy used in tests to encapsulate the interaction with GViz 
-  providers. In this case the provider's methods are invoked directly.
-
-  It also asserts that the permissions necessary to execute a given 
-  method are satisfied by the corresponding request object.
-  """
-  # TODO: Implement
+from tracdutest import DocTestTracLoader, EnvironmentStub
+from tracdutest.rpc import DocTestRpcLoader, RpcDirectProxy 
+from tracdutest.gviz import DocTestGVizLoader, GVizDirectProxy
 
 #------------------------------------------------------
 #    Helper functions used in test cases
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.