Skip to content

Commit

Permalink
Merge pull request #538 from requests/docs-examples
Browse files Browse the repository at this point in the history
Added secrets to actions to run test example
  • Loading branch information
JonathanHuot committed Apr 20, 2024
2 parents 45eca1a + 59f3d6a commit 77905a4
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 2 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ jobs:
python -m pip install coveralls coverage-lcov toml
- name: Execute tests with tox
env:
AUTH0_USERNAME: ${{ secrets.AUTH0_USERNAME }}
AUTH0_PASSWORD: ${{ secrets.AUTH0_PASSWORD }}
AUTH0_PKCE_CLIENT_ID: ${{ secrets.AUTH0_PKCE_CLIENT_ID }}
AUTH0_DOMAIN: ${{ secrets.AUTH0_DOMAIN }}
TOXENV: ${{ matrix.tox-env }}
run: |
tox
Expand Down
89 changes: 89 additions & 0 deletions docs/contributing_examples.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
======================
Documentation examples
======================

Examples found in documentation must be tested to be sure we have the appropriate
coverage and be sure new releases are tested against regressions.

Also, it helps testing any changes in public Identity Providers.

Currently few tests are covered, and ``selenium`` package is used to interact with browser. Feel free to have a look at the base class in ``tests/examples/base.py`` to reuse utility specially crafted for testing samples in documentation.

Identity Providers available for tests
======================================

Currently only an Auth0 test provider is available but new can be created on request. Following are the environment variables :

- Auth0 https://auth0.com/ :

- ``AUTH0_USERNAME``
- ``AUTH0_PASSWORD``
- ``AUTH0_DOMAIN``
- ``AUTH0_PKCE_CLIENT_ID``

Guidelines to write samples
===========================

Documentation
^^^^^^^^^^^^^

In order to write a testable sample, like an easy copy/paste, it is recommended to separate the python code from the documentation as below :

.. code-block::
.. literalinclude:: xyz_foobar.py
:language: python
Verify if formatting is correct by checking :

.. code-block:: bash
tox -e docs
# output located in docs/_build/html/index.html
Python example
^^^^^^^^^^^^^^

It's recommended to write a python example with either predefined placeholder variables for environment setup properties (like identity provider tenants identifiers/secrets), and use ``input()`` when user interaction is required. Feel free to reuse an existing example like ``docs/examples/native_spa_pkce_auth0.py`` and its associated test.

Python tests
^^^^^^^^^^^^

You can write new tests in ``tests/examples/test_*py`` and inherit of base classes found in ``tests/examples/base.py`` based on your needs.

Don't forget to skip python tests if you require an environment variables, also don't store any secrets or leak tenant informations in git.

Skip tests example as below:

.. code-block:: python
self.client_id = os.environ.get("AUTH0_PKCE_CLIENT_ID")
self.idp_domain = os.environ.get("AUTH0_DOMAIN")
if not self.client_id or not self.idp_domain:
self.skipTest("native auth0 is not configured properly")
Then the sample can be copy paste into a python console

Environment variables
^^^^^^^^^^^^^^^^^^^^^

Once referencing environment variables, you have to set them in the Github Actions. Any maintainers can do it, and it's the role of the maintainer to create a test tenant with test clients.

Example on how to set new env secrets with `GitHub CLI <https://cli.github.com/>`_:

.. code-block:: bash
gh secret set AUTH0_PASSWORD --body "secret"
Helper Interfaces
=================

.. autoclass:: tests.examples.Sample
:members:

.. autoclass:: tests.examples.Browser
:members:
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Getting Started:

api
contributing
contributing_examples



Expand Down
2 changes: 2 additions & 0 deletions tests/examples/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .base import Sample
from .base import Browser
32 changes: 32 additions & 0 deletions tests/examples/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ def replaceVariables(self, filein ,fileout, vars):
fout.write(line)

def run_sample(self, filepath, variables):
"""
Execute python sample as a background process.
:param filepath: Name of the python sample present in docs examples folder.
:type filepath: string
:param variables: Key Names/Values to replace in the python script before being run
:type variables: dict
"""
inpath = os.path.join(cwd, "..", "..", "docs", "examples", filepath)
outpath = os.path.join(cwd, "tmp_{}".format(filepath))
self.replaceVariables(inpath, outpath, variables)
Expand All @@ -48,10 +56,21 @@ def run_sample(self, filepath, variables):
)

def write(self, string):
"""
Write string into standard input. Useful to fill an answer to ``input()``
:param string: string to write
"""
self.proc.stdin.write(string)
self.proc.stdin.flush()

def wait_for_pattern(self, pattern):
"""
Wait until the background process is writing ``pattern`` in standard output.
:param pattern: search for this string before returning.
:type pattern: string
"""
try:
while True:
line = self.proc.stdout.readline()
Expand All @@ -62,6 +81,9 @@ def wait_for_pattern(self, pattern):
self.assertTrue(False, "timeout when looking for output")

def wait_for_end(self):
"""
Wait until the background process ends. Timeout after 10sec.
"""
try:
outs, err = self.proc.communicate(timeout=10)
self.outputs += filter(lambda x: x != '', outs.split('\n'))
Expand All @@ -88,6 +110,16 @@ def tearDown(self):
self.driver.quit()

def authorize_auth0(self, authorize_url, expected_redirect_uri):
"""
Start browser based on an Auth0 authorize url, and log user with user and password.
Returns once login journey ends with a redirection to ``expected_redirect_uri``.
Note this is for Auth0 login dialog specifically.
:param authorize_url: Full Authorize URL of Identity Provider
:type authorize_url: string
:param expected_redirect_uri: Expected ``redirect_uri``. Used only to check end of the authorize journey.
:type expected_redirect_uri: string
"""
self.driver.get(authorize_url)
username = self.driver.find_element(By.ID, "username")
password = self.driver.find_element(By.ID, "password")
Expand Down
5 changes: 3 additions & 2 deletions tests/examples/test_native_spa_pkce_auth0.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import os
import unittest

from . import base
from . import Sample
from . import Browser

class TestNativeAuth0Test(base.Sample, base.Browser, unittest.TestCase):
class TestNativeAuth0Test(Sample, Browser, unittest.TestCase):
def setUp(self):
super().setUp()
self.client_id = os.environ.get("AUTH0_PKCE_CLIENT_ID")
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ basepython=python3.11
skipsdist=True
deps=
-r{toxinidir}/docs/requirements.txt
-r{toxinidir}/requirements-test.txt
changedir=docs
allowlist_externals=make
commands=make clean html
Expand Down

0 comments on commit 77905a4

Please sign in to comment.