- Background Information & Motivation
- Local Setup
- Heroku Deployment
- Roles and API Access
- API Documentation
- Testing
This project provides a RESTful
and RBAC
based API
to provide data of GNSS satellite constellations
(Global Navigation Satellite Systems). Data includes:
- Information about each GNSS, such as owner and number of satellites
- Information on signals names for a specific GNSS
The motivation for this project is to provide access to GNSS data to those in the satellite navigation industry whilst practicing the skills gained from this Full Stack nanodegree program.
This project summarizes the concepts learned from the various courses in the Full Stack Nanodegree program:
- Utilizing a database with models based on the Postgres client.
- The
ORM
used is python'sSQLAlchemy
(combined withFlask
) that containsCRUD
operations. - See more information on the data modeling schema in the Data Modeling section below.
- The
- Generating
REST
APIs containing GNSS and Signals data. - Enabling
RBAC
on the API endpoints using Auth0.- A role of
GNSS Director
can view GNSS and Signals, plus add, modify and delete GNSS and Signals. - A role of
GNSS Client
can view GNSS and Signals, but not add, modify or delete GNSS and Signals. - No role can only view GNSS (not view Signals).
- A role of
- Deploying the project on Heroku.
Data modeling is done in models.py, where:
- 2 tables are created: Gnss and Signals
- The Gnss table can be viewed by any user, but can only be changed by the director user
- The Signals table can be viewed by the client and director users (not the normal user), but can only be changed by the director user
Each table has helper functions:
- insert() to insert a new row into the table.
- update() to commit the session to the table.
- delete() to delete a row from the table.
- cancel() to cancel/rollback the current session.
- close() to close the db connection.
- format() to format the attributes of the table for the API JSON format.
Note: The instructions below are for a Windows 10 platform using Python 3.8.X. Note that python is deployed on Heroku as version 3.7
Follow instructions to install the latest version of python for your platform in the python docs.
Install https://visualstudio.microsoft.com/visual-cpp-build-tools.
Create a folder on your PC to host the project files. Navigate to the root folder and open a command window (Windows Key + cmd.exe)
at this location.
Create the virtual environment in hte root folder by running the following command:
python3 -m virtualenv env
Note: For Windows users, python3
can be python
.
For Windows 10, this means going into the env\Scripts
folder(by using the cd command in cmd.exe) and running activate.bat
via command prompt. Now this command prompt has (env)
in it and is the virtual environment for this project, only containing the dependencies required for it (i.e. those from requirements.txt).
Once you have your virtual environment setup and running, install dependencies by navigating to the root directory in the command window (cd..
twice) and running:
pip3 install -r requirements.txt
Note: For Windows users, pip3
can be pip
.
This will install all of the required packages we selected within the requirements.txt
file.
For Python 3.8 users only (not required for Heroku or Python 3.7): A small fix is required to work with Python 3.8:
Go into env\Lib\site-packages\sqlalchemy\util\compat.py
and follow the instructions here: https://knowledge.udacity.com/questions/132762#132817, which is:
- Comment out line 14 - "import time"
- Comment out lines 330-333 - If else statements related to time_func
Navigate to the root folder of the project (where manage.py is located) with the virtual environment activated ((env)
should appear in the command prompt).
To run the server, first execute:
run source setup.sh
(Mac)
to store the local environment variables.
python3 manage.py runserver
Note: For Windows users, python3
can be python
.
The server will start at http://127.0.0.1:5000/
Download Postgres Postgres. Note the version of Postgres (e.g. 13) and perform the following commands:
pg_ctl -D "C:\Program Files\PostgreSQL\<Version>\data" start
dropdb -U postgres gnss
createdb -U postgres gnss
dropdb -U postgres gnss_test
createdb -U postgres gnss_test
Note: The gnss
database is for production, gnss_test
is for testing (via test_gnssapi.py
script).
Navigate to the root with the virtual environment activated ((env)
should appear in the command prompt) and run the following commands to create the postgres db schema (no GNSS data will be populated yet):
flask db init
flask db migrate
flask db upgrade
Navigate to the root folder with the virtual environment activated ((env)
should appear in the command prompt) and run the following:
python3 populate_gnss.py
Note: For Windows users, python3
can be python
.
The app is located at: https://gnss-api.herokuapp.com/
See next 2 sections for logging in for different users/roles for testing.
- A role of
GNSS Director
can view GNSS and Signals, plus add, modify and delete GNSS and Signals. - A role of
GNSS Client
can view GNSS and Signals, but not add, modify or delete GNSS and Signals. - No role (not signed into Auth0) can only view GNSS (not view Signals).
These are fake accounts used for testing purposes to obtain JWTs to test the RBAC of the API.
User | Password |
---|---|
[email protected] | Director1atgnss |
[email protected] | Client1atgnss |
Available API endpoints:
- GET /gnss
- GET /gnss-signals
- POST /gnss
- POST /gnss-signals
- PATCH /gnss/gnss_id
- PATCH /gnss-signals/signal_id
- DELETE /gnss/gnss_id
- DELETE /gnss-signals/signal_id
- Errors
- Fetches a dictionary of all gnss.
- Request Arguments: none
- Returns: An object with:
- key:
"gnss"
, value is alist
of key value pairs containing:- key:
"id" (str)
, value:int
- key:
"name" (str)
, value:str
- key:
"num_frequencies" (str)
, value:int
- key:
"num_satellites" (str)
, value:int
- key:
"owner" (str)
, value:str
- key:
- key:
"success"
, value:true
orfalse
(boolean)
- key:
curl -X GET https://gnss-api.herokuapp.com/gnss
{
"gnss": [
{
"id": 1,
"name": "GPS",
"num_frequencies": 3,
"num_satellites": 32,
"owner": "USA"
},
{
"id": 2,
"name": "Galileo",
"num_frequencies": 4,
"num_satellites": 36,
"owner": "EU"
}
],
"success": true
}
- Fetches a dictionary of all gnss signals.
- Request Arguments: none
- Returns: An object with:
- key
"signal"
, value is alist
of key value pairs containing:- key:
"gnss_id" (str)
, value:int
- key:
"id" (str)
, value:int
- key:
"signal" (str)
, value:str
- key:
- key:
"success"
, value:true
orfalse
(boolean)
- key
curl -X GET https://gnss-api.herokuapp.com/gnss-signals --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ikh5VC1aRk1qdkVoaTNRVUJMLW44QiJ9.eyJpc3MiOiJodHRwczovL2NiaHViZXIudXMuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVmZDUwZDhhYjI3ZDhhMDA2OGE5MTAzNCIsImF1ZCI6Imduc3MiLCJpYXQiOjE2MDc4OTQ5MzgsImV4cCI6MTYwNzk4MTMzOCwiYXpwIjoibkhaWllLMXJ2RTVBSG81dHdjTGd2dXNoSDl2YnhpQTAiLCJzY29wZSI6IiIsInBlcm1pc3Npb25zIjpbImRlbGV0ZTpnbnNzIiwiZGVsZXRlOnNpZ25hbCIsImdldDpzaWduYWxzIiwicGF0Y2g6Z25zcyIsInBhdGNoOnNpZ25hbCIsInBvc3Q6Z25zcyIsInBvc3Q6c2lnbmFsIl19.z7b9-4rcI-0ultsQdVPS0exnoV3kH1mC-QV2FXrX0dQHOQrZesodIwNsrWaX6qk1s2sDpSEA9hSyXsKInVMCXwslHIk5yq2WkP2gROVVL1O--FOO2WxsDh7J2ig9Qhs_Np0pbJ7UgXPg9xDI-ylxTfxsU7cOgTyrGUc57176YdwFW4674NFIlXjjHZHT8ef7emts04yIl3Ud1nD_bNIwjFCcmDPOaz0KqAxDRNMu38YoXE19U3YQ0YaPxRsdMn3kZlBjKoi1sQCQvFSfOLBrlF5apTCw2Xnz3eWHdamIxVOjIFa5_aahl7tl-ACLFRx93494wYoTaQmC4CQR-NhWBA"
{
"signal": [
{
"gnss_id": 1,
"id": 1,
"signal": "L1 C/A"
},
{
"gnss_id": 1,
"id": 2,
"signal": "L1C"
},
{
"gnss_id": 1,
"id": 3,
"signal": "L2 P(Y)"
},
{
"gnss_id": 1,
"id": 4,
"signal": "L2C"
},
{
"gnss_id": 1,
"id": 5,
"signal": "L5"
},
{
"gnss_id": 2,
"id": 6,
"signal": "E1"
},
{
"gnss_id": 2,
"id": 7,
"signal": "E5A"
},
{
"gnss_id": 2,
"id": 8,
"signal": "E5B"
},
{
"gnss_id": 2,
"id": 9,
"signal": "E5AltBOC"
}
],
"success": true
}
- Adds an additional gnss to the database
- Request Arguments: dictionary:
{'name': str, 'owner': str, 'num_satellites': int, 'num_frequencies': int}
- Returns: An object with:
- key:
"gnss"
, value is alist
of key value pairs containing:- key:
"id" (str)
, value:int
- key:
"name" (str)
, value:str
- key:
"num_frequencies" (str)
, value:int
- key:
"num_satellites" (str)
, value:int
- key:
"owner" (str)
, value:str
- key:
- key:
"success"
, value:true
orfalse
(boolean)
- key:
curl -X POST https://gnss-api.herokuapp.com/gnss --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ikh5VC1aRk1qdkVoaTNRVUJMLW44QiJ9.eyJpc3MiOiJodHRwczovL2NiaHViZXIudXMuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVmZDUwZDhhYjI3ZDhhMDA2OGE5MTAzNCIsImF1ZCI6Imduc3MiLCJpYXQiOjE2MDc4OTQ5MzgsImV4cCI6MTYwNzk4MTMzOCwiYXpwIjoibkhaWllLMXJ2RTVBSG81dHdjTGd2dXNoSDl2YnhpQTAiLCJzY29wZSI6IiIsInBlcm1pc3Npb25zIjpbImRlbGV0ZTpnbnNzIiwiZGVsZXRlOnNpZ25hbCIsImdldDpzaWduYWxzIiwicGF0Y2g6Z25zcyIsInBhdGNoOnNpZ25hbCIsInBvc3Q6Z25zcyIsInBvc3Q6c2lnbmFsIl19.z7b9-4rcI-0ultsQdVPS0exnoV3kH1mC-QV2FXrX0dQHOQrZesodIwNsrWaX6qk1s2sDpSEA9hSyXsKInVMCXwslHIk5yq2WkP2gROVVL1O--FOO2WxsDh7J2ig9Qhs_Np0pbJ7UgXPg9xDI-ylxTfxsU7cOgTyrGUc57176YdwFW4674NFIlXjjHZHT8ef7emts04yIl3Ud1nD_bNIwjFCcmDPOaz0KqAxDRNMu38YoXE19U3YQ0YaPxRsdMn3kZlBjKoi1sQCQvFSfOLBrlF5apTCw2Xnz3eWHdamIxVOjIFa5_aahl7tl-ACLFRx93494wYoTaQmC4CQR-NhWBA" --header "Content-Type: application/json" --data "{\"name\": \"GLONASS\", \"owner\": \"Russia\", \"num_satellites\": 24, \"num_frequencies\": 2}"
{
"gnss": [
{
"id": 3,
"name": "GLONASS",
"num_frequencies": 2,
"num_satellites": 24,
"owner": "Russia"
}
],
"success": true
}
- Adds an additional gnss signal to the database
- Request Arguments: dictionary:
{'signal': str, 'gnss_id': int}
- Returns: An object with:
- key
"signal"
, value is alist
of key value pairs containing:- key:
"gnss_id" (str)
, value:int
- key:
"id" (str)
, value:int
- key:
"signal" (str)
, value:str
- key:
- key:
"success"
, value:true
orfalse
(boolean)
- key
curl -X POST https://gnss-api.herokuapp.com/gnss-signals --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ikh5VC1aRk1qdkVoaTNRVUJMLW44QiJ9.eyJpc3MiOiJodHRwczovL2NiaHViZXIudXMuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVmZDUwZDhhYjI3ZDhhMDA2OGE5MTAzNCIsImF1ZCI6Imduc3MiLCJpYXQiOjE2MDc4OTQ5MzgsImV4cCI6MTYwNzk4MTMzOCwiYXpwIjoibkhaWllLMXJ2RTVBSG81dHdjTGd2dXNoSDl2YnhpQTAiLCJzY29wZSI6IiIsInBlcm1pc3Npb25zIjpbImRlbGV0ZTpnbnNzIiwiZGVsZXRlOnNpZ25hbCIsImdldDpzaWduYWxzIiwicGF0Y2g6Z25zcyIsInBhdGNoOnNpZ25hbCIsInBvc3Q6Z25zcyIsInBvc3Q6c2lnbmFsIl19.z7b9-4rcI-0ultsQdVPS0exnoV3kH1mC-QV2FXrX0dQHOQrZesodIwNsrWaX6qk1s2sDpSEA9hSyXsKInVMCXwslHIk5yq2WkP2gROVVL1O--FOO2WxsDh7J2ig9Qhs_Np0pbJ7UgXPg9xDI-ylxTfxsU7cOgTyrGUc57176YdwFW4674NFIlXjjHZHT8ef7emts04yIl3Ud1nD_bNIwjFCcmDPOaz0KqAxDRNMu38YoXE19U3YQ0YaPxRsdMn3kZlBjKoi1sQCQvFSfOLBrlF5apTCw2Xnz3eWHdamIxVOjIFa5_aahl7tl-ACLFRx93494wYoTaQmC4CQR-NhWBA" --header "Content-Type: application/json" --data "{\"signal\": \"G1\", \"gnss_id\": 3}"
{
"signal": [
{
"gnss_id": 3,
"id": 10,
"signal": "G1"
}
],
"success": true
}
- Modifies an existing gnss
- URL Arguments:
gnss_id
is anint
- Request Arguments: Any of the following key/value pairs:
{'name': str, 'owner': str, 'num_satellites': int, 'num_frequencies': int}
- Returns: An object with:
- key:
"gnss"
, value is alist
of key value pairs containing:- key:
"id" (str)
, value:int
- key:
"name" (str)
, value:str
- key:
"num_frequencies" (str)
, value:int
- key:
"num_satellites" (str)
, value:int
- key:
"owner" (str)
, value:str
- key:
- key:
"success"
, value:true
orfalse
(boolean)
- key:
curl -X PATCH https://gnss-api.herokuapp.com/gnss/1 --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ikh5VC1aRk1qdkVoaTNRVUJMLW44QiJ9.eyJpc3MiOiJodHRwczovL2NiaHViZXIudXMuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVmZDUwZDhhYjI3ZDhhMDA2OGE5MTAzNCIsImF1ZCI6Imduc3MiLCJpYXQiOjE2MDc4OTQ5MzgsImV4cCI6MTYwNzk4MTMzOCwiYXpwIjoibkhaWllLMXJ2RTVBSG81dHdjTGd2dXNoSDl2YnhpQTAiLCJzY29wZSI6IiIsInBlcm1pc3Npb25zIjpbImRlbGV0ZTpnbnNzIiwiZGVsZXRlOnNpZ25hbCIsImdldDpzaWduYWxzIiwicGF0Y2g6Z25zcyIsInBhdGNoOnNpZ25hbCIsInBvc3Q6Z25zcyIsInBvc3Q6c2lnbmFsIl19.z7b9-4rcI-0ultsQdVPS0exnoV3kH1mC-QV2FXrX0dQHOQrZesodIwNsrWaX6qk1s2sDpSEA9hSyXsKInVMCXwslHIk5yq2WkP2gROVVL1O--FOO2WxsDh7J2ig9Qhs_Np0pbJ7UgXPg9xDI-ylxTfxsU7cOgTyrGUc57176YdwFW4674NFIlXjjHZHT8ef7emts04yIl3Ud1nD_bNIwjFCcmDPOaz0KqAxDRNMu38YoXE19U3YQ0YaPxRsdMn3kZlBjKoi1sQCQvFSfOLBrlF5apTCw2Xnz3eWHdamIxVOjIFa5_aahl7tl-ACLFRx93494wYoTaQmC4CQR-NhWBA" --header "Content-Type: application/json" --data "{\"owner\": \"America\"}"
{
"gnss": [
{
"id": 1,
"name": "GPS",
"num_frequencies": 3,
"num_satellites": 32,
"owner": "America"
}
],
"success": true
}
- Modifies an existing gnss signal
- URL Arguments:
signal_id
is anint
- Request Arguments: Any of the following key/value pairs:
{'signal': str, 'gnss_id': int}
- Returns: An object with:
- key
"signal"
, value is alist
of key value pairs containing:- key:
"gnss_id" (str)
, value:int
- key:
"id" (str)
, value:int
- key:
"signal" (str)
, value:str
- key:
- key:
"success"
, value:true
orfalse
(boolean)
- key
curl -X PATCH https://gnss-api.herokuapp.com/gnss-signals/1 --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ikh5VC1aRk1qdkVoaTNRVUJMLW44QiJ9.eyJpc3MiOiJodHRwczovL2NiaHViZXIudXMuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVmZDUwZDhhYjI3ZDhhMDA2OGE5MTAzNCIsImF1ZCI6Imduc3MiLCJpYXQiOjE2MDc4OTQ5MzgsImV4cCI6MTYwNzk4MTMzOCwiYXpwIjoibkhaWllLMXJ2RTVBSG81dHdjTGd2dXNoSDl2YnhpQTAiLCJzY29wZSI6IiIsInBlcm1pc3Npb25zIjpbImRlbGV0ZTpnbnNzIiwiZGVsZXRlOnNpZ25hbCIsImdldDpzaWduYWxzIiwicGF0Y2g6Z25zcyIsInBhdGNoOnNpZ25hbCIsInBvc3Q6Z25zcyIsInBvc3Q6c2lnbmFsIl19.z7b9-4rcI-0ultsQdVPS0exnoV3kH1mC-QV2FXrX0dQHOQrZesodIwNsrWaX6qk1s2sDpSEA9hSyXsKInVMCXwslHIk5yq2WkP2gROVVL1O--FOO2WxsDh7J2ig9Qhs_Np0pbJ7UgXPg9xDI-ylxTfxsU7cOgTyrGUc57176YdwFW4674NFIlXjjHZHT8ef7emts04yIl3Ud1nD_bNIwjFCcmDPOaz0KqAxDRNMu38YoXE19U3YQ0YaPxRsdMn3kZlBjKoi1sQCQvFSfOLBrlF5apTCw2Xnz3eWHdamIxVOjIFa5_aahl7tl-ACLFRx93494wYoTaQmC4CQR-NhWBA" --header "Content-Type: application/json" --data "{\"signal\": \"F1\"}"
{
"signal": [
{
"gnss_id": 1,
"id": 1,
"signal": "F1"
}
],
"success": true
}
- Deletes an existing gnss
- URL Arguments:
gnss_id
is anint
- Request Arguments: None
- Returns: An object with:
- key:
delete
, value:gnss_id
(int)
- key:
"success"
, value:true
orfalse
(boolean)
- key:
curl -X DELETE https://gnss-api.herokuapp.com/gnss/1 --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ikh5VC1aRk1qdkVoaTNRVUJMLW44QiJ9.eyJpc3MiOiJodHRwczovL2NiaHViZXIudXMuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVmZDUwZDhhYjI3ZDhhMDA2OGE5MTAzNCIsImF1ZCI6Imduc3MiLCJpYXQiOjE2MDc4OTQ5MzgsImV4cCI6MTYwNzk4MTMzOCwiYXpwIjoibkhaWllLMXJ2RTVBSG81dHdjTGd2dXNoSDl2YnhpQTAiLCJzY29wZSI6IiIsInBlcm1pc3Npb25zIjpbImRlbGV0ZTpnbnNzIiwiZGVsZXRlOnNpZ25hbCIsImdldDpzaWduYWxzIiwicGF0Y2g6Z25zcyIsInBhdGNoOnNpZ25hbCIsInBvc3Q6Z25zcyIsInBvc3Q6c2lnbmFsIl19.z7b9-4rcI-0ultsQdVPS0exnoV3kH1mC-QV2FXrX0dQHOQrZesodIwNsrWaX6qk1s2sDpSEA9hSyXsKInVMCXwslHIk5yq2WkP2gROVVL1O--FOO2WxsDh7J2ig9Qhs_Np0pbJ7UgXPg9xDI-ylxTfxsU7cOgTyrGUc57176YdwFW4674NFIlXjjHZHT8ef7emts04yIl3Ud1nD_bNIwjFCcmDPOaz0KqAxDRNMu38YoXE19U3YQ0YaPxRsdMn3kZlBjKoi1sQCQvFSfOLBrlF5apTCw2Xnz3eWHdamIxVOjIFa5_aahl7tl-ACLFRx93494wYoTaQmC4CQR-NhWBA"
{
"delete": 1,
"success": true
}
- Deletes an existing gnss signal
- URL Arguments:
signal_id
is anint
- Request Arguments: None
- Returns: An object with:
- key:
delete
, value:signal_id
(int)
- key:
"success"
, value:true
orfalse
(boolean)
- key:
curl -X DELETE https://gnss-api.herokuapp.com/gnss-signals/1 --header "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ikh5VC1aRk1qdkVoaTNRVUJMLW44QiJ9.eyJpc3MiOiJodHRwczovL2NiaHViZXIudXMuYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVmZDUwZDhhYjI3ZDhhMDA2OGE5MTAzNCIsImF1ZCI6Imduc3MiLCJpYXQiOjE2MDc4OTQ5MzgsImV4cCI6MTYwNzk4MTMzOCwiYXpwIjoibkhaWllLMXJ2RTVBSG81dHdjTGd2dXNoSDl2YnhpQTAiLCJzY29wZSI6IiIsInBlcm1pc3Npb25zIjpbImRlbGV0ZTpnbnNzIiwiZGVsZXRlOnNpZ25hbCIsImdldDpzaWduYWxzIiwicGF0Y2g6Z25zcyIsInBhdGNoOnNpZ25hbCIsInBvc3Q6Z25zcyIsInBvc3Q6c2lnbmFsIl19.z7b9-4rcI-0ultsQdVPS0exnoV3kH1mC-QV2FXrX0dQHOQrZesodIwNsrWaX6qk1s2sDpSEA9hSyXsKInVMCXwslHIk5yq2WkP2gROVVL1O--FOO2WxsDh7J2ig9Qhs_Np0pbJ7UgXPg9xDI-ylxTfxsU7cOgTyrGUc57176YdwFW4674NFIlXjjHZHT8ef7emts04yIl3Ud1nD_bNIwjFCcmDPOaz0KqAxDRNMu38YoXE19U3YQ0YaPxRsdMn3kZlBjKoi1sQCQvFSfOLBrlF5apTCw2Xnz3eWHdamIxVOjIFa5_aahl7tl-ACLFRx93494wYoTaQmC4CQR-NhWBA"
{
"delete": 1,
"success": true
}
If an error happens, a response will be returned as follows:
- key:
"error"
, value isint
- key:
"message"
, value isstr
- key:
"success"
, value isfalse
(boolean)
Example:
{
"error": 401,
"message": "Unauthorized",
"success": false
}
The following steps allow unit testing of the end points with the local build:
-
Go to the app at https://gnss-api.herokuapp.com/ and log in using the testing accounts.
-
Capture the JWT after logging in (will be on the post log-in page or in the URL under access_token).
-
Log out when capturing the JWT (return to the home page and log out).
-
In
test_gnssapi.py
, in thesetUp
method, paste the JWTs for the client and director in theself.client_bearer_token
andself.director_bearer_token
variables. -
Open a command window in the root folder (where test_gnssapi.py is located) and run
python3 test_gnssapi.py
. Test results will be reported as OK if all tests pass.
Note: For Windows users, python3
can be python
.