├── .gitignore
├── CSECodeSpaces101Introduction.mp4
├── Challenges
├── Challenge1.md
├── Challenge2.md
├── Challenge3.md
├── Challenge4.md
├── Challenge5.md
└── Challenge6.md
├── Images
├── PortForwardingDetection.png
├── PortForwardingPorts.png
├── PortUnknownProcess.png
└── RestClientExtension.png
├── Readme.md
├── api
├── __init__.py
└── math_api.py
├── dev_requirements.txt
├── math.http
├── requirements.txt
└── tests
├── __init__.py
└── api
├── __init__.py
└── test_math_api.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98 | __pypackages__/
99 |
100 | # Celery stuff
101 | celerybeat-schedule
102 | celerybeat.pid
103 |
104 | # SageMath parsed files
105 | *.sage.py
106 |
107 | # Environments
108 | .env
109 | .venv
110 | env/
111 | venv/
112 | ENV/
113 | env.bak/
114 | venv.bak/
115 |
116 | # Spyder project settings
117 | .spyderproject
118 | .spyproject
119 |
120 | # Rope project settings
121 | .ropeproject
122 |
123 | # mkdocs documentation
124 | /site
125 |
126 | # mypy
127 | .mypy_cache/
128 | .dmypy.json
129 | dmypy.json
130 |
131 | # Pyre type checker
132 | .pyre/
133 |
134 | # pytype static type analyzer
135 | .pytype/
136 |
137 | # Cython debug symbols
138 | cython_debug/
--------------------------------------------------------------------------------
/CSECodeSpaces101Introduction.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cse-labs/codespaces101/8e5e926fe9e608a38ae19ccbddca92c8e2cfccb3/CSECodeSpaces101Introduction.mp4
--------------------------------------------------------------------------------
/Challenges/Challenge1.md:
--------------------------------------------------------------------------------
1 | # Using predefined container configurations
2 | ## Background
3 | In order to learn about configuring development containers, it is helpful to start with the simplist definition. The simplist .devcontainer/devcontainer.json file has only an image entry.
4 | ```json
5 | {
6 | "image": "python:3.9"
7 | }
8 | ```
9 |
10 | Although the above works, you will likely want a more helpful configuration. If you are getting started building a devcontainer, the easiest way is to get started is to use the [predefined container configurations](https://docs.github.com/en/codespaces/customizing-your-codespace/configuring-codespaces-for-your-project#using-a-predefined-container-configuration) that are available. They provide a good starting development environment configuration for different environments.
11 |
12 | ## Challenge
13 | In this challenge, you need to accomplish the following, using **Visual Studio Code**:
14 | - Using a predefined container configuration, create a development container configuration
15 | - Open the root folder (CodespacesTraining) in a development container (Remote-Containers)
16 | - Run the python tests. 6 should pass. In order to run the tests, you need to open a bash terminal in the development container and run the following:
17 | ```bash
18 | $ pytest
19 | ```
20 | You should see the following (or something like it)
21 | ```bash
22 | ====================================================== test session starts =======================================================
23 | platform linux -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
24 | rootdir: /workspaces/Codespaces
25 | plugins: mock-3.6.1
26 | collected 6 items
27 |
28 | tests/api/test_math_api.py ...... [100%]
29 |
30 | ======================================================= 6 passed in 0.32s ========================================================
31 | ```
32 |
33 | ## Helpful hints
34 | - You will need to clone this repo so you have the code locally
35 | - You can find information about [predefined container configurations here](https://docs.github.com/en/codespaces/customizing-your-codespace/configuring-codespaces-for-your-project#using-a-predefined-container-configuration)
36 | - You will need to have the Remote-Containers extension installed in Visual Studio Code
37 | - You can find the helpful commands in VS Code by pressing (Ctrl+Shift+P on Windows) or (Cmd+Shift+P on a Mac) and typing "Remote-Containers". You will see the remote containers options in the menu.
38 | - This is a Python app
39 | - You can use Python 3.9
40 | - The requirements.txt and dev_requirements.txt files holds all the dependencies required by the application
41 | - You can install the requirements by running the following in a bash terminal:
42 | ```bash
43 | python -m pip install --upgrade pip
44 | pip install -r requirements.txt
45 | pip install -r dev_requirements.txt
46 | ```
47 | - **Important - You will need to choose Remote-Containers: Rebuild Container" if you want to see a change you made and you have already built the remote container.
48 |
--------------------------------------------------------------------------------
/Challenges/Challenge2.md:
--------------------------------------------------------------------------------
1 | # Customizing the development container with the onCreateCommand hook
2 | ## Background
3 | You likely noticed in Challenge1 that the default Python development environment configuration did not yield a development environment that was fully configured for the application. You were forced to further configure the environment for the application dependencies in order to run the tests or access the api. This is certainly not ideal, as every developer would have to **know** both that they need to install the dependencies **and** how to install them. A better solution would be to have the dependencies installed in the development environment.
4 | [Development containers](https://code.visualstudio.com/docs/remote/devcontainerjson-reference) have hooks that allow you to run commands at different points in the development container lifecycle. These include:
5 | - onCreateCommand - Run when creating the container
6 | - postCreateCommand - Run inside the container after it is created
7 | - postStartCommand - Run every time the container starts
8 |
9 | ## Challenge
10 | In this challenge, you will use the postCreateCommand to install the application dependencies.
11 |
12 |
13 | ## Helpful Hints
14 | - Remember that in challenge 1 you needed to run the following in a bash terminal:
15 | ```bash
16 | python -m pip install --upgrade pip
17 | pip install -r requirements.txt
18 | pip install -r dev_requirements.txt
19 | ```
20 |
--------------------------------------------------------------------------------
/Challenges/Challenge3.md:
--------------------------------------------------------------------------------
1 | # Moving the customizations from postCreateCommand to the local Dockerfile
2 | Once we have validated the code in the bash script, the next step is to move the changes to the local Dockerfile. This brings us back to the tip from solution1:
3 |
4 | ## (from solution 1) From the Field
5 | We never just have an image pointer in devcontainer.json like below:
6 | ```json
7 | {
8 | "image": "python:3.9"
9 | }
10 | ```
11 |
12 | Even if we are just using the base image, we have a Dockerfile with a FROM and point to the image. Below is a simplified equivelant to the above, using a Dockerfile:
13 | ```json
14 | {
15 | "build": {
16 | "dockerfile": "Dockerfile"
17 | }
18 | }
19 | ```
20 |
21 | ```Dockerfile
22 | FROM python:3.9
23 | ```
24 |
25 | This refactor illustrates why that tip is in place. We already have a Dockerfile in our solution where we can move our changes.
26 |
27 | ## Challenge
28 | Move the logic that installs the dependencies for the application from the bash script file to the local Dockerfile.
29 |
--------------------------------------------------------------------------------
/Challenges/Challenge4.md:
--------------------------------------------------------------------------------
1 | ## Forwarding Ports
2 | When running applications inside of the container, they are not accessible to the host unless you forward the port that the application is running on. Ports can be forwarded either temporarily or you can configure your dev container to always forward the ports.
3 | Visual Studio Code often detects ports that are running in the dev container and automatically, temporarily forwards the ports for you. See the images below:
4 | 
5 | 
6 | Here, you will notice that when we ran our simple Flask API, Visual Studio Code detected that the API was running on port 5000 and automatically forwarded it for us. You can see the ports that are being forwarded on the ports tab.
7 |
8 | There are 2 potential challenges that we may want to address:
9 | 1. We may not want to rely on Visual Studio Code to detect the ports. This does not always happen. In more complicated development environments, we will likely want to control what parts are forwarded.
10 | 2. We may want to provide some context as to what is running on each port via a label.
11 | 
12 | In the above example, we ran the yeasy/simple-web docker image in a docker-in-docker development container. Looking are the forwarded ports, it is unclear what is running on port 5020.
13 |
14 | ## Challenge
15 | In this challenge, you need to accomplish 2 things:
16 | 1. Configure the dev container to forward port 5000.
17 | 2. Label port 5000 "Math API"
18 |
19 | ## Helpful Hints
20 | [devcontainer.json reference](https://code.visualstudio.com/docs/remote/devcontainerjson-reference)
21 |
--------------------------------------------------------------------------------
/Challenges/Challenge5.md:
--------------------------------------------------------------------------------
1 | ## Extensions
2 | As noted in Readme.md, the goal of these technologies is to allow developers to define a fully-configured development environment. Fully-configured goes well beyond just defining a container with all of the application dependencies that the developer can develop in. Developer containers also have a Visual Studio Code Server running in them and this server can also be configured by the devcontainer.json file.
3 |
4 | One of the options is to configure the extensions that are installed in the code server running in the developer container. The "in the developer container" part of that sentence is important. [The following hold true for extensions configured in devcontainer.json](https://code.visualstudio.com/docs/remote/containers#_managing-extensions):
5 | - Some extensions have to run locally, including themes and snippets
6 | - Extensions that can be run on the server are **not** installed on your local Visual Studio Code Client. They **will be** installed in the Visual Studio Code Server running in the developer container.
7 |
8 | Beyond the devcontainer.json, it is possible to install extensions that are installed locally in Visual Studio Code in the remote container. This can be done via the Extensions tab.
9 |
10 | ### Rest Client - a helpful extension
11 | There is an extension that is very helpful when developing REST APIs. It is the [Rest Client](https://marketplace.visualstudio.com/items?itemName=humao). Among other things, it allows you to send HTTP requests from a file (*.http) and see the results in a separate panel. See the example below:
12 | 
13 |
14 | ## Challenge
15 | Install the [Rest Client extension](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) in the developer container and make a call to the add operation.
16 |
17 | ## Helpful Hints
18 | Make sure the API is running.
--------------------------------------------------------------------------------
/Challenges/Challenge6.md:
--------------------------------------------------------------------------------
1 | # GitHub Codespaces
2 | As you read in the Readme.md file, devcontainers provide the ability to define fully-configured development environments. GitHub Codespaces builds upon devcontainers to allow for a one-click hosted development environment. The following are some of the key benefits of GitHub Codespaces:
3 | - The only prerequisite is a modern browser. While devcontainers have minimal prerequisites, they do require Docker and Visual Studio Code to be installed.
4 | - Codespaces allows developers to add features, fix bugs or review PRs without installing anything on their machine.
5 |
6 | This challenge will illustrate the power of GitHub Codespaces.
7 |
8 | # Challenge
9 | - Open the repository in GitHub Codespaces
10 | - Perform the following using the browser client
11 | - Run the API in debug mode
12 | - Set a breakpoint on line 10 in api/math_api.py
13 | - Click on 'Send Request' in math.http just above
14 | ```bash
15 | GET http://localhost:5000/add?x=100&y=10101 HTTP/1.1
16 | ```
17 | - Debug through the call to add
18 | - Perform the same steps above using Visual Studio Code as the client
19 |
20 | # Helpful Hints
21 | - You have several choices with regard to the repository and branch you open in GitHub Codespaces:
22 | - You can use the Solution5 or Solution6 branch in https://github.com/RobBagby/codespaces-training
23 | - You can use fork https://github.com/RobBagby/codespaces-training and push to your own GitHub repository and
24 | - Use the Solution5 or Solution6 branch
25 | - Use master, as long as you have followed all the challenges
26 | - You have to have access to GitHub CodeSpaces in order to follow this challenge
--------------------------------------------------------------------------------
/Images/PortForwardingDetection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cse-labs/codespaces101/8e5e926fe9e608a38ae19ccbddca92c8e2cfccb3/Images/PortForwardingDetection.png
--------------------------------------------------------------------------------
/Images/PortForwardingPorts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cse-labs/codespaces101/8e5e926fe9e608a38ae19ccbddca92c8e2cfccb3/Images/PortForwardingPorts.png
--------------------------------------------------------------------------------
/Images/PortUnknownProcess.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cse-labs/codespaces101/8e5e926fe9e608a38ae19ccbddca92c8e2cfccb3/Images/PortUnknownProcess.png
--------------------------------------------------------------------------------
/Images/RestClientExtension.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cse-labs/codespaces101/8e5e926fe9e608a38ae19ccbddca92c8e2cfccb3/Images/RestClientExtension.png
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # Table of Contents
2 | I. [Overview](#overview)
3 | A. [Why you care](#why-you-care)
4 | B. [What you will learn](#what-you-will-learn)
5 | II. [How this training is structured](#how-this-training-is-structured)
6 | III. [Requirements](#requirements)
7 | IV. [Overview of Development containers, GitHub Codespaces And Visual Studio Code](#overview-of-development-containers-github-codespaces-and-visual-studio-code)
8 | A. [Development Container](#development-container)
9 | B. [Visual Studio Code](#visual-studio-code)
10 | C. [GitHub Codespaces](#github-codespaces)
11 | V. [Challenges](#challenges)
12 | A. [Challenge1](Challenges/Challenge1.md)
13 | B. [Challenge2](Challenges/Challenge2.md)
14 | C. [Challenge3](Challenges/Challenge3.md)
15 | D. [Challenge4](Challenges/Challenge4.md)
16 | E. [Challenge5](Challenges/Challenge5.md)
17 | F. [Challenge6](Challenges/Challenge6.md)
18 |
19 | # Overview
20 | ## Why you care
21 | Traditionally, there is considerable friction for developers when setting up development environments. It is not uncommon for devs new to projects to spend days updating their environment before being able to start contributing to the project.
22 |
23 | The more complex the requirements, the greater the friction. Consider the following 2 examples:
24 | 1. Configuring a local Kubernetes development environment with the following:
25 | - Grafana
26 | - Prometheus
27 | - Fluentbit
28 | 2. A Python API with:
29 | - The current version of Python
30 | - Debugging configured
31 | - Pytest
32 | - Flask
33 |
34 | The above are 2 very real examples. The Retail Dev Crew team in CSE has been working with some of the largest Kubernetes deployments in the world. The dev environment includes everything listed above in example #1 plus much more. Despite the complex dev environment, the team prides itself upon new devs creating a PR on their first day. This is only possible because the Retail Dev Crew's use of development containers and GitHub Codespaces.
35 |
36 | Python environments are notoriously challenging to configure. This is especially true with regard to debugging.
37 |
38 | A large blocker to contributing to OSS projects is configuring the development environment. Imagine being able to instantiate a fully-configured development environment with the click of a button. That is the promise of development containers and GitHub Codespaces.
39 |
40 | ## What you will learn
41 | If you complete this self-directed training, you will:
42 | - Learn what development containers are
43 | - Learn what GitHub Codespaces are
44 | - Understand the relationship between Visual Studio Code, development containers and GitHub Codespaces
45 | - Learn how to build devcontainers
46 | - Using an existing docker image
47 | - Using the commands
48 | - onCreateCommand
49 | - postCreateCommand
50 | - postStartCommand
51 | - Creating a custom docker image
52 | - Updating the developer experience
53 | - Installing extensions
54 | - dotfiles
55 | - Patterns and best practices working with development containers and GitHub Codespaces
56 |
57 | # How this training is structured
58 | This GitHub repository has a master branch and a collection of solution branches.
59 |
60 | The master branch contains the following:
61 | - Readme.md - The main training file. Start here.
62 | - Challenges/* - The challenge files for this training. Each Challenge file will contain some learnings/background on the challenge, the challenge itself and, optionally, some helpful hints.
63 | - api/math_api.py - A very simple python Flask REST API
64 | - tests/api/test_math_api.py - Pytest unit tests
65 | - requirements.txt and dev_requirements.txt - Python requirements files containing the dependencies for the application and application development environment
66 | - math.http - A manual test file for use in Challenge 5
67 |
68 | Each challenge has its own solution branch. Use your git client to open each Solution branch. For example:
69 | ```bash
70 | git checkout Solution1
71 |
72 | # Or if you don't have the solution branch local
73 | git checkout --track origin/Solution1
74 | ```
75 |
76 | Each branch contains the following:
77 | - Solution(1-N).md - File describing the solution. **This file may also contain a "From the Field" section where we list some of the learnings the CSE Retail Dev Crews team has had working with GitHub codespaces with our largest customers**
78 | - The solution configured in the .devcontainer folder
79 | - Solution(1-N).mp4 - A video outlining a solution to the challenge. **Open the videos from the file system, not Visual Studio Code**
80 |
81 |
82 | # Requirements
83 | You will need the following to complete the development container challenges in this training [(see detailed installation instructions here)](https://code.visualstudio.com/docs/remote/containers#_system-requirements):
84 | - Docker for Windows/Mac/Linux
85 | - Visual Studio Code
86 |
87 | You will need to be enabled for GitHub Codespaces in order to complete the codespaces challenges. [(see documentation here about getting access to Codespaces)](https://docs.github.com/en/codespaces/managing-codespaces-for-your-organization/enabling-codespaces-for-your-organization)
88 |
89 |
90 |
91 | # Overview of Development containers, GitHub Codespaces And Visual Studio Code
92 | The goal of these technologies is to allow developers to define a fully-configured development environment, run it in a container and develop against it with Visual Studio Code running as a client application or running in the browser. This section will provide a high-level overview of these technologies and how they interrelate. You will find links to more information throughout this section.
93 |
94 | ## Development Container
95 | As noted above, a development container is a fully-featured development environment running in a container. The development container is a Docker container running locally or remotely that, at a high-level, contains the following:
96 | - All the application dependencies - Defined in a Docker image, Dockerfile or docker-compose file and potentially updated via scripts called by well-defined hooks.
97 | - The application code - mounted, copied or cloned into the container
98 | - Visual Studio Code Server - configured with the appropriate Visual Studio Code Extensions required to develop
99 |
100 | [Default Images](https://docs.github.com/en/codespaces/customizing-your-codespace/configuring-codespaces-for-your-project#using-the-default-configuration) can be used for general development. However, for a more productive development experience, you will likely want to define your own development containers. The configuration for the development container is in a [devcontainer.json](https://code.visualstudio.com/docs/remote/devcontainerjson-reference) file which exists either at the root of the project or under a .devcontainer folder at the root. **From the field: We always put the devcontainer.json file under a .devcontainer folder. We do that because we always have additional files that accompany the devcontainer.json file. These files include bash scripts and a Dockerfile. We will get into more details about these files later.** During the challenges in this training you will explore and learn the common configuration patterns in a devcontainer.json file. For the time being, we will show you a [very simple example of a devcontainer.json file](https://code.visualstudio.com/docs/remote/containers#_create-a-devcontainerjson-file) taken from the documentation:
101 |
102 | ```json
103 | {
104 | "image": "mcr.microsoft.com/vscode/devcontainers/typescript-node:0-12",
105 | "forwardPorts": [3000],
106 | "extensions": ["dbaeumer.vscode-eslint"]
107 | }
108 | ```
109 | Again, we will explore each of the above in more detail in the challenges. For now, it is enough to understand that the devcontainer.json points to an existing typescript-node image. This is the image that will be used when starting the developer (Docker) container. The configuration further specifies that port 3000 should be forwarded from the container to the host. Lastly, it specifies that a linting extension should be installed in the VS Code Server running in the developer container.
110 |
111 | ## Visual Studio Code
112 | Visual Studio Code has a [Remote-Containers Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) that enables the use of a Docker container as a fully configured development environment. This is enabled through a client-server architecture. As noted above, running development containers have a Visual Studio Code Server running in them. The Visual Studio Code Client can access a running container or can create an instance of a new development container and connect to it.
113 |
114 | The challenges will mainly be using Visual Studio Code to create and run development containers.
115 |
116 | ## GitHub Codespaces
117 | GitHub Codespaces enables exposing a fully configured development environment for GitHub repositories. This can be used for anthing from new feature development to code reviews. Codespaces extends the use of development containers by providing a remote hosting environment for them. Developers can simply click on a button in GitHub to open a Codespace for the repo. Behind the scenes, GitHub Codespaces is:
118 | - Spinning up a VM
119 | - Shallow cloning the repo in that VM. The shallow clone pulls the devcontainer.json onto the VM
120 | - Spins up the development container on the VM
121 | - Clones the repository in the development container
122 | - Connects you to the remotely hosted development container - via the browser or GitHub
123 |
124 | # The Challenges - Building a Devcontainer
125 | The challenges below are designed to provide a stepwise approach to building development containers. They start with the simplist approach, with each subsequent challenge teaching you a further aspect. Throughout the challeges, we will be providing real-world guidance that we have learned working with real customers in the field.
126 | - [Challenge1](Challenges/Challenge1.md)
127 | - [Challenge2](Challenges/Challenge2.md)
128 | - [Challenge3](Challenges/Challenge3.md)
129 | - [Challenge4](Challenges/Challenge4.md)
130 | - [Challenge5](Challenges/Challenge5.md)
131 | - [Challenge6](Challenges/Challenge6.md)
132 |
133 |
--------------------------------------------------------------------------------
/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cse-labs/codespaces101/8e5e926fe9e608a38ae19ccbddca92c8e2cfccb3/api/__init__.py
--------------------------------------------------------------------------------
/api/math_api.py:
--------------------------------------------------------------------------------
1 | import flask
2 |
3 | app = flask.Flask(__name__)
4 |
5 | BAD_REQUEST = "Bad request. Add requires x and y in the querystring - .../add?x=1&y=2"
6 |
7 | @app.route('/add/', methods=['GET'])
8 | def add():
9 | addend1 = flask.request.args.get('x', None, type=float)
10 | if addend1 is None or _is_number(addend1) is False:
11 | return BAD_REQUEST, 400
12 |
13 | addend2 = flask.request.args.get('y', None, type=float)
14 | if addend2 is None or _is_number(addend1) is False:
15 | return BAD_REQUEST, 400
16 |
17 | return str(addend1 + addend2)
18 |
19 | def _is_number(var):
20 | return isinstance(var, int) or isinstance(var, float)
21 |
22 | if __name__ == '__main__':
23 | app.run(debug=False, use_reloader=False)
--------------------------------------------------------------------------------
/dev_requirements.txt:
--------------------------------------------------------------------------------
1 | pytest
2 | mock
3 | pytest-mock
--------------------------------------------------------------------------------
/math.http:
--------------------------------------------------------------------------------
1 | # math_api app endpoints
2 |
3 | # add
4 | GET http://localhost:5000/add?x=5&y=3 HTTP/1.1
5 |
6 | ###
7 |
8 | # add again
9 | GET http://localhost:5000/add?x=100&y=10101 HTTP/1.1
10 |
11 | ###
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | flask
2 | flask-restful
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cse-labs/codespaces101/8e5e926fe9e608a38ae19ccbddca92c8e2cfccb3/tests/__init__.py
--------------------------------------------------------------------------------
/tests/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cse-labs/codespaces101/8e5e926fe9e608a38ae19ccbddca92c8e2cfccb3/tests/api/__init__.py
--------------------------------------------------------------------------------
/tests/api/test_math_api.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import mock
3 | import flask
4 | import pdb;
5 |
6 | import api.math_api
7 | from api.math_api import add
8 |
9 | def test__add__x_not_passed__returns_400(mocker):
10 | app = flask.Flask(__name__)
11 |
12 | with app.test_request_context('/?y=4'):
13 | message, code = add()
14 | assert code == 400
15 |
16 | def test__add__y_not_passed__returns_400(mocker):
17 | app = flask.Flask(__name__)
18 |
19 | with app.test_request_context('/?x=4'):
20 | message, code = add()
21 | assert code == 400
22 |
23 | def test__add__x_not_numeric__returns_400(mocker):
24 | app = flask.Flask(__name__)
25 |
26 | with app.test_request_context('/?x=ggg&y=4'):
27 | message, code = add()
28 | assert code == 400
29 |
30 | def test__add__y_not_numeric__returns_400(mocker):
31 | app = flask.Flask(__name__)
32 |
33 | with app.test_request_context('/?x=4&y=ggg'):
34 | message, code = add()
35 | assert code == 400
36 |
37 | def test__add__z_and_y_integers_passed__returns_sum(mocker):
38 | app = flask.Flask(__name__)
39 |
40 | with app.test_request_context('/?x=4&y=5'):
41 | response = add()
42 | assert response == '9.0'
43 |
44 | def test__add__z_and_y_floats_passed__returns_sum(mocker):
45 | app = flask.Flask(__name__)
46 |
47 | with app.test_request_context('/?x=4.4&y=5.5'):
48 | response = add()
49 | assert response == '9.9'
--------------------------------------------------------------------------------