[book] add doc about request, session and connection management you need to know when writing tests stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Tue, 17 Jan 2012 14:05:04 +0100
branchstable
changeset 8168 707466abe9cc
parent 8167 41ec579e27c4
child 8169 f9fb7d903800
[book] add doc about request, session and connection management you need to know when writing tests
doc/book/en/devrepo/testing.rst
doc/book/en/images/request_session.png
doc/book/en/images/request_session.svg
--- a/doc/book/en/devrepo/testing.rst	Tue Jan 17 14:04:56 2012 +0100
+++ b/doc/book/en/devrepo/testing.rst	Tue Jan 17 14:05:04 2012 +0100
@@ -460,3 +460,127 @@
 ``````````````
 .. autoclass:: cubicweb.devtools.testlib.CubicWebTC
    :members:
+
+
+What you need to know about request and session
+-----------------------------------------------
+
+
+.. image:: ../images/request_session.png
+
+First, remember to think that some code run on a client side, some
+other on the repository side. More precisely:
+
+* client side: web interface, raw db-api connection (cubicweb-ctl shell for
+  instance);
+
+* repository side: RQL query execution, that may trigger hooks and operation.
+
+The client interact with the repository through a db-api connection.
+
+
+A db-api connection is tied to a session in the repository. The connection and
+request objects are unaccessible from repository code / the session object is
+unaccessible from client code (theorically at least).
+
+The :mod:`cubicweb.dbapi` module provides a base request class. The web interface
+provides an extended request class.
+
+
+The `request` object provides access to all cubicweb resources, eg:
+
+* the registry (which itself provides access to the schema and the
+  configuration);
+
+* an underlying db-api connection (when using req.execute, you actually call the
+  db-api);
+
+* other specific resources depending on the client type (url generation according
+  to base url, form parameters, etc.).
+
+
+A `session` provides an api similar to a request regarding RQL execution and
+access to global resources (registry and all), but also have the following
+responsibilities:
+
+* handle transaction data, that will live during the time of a single
+  transaction. This includes the database connections that will be used to
+  execute RQL queries.
+
+* handle persistent data that may be used across different (web) requests
+
+* security and hooks control (not possible through a request)
+
+
+The `_cw` attribute
+```````````````````
+The `_cw` attribute available on every application object provides access to all
+cubicweb resources, eg:
+
+For code running on the client side (eg web interface view), `_cw` is a request
+instance.
+
+For code running on the repository side (hooks and operation), `_cw` is a session
+instance.
+
+
+Beware some views may be called with a session (eg notifications) or with a
+DB-API request. In the later case, see :meth:`use_web_compatible_requests` on
+:class:`Connection` instances.
+
+
+Request, session and transaction
+````````````````````````````````
+
+In the web interface, an HTTP request is handle by a single request, which will
+be thrown way once the response send.
+
+The web publisher handle the transaction:
+
+* commit / rollback is done automatically
+* you should not commit / rollback explicitly
+
+When using a raw db-api, you're on your own regarding transaction.
+
+On the other hand, db-api connection and session live from a user login to its logout.
+
+Because session lives for a long time, and database connections is a limited
+resource, we can't bound a session to its own database connection for all its
+lifetime. The repository handles a pool of connections (4 by default), and it's
+responsible to attribute them as needed.
+
+Let's detail the process:
+
+1. an incoming RQL query comes from a client to the repository
+
+2. the repository attributes a database connection to the session
+
+3. the repository's querier execute the query
+
+4. this query may trigger hooks. Hooks and operation may execute some rql queries
+   through `_cw.execute`. Those queries go directly to the querier, hence don't
+   touch the database connection, they use the one attributed in 2.
+
+5. the repository's get the result of the query in 1. If it was a RQL read query,
+   the database connection is released. If it was a write query, the connection
+   is then tied to the session until the transaction is commited or rollbacked.
+
+6. results are sent back to the client
+
+This implies several things:
+
+* when using a request, or code executed in hooks, this database connection
+  handling is totally transparent
+
+* however, take care when writing test: you are usually faking / testing both the
+  server and the client side, so you have to decide when to use self.request() /
+  self.session. Ask yourself "where the code I want to test will be running,
+  client or repository side ?". The response is usually : use a request :)
+  However, if you really need using a session:
+
+  - commit / rollback will free the database connection (unless explicitly told
+    not to do so).
+
+  - if you issue a query after that without asking for a database connection
+    (`session.get_cnxset()`), you will end up with a 'None type has no attribute
+    source()' error
Binary file doc/book/en/images/request_session.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/images/request_session.svg	Tue Jan 17 14:05:04 2012 +0100
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="85.960938"
+   height="12.382812"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.48.1 r9760"
+   sodipodi:docname="request_session.svg">
+  <defs
+     id="defs4">
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Lend"
+       style="overflow:visible;">
+      <path
+         id="path3822"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="0.98994949"
+     inkscape:cx="25.928992"
+     inkscape:cy="-185.87004"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:window-width="766"
+     inkscape:window-height="1151"
+     inkscape:window-x="1152"
+     inkscape:window-y="24"
+     inkscape:window-maximized="0"
+     inkscape:snap-global="true" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-263.52249,-495.73373)">
+    <rect
+       style="fill:#ffffff;stroke:#000000;stroke-width:0.92460138;stroke-opacity:1"
+       id="rect3773"
+       width="214.15233"
+       height="184.80336"
+       x="57.578697"
+       y="366.01306" />
+    <rect
+       id="rect2985"
+       width="216.86372"
+       height="183.54575"
+       x="348.50262"
+       y="367.78079"
+       style="fill:#ffffff;stroke:#000000;stroke-width:0.55298227;stroke-opacity:1" />
+    <text
+       xml:space="preserve"
+       style="font-size:32px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="376.7869"
+       y="399.80365"
+       id="text3755"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3757"
+         x="376.7869"
+         y="399.80365">Repository</tspan></text>
+    <rect
+       style="fill:#ffffff;stroke:#000000;stroke-opacity:1"
+       id="rect3759"
+       width="144.45181"
+       height="104.04572"
+       x="237.38585"
+       y="423.03714" />
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="262.63968"
+       y="470.51431"
+       id="text3761"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3763"
+         x="262.63968"
+         y="470.51431">DB API</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="262.63968"
+       y="507.88998"
+       id="text3765"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3767"
+         x="262.63968"
+         y="507.88998">connection</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="419.21332"
+       y="509.91025"
+       id="text3769"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3771"
+         x="419.21332"
+         y="509.91025">session</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:32px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="102.02541"
+       y="397.78333"
+       id="text3775"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3777"
+         x="102.02541"
+         y="397.78333">Client</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="116.16754"
+       y="507.88995"
+       id="text3779"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3781"
+         x="116.16754"
+         y="507.88995">request</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="361.50729"
+       y="585.89832"
+       id="text3802"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3804"
+         x="361.50729"
+         y="585.89832">database </tspan><tspan
+         sodipodi:role="line"
+         x="361.50729"
+         y="605.89832"
+         id="tspan3806">connection</tspan></text>
+    <rect
+       style="fill:#ffffff;stroke:#000000;stroke-width:1.48014534;stroke-opacity:1"
+       id="rect3808"
+       width="192.09367"
+       height="58.095726"
+       x="365.79443"
+       y="621.50018" />
+    <text
+       xml:space="preserve"
+       style="font-size:36px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="369.5885"
+       y="662.66992"
+       id="text3810"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3812"
+         x="369.5885"
+         y="662.66992">Database</tspan></text>
+    <path
+       style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:none"
+       d="M 197.57252,125.76645 195.76971,55.592808"
+       id="path4260"
+       inkscape:connector-type="polyline"
+       inkscape:connector-curvature="3"
+       inkscape:connection-start="#rect3808"
+       inkscape:connection-start-point="d4"
+       inkscape:connection-end="#rect2985"
+       inkscape:connection-end-point="d4"
+       transform="translate(263.52249,495.73373)" />
+  </g>
+</svg>